From 111aceb63e6c38e17e89cf32939bf9f2ab567143 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 24 Jun 2015 13:39:32 -0700 Subject: [PATCH 001/260] 8140802: Clean up and refactor of class loading code for CDS Reviewed-by: mchung, jiangli --- jdk/make/src/classes/build/tools/module/boot.modules | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/make/src/classes/build/tools/module/boot.modules b/jdk/make/src/classes/build/tools/module/boot.modules index 02de8910651..296d393eea8 100644 --- a/jdk/make/src/classes/build/tools/module/boot.modules +++ b/jdk/make/src/classes/build/tools/module/boot.modules @@ -19,6 +19,7 @@ java.xml.crypto jdk.charsets jdk.deploy jdk.deploy.osx +jdk.vm.cds jdk.httpserver jdk.jfr jdk.management From 325d83e6893f70c1b04f19166664dfab185673f9 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 22 Jul 2015 20:14:16 -0700 Subject: [PATCH 002/260] 8140802: Clean up and refactor of class loading code for CDS Reviewed-by: jiangli, acorn --- modules.xml | 1 + test/lib/sun/hotspot/WhiteBox.java | 1 + 2 files changed, 2 insertions(+) diff --git a/modules.xml b/modules.xml index 94b55f7c691..1d5d8bfbc99 100644 --- a/modules.xml +++ b/modules.xml @@ -340,6 +340,7 @@ java.sql java.sql.rowset jdk.scripting.nashorn + jdk.vm.cds sun.reflect.annotation diff --git a/test/lib/sun/hotspot/WhiteBox.java b/test/lib/sun/hotspot/WhiteBox.java index 2af9e12d0f3..93c24705b7e 100644 --- a/test/lib/sun/hotspot/WhiteBox.java +++ b/test/lib/sun/hotspot/WhiteBox.java @@ -407,6 +407,7 @@ public class WhiteBox { public native void assertMatchingSafepointCalls(boolean mutexSafepointValue, boolean attemptedNoSafepointValue); // Sharing + public native boolean isSharedClass(Class c); public native boolean isShared(Object o); public native boolean areSharedStringsIgnored(); } From 87b0df30ed43926ad3d44064df2484f8778e7f86 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 18 Aug 2015 11:27:23 -0700 Subject: [PATCH 003/260] 8140802: Clean up and refactor of class loading code for CDS Reviewed-by: jiangli, acorn, coleenp --- hotspot/make/excludeSrc.make | 5 +- .../share/vm/classfile/classListParser.cpp | 66 +++++++++++ .../share/vm/classfile/classListParser.hpp | 56 +++++++++ .../share/vm/classfile/classLoaderData.cpp | 2 +- .../share/vm/classfile/classLoaderData.hpp | 12 ++ .../src/share/vm/classfile/classLoaderExt.cpp | 36 ++++++ .../src/share/vm/classfile/classLoaderExt.hpp | 5 +- hotspot/src/share/vm/classfile/dictionary.cpp | 16 ++- hotspot/src/share/vm/classfile/dictionary.hpp | 2 + .../vm/classfile/sharedPathsMiscInfo.hpp | 16 +-- .../share/vm/classfile/systemDictionary.cpp | 57 +++++++-- .../share/vm/classfile/systemDictionary.hpp | 13 +-- .../vm/classfile/systemDictionaryShared.hpp | 30 ++++- .../vm/classfile/systemDictionary_ext.hpp | 30 +++++ hotspot/src/share/vm/classfile/vmSymbols.hpp | 4 + .../src/share/vm/classfile/vmSymbols_ext.hpp | 31 +++++ .../src/share/vm/memory/metaspaceShared.cpp | 109 ++++++++++++------ .../src/share/vm/memory/metaspaceShared.hpp | 3 + hotspot/src/share/vm/prims/whitebox.cpp | 5 + hotspot/src/share/vm/utilities/hashtable.cpp | 2 + 20 files changed, 426 insertions(+), 74 deletions(-) create mode 100644 hotspot/src/share/vm/classfile/classListParser.cpp create mode 100644 hotspot/src/share/vm/classfile/classListParser.hpp create mode 100644 hotspot/src/share/vm/classfile/classLoaderExt.cpp create mode 100644 hotspot/src/share/vm/classfile/systemDictionary_ext.hpp create mode 100644 hotspot/src/share/vm/classfile/vmSymbols_ext.hpp diff --git a/hotspot/make/excludeSrc.make b/hotspot/make/excludeSrc.make index dac7372c6fc..9feb96861ee 100644 --- a/hotspot/make/excludeSrc.make +++ b/hotspot/make/excludeSrc.make @@ -73,8 +73,9 @@ ifeq ($(INCLUDE_CDS), false) CXXFLAGS += -DINCLUDE_CDS=0 CFLAGS += -DINCLUDE_CDS=0 - Src_Files_EXCLUDE += filemap.cpp metaspaceShared*.cpp sharedPathsMiscInfo.cpp \ - systemDictionaryShared.cpp classLoaderExt.cpp sharedClassUtil.cpp + Src_Files_EXCLUDE += classListParser.cpp classLoaderExt.cpp \ + filemap.cpp metaspaceShared*.cpp sharedClassUtil.cpp sharedPathsMiscInfo.cpp \ + systemDictionaryShared.cpp endif ifeq ($(INCLUDE_ALL_GCS), false) diff --git a/hotspot/src/share/vm/classfile/classListParser.cpp b/hotspot/src/share/vm/classfile/classListParser.cpp new file mode 100644 index 00000000000..8f7be316b50 --- /dev/null +++ b/hotspot/src/share/vm/classfile/classListParser.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/classListParser.hpp" +#include "runtime/os.hpp" +#include "runtime/java.hpp" + +ClassListParser::ClassListParser(const char* file) { + _classlist_file = file; + _file = fopen(file, "r"); + if (_file == NULL) { + char errmsg[JVM_MAXPATHLEN]; + os::lasterror(errmsg, JVM_MAXPATHLEN); + vm_exit_during_initialization("Loading classlist failed", errmsg); + } +} + +ClassListParser::~ClassListParser() { + if (_file) { + fclose(_file); + } +} + +bool ClassListParser::parse_one_line() { + for (;;) { + if (fgets(_line, sizeof(_line), _file) == NULL) { + return false; + } + int line_len = (int)strlen(_line); + if (line_len > _max_allowed_line_len) { + tty->print_cr("input line too long (must be no longer than %d chars)", _max_allowed_line_len); + vm_exit_during_initialization("Loading classlist failed"); + } + if (*_line == '#') { // comment + continue; + } + break; + } + + // Remove trailing \r\n + _line[strcspn(_line, "\r\n")] = 0; + return true; +} + diff --git a/hotspot/src/share/vm/classfile/classListParser.hpp b/hotspot/src/share/vm/classfile/classListParser.hpp new file mode 100644 index 00000000000..912ae3175a3 --- /dev/null +++ b/hotspot/src/share/vm/classfile/classListParser.hpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_MEMORY_CLASSLISTPARSER_HPP +#define SHARE_VM_MEMORY_CLASSLISTPARSER_HPP + +#include "utilities/exceptions.hpp" +#include "utilities/globalDefinitions.hpp" + +class ClassListParser : public StackObj { + enum { + // Max number of bytes allowed per line in the classlist. + // Theoretically Java class names could be 65535 bytes in length. In reality, + // 4K bytes is more than enough. + _max_allowed_line_len = 4096, + _line_buf_extra = 10, // for detecting input too long + _line_buf_size = _max_allowed_line_len + _line_buf_extra + }; + + const char* _classlist_file; + FILE* _file; + char _line[_line_buf_size]; // The buffer that holds the current line. + +public: + ClassListParser(const char* file); + ~ClassListParser(); + bool parse_one_line(); + + const char* current_class_name() { + return _line; + } +}; + + +#endif // SHARE_VM_MEMORY_CLASSLISTPARSER_HPP diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index 3d0727ed67e..734b4acb225 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -82,7 +82,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Depen _keep_alive(is_anonymous || h_class_loader.is_null()), _metaspace(NULL), _unloading(false), _klasses(NULL), _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL), - _next(NULL), _dependencies(dependencies), + _next(NULL), _dependencies(dependencies), _shared_class_loader_id(-1), _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true, Monitor::_safepoint_check_never)) { // empty diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp index fce18be32f0..ce323c799f8 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp @@ -187,6 +187,9 @@ class ClassLoaderData : public CHeapObj { // Support for walking class loader data objects ClassLoaderData* _next; /// Next loader_datas created + // CDS + int _shared_class_loader_id; + // ReadOnly and ReadWrite metaspaces (static because only on the null // class loader for now). static Metaspace* _ro_metaspace; @@ -308,6 +311,15 @@ class ClassLoaderData : public CHeapObj { Metaspace* ro_metaspace(); Metaspace* rw_metaspace(); void initialize_shared_metaspaces(); + + int shared_class_loader_id() { + return _shared_class_loader_id; + } + void set_shared_class_loader_id(int id) { + assert(id >= 0, "sanity"); + assert(_shared_class_loader_id <0, "cannot be assigned more than once"); + _shared_class_loader_id = id; + } }; // An iterator that distributes Klasses to parallel worker threads. diff --git a/hotspot/src/share/vm/classfile/classLoaderExt.cpp b/hotspot/src/share/vm/classfile/classLoaderExt.cpp new file mode 100644 index 00000000000..44efabec083 --- /dev/null +++ b/hotspot/src/share/vm/classfile/classLoaderExt.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/classListParser.hpp" +#include "classfile/classLoaderExt.hpp" +#include "classfile/symbolTable.hpp" +#include "classfile/systemDictionary.hpp" + + +Klass* ClassLoaderExt::load_one_class(ClassListParser* parser, TRAPS) { + TempNewSymbol class_name_symbol = SymbolTable::new_symbol(parser->current_class_name(), THREAD); + guarantee(!HAS_PENDING_EXCEPTION, "Exception creating a symbol."); + return SystemDictionary::resolve_or_null(class_name_symbol, THREAD); +} diff --git a/hotspot/src/share/vm/classfile/classLoaderExt.hpp b/hotspot/src/share/vm/classfile/classLoaderExt.hpp index 52d9c07d32c..c455a25bd5c 100644 --- a/hotspot/src/share/vm/classfile/classLoaderExt.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderExt.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -29,6 +29,8 @@ #include "oops/instanceKlass.hpp" #include "runtime/handles.hpp" +class ClassListParser; + class ClassLoaderExt: public ClassLoader { // AllStatic public: @@ -69,6 +71,7 @@ public: ClassLoader::add_to_list(new_entry); } static void setup_search_paths() {} + static Klass* load_one_class(ClassListParser* parser, TRAPS); }; #endif // SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP diff --git a/hotspot/src/share/vm/classfile/dictionary.cpp b/hotspot/src/share/vm/classfile/dictionary.cpp index 82e4e71cf81..fde1bb4c6c7 100644 --- a/hotspot/src/share/vm/classfile/dictionary.cpp +++ b/hotspot/src/share/vm/classfile/dictionary.cpp @@ -23,8 +23,10 @@ */ #include "precompiled.hpp" +#include "classfile/sharedClassUtil.hpp" #include "classfile/dictionary.hpp" #include "classfile/systemDictionary.hpp" +#include "classfile/systemDictionaryShared.hpp" #include "memory/iterator.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp" @@ -34,9 +36,16 @@ DictionaryEntry* Dictionary::_current_class_entry = NULL; int Dictionary::_current_class_index = 0; +size_t Dictionary::entry_size() { + if (DumpSharedSpaces) { + return SystemDictionaryShared::dictionary_entry_size(); + } else { + return sizeof(DictionaryEntry); + } +} Dictionary::Dictionary(int table_size) - : TwoOopHashtable(table_size, sizeof(DictionaryEntry)) { + : TwoOopHashtable(table_size, (int)entry_size()) { _current_class_index = 0; _current_class_entry = NULL; _pd_cache_table = new ProtectionDomainCacheTable(defaultProtectionDomainCacheSize); @@ -45,7 +54,7 @@ Dictionary::Dictionary(int table_size) Dictionary::Dictionary(int table_size, HashtableBucket* t, int number_of_entries) - : TwoOopHashtable(table_size, sizeof(DictionaryEntry), t, number_of_entries) { + : TwoOopHashtable(table_size, (int)entry_size(), t, number_of_entries) { _current_class_index = 0; _current_class_entry = NULL; _pd_cache_table = new ProtectionDomainCacheTable(defaultProtectionDomainCacheSize); @@ -61,6 +70,9 @@ DictionaryEntry* Dictionary::new_entry(unsigned int hash, Klass* klass, entry->set_loader_data(loader_data); entry->set_pd_set(NULL); assert(klass->is_instance_klass(), "Must be"); + if (DumpSharedSpaces) { + SystemDictionaryShared::init_shared_dictionary_entry(klass, entry); + } return entry; } diff --git a/hotspot/src/share/vm/classfile/dictionary.hpp b/hotspot/src/share/vm/classfile/dictionary.hpp index 1f6b568670e..19bd96e1380 100644 --- a/hotspot/src/share/vm/classfile/dictionary.hpp +++ b/hotspot/src/share/vm/classfile/dictionary.hpp @@ -53,6 +53,7 @@ private: DictionaryEntry* get_entry(int index, unsigned int hash, Symbol* name, ClassLoaderData* loader_data); +protected: DictionaryEntry* bucket(int i) { return (DictionaryEntry*)Hashtable::bucket(i); } @@ -66,6 +67,7 @@ private: Hashtable::add_entry(index, (HashtableEntry*)new_entry); } + static size_t entry_size(); public: Dictionary(int table_size); Dictionary(int table_size, HashtableBucket* t, int number_of_entries); diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp index d1992e4bd4a..fb3d143d217 100644 --- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #ifndef SHARE_VM_CLASSFILE_SHAREDPATHSMISCINFO_HPP #define SHARE_VM_CLASSFILE_SHAREDPATHSMISCINFO_HPP +#include "classfile/classLoader.hpp" #include "runtime/os.hpp" // During dumping time, when processing class paths, we build up the dump-time @@ -106,19 +107,6 @@ public: add_path(path, NON_EXIST); } - // The path must exist and have required size and modification time - void add_required_file(const char* path) { - add_path(path, REQUIRED); - - struct stat st; - if (os::stat(path, &st) != 0) { - assert(0, "sanity"); - ClassLoader::exit_with_path_failure("failed to os::stat(%s)", path); // should not happen - } - write_time(st.st_mtime); - write_long(st.st_size); - } - // The path must exist, and must contain exactly files/dirs void add_boot_classpath(const char* path) { add_path(path, BOOT); diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index ec634070767..fdac5374d6b 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -322,6 +322,17 @@ Klass* SystemDictionary::resolve_super_or_fail(Symbol* child_name, Handle protection_domain, bool is_superclass, TRAPS) { +#if INCLUDE_CDS + if (DumpSharedSpaces) { + // Special processing for CDS dump time. + Klass* k = SystemDictionaryShared::dump_time_resolve_super_or_fail(child_name, + class_name, class_loader, protection_domain, is_superclass, CHECK_NULL); + if (k) { + return k; + } + } +#endif // INCLUDE_CDS + // Double-check, if child class is already loaded, just return super-class,interface // Don't add a placedholder if already loaded, i.e. already in system dictionary // Make sure there's a placeholder for the *child* before resolving. @@ -1079,12 +1090,30 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name, // // Note: "name" is updated. - instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name, - loader_data, - protection_domain, - parsed_name, - verify, - THREAD); + instanceKlassHandle k; + +#if INCLUDE_CDS + k = SystemDictionaryShared::lookup_from_stream(class_name, + class_loader, + protection_domain, + st, + verify, + CHECK_NULL); +#endif + + if (k.not_null()) { + parsed_name = k->name(); + } else { + if (st->buffer() == NULL) { + return NULL; + } + k = ClassFileParser(st).parseClassFile(class_name, + loader_data, + protection_domain, + parsed_name, + verify, + THREAD); + } const char* pkg = "java/"; if (!HAS_PENDING_EXCEPTION && @@ -1201,8 +1230,13 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, if (ik->super() != NULL) { Symbol* cn = ik->super()->name(); - resolve_super_or_fail(class_name, cn, - class_loader, protection_domain, true, CHECK_(nh)); + Klass *s = resolve_super_or_fail(class_name, cn, + class_loader, protection_domain, true, CHECK_(nh)); + if (s != ik->super()) { + // The dynamically resolved super class is not the same as the one we used during dump time, + // so we cannot use ik. + return nh; + } } Array* interfaces = ik->local_interfaces(); @@ -1215,7 +1249,12 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, // reinitialized yet (they will be once the interface classes // are loaded) Symbol* name = k->name(); - resolve_super_or_fail(class_name, name, class_loader, protection_domain, false, CHECK_(nh)); + Klass* i = resolve_super_or_fail(class_name, name, class_loader, protection_domain, false, CHECK_(nh)); + if (k != i) { + // The dynamically resolved interface class is not the same as the one we used during dump time, + // so we cannot use ik. + return nh; + } } // Adjust methods to recover missing data. They need addresses for diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index b9491903cfd..e735f095dbe 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -27,6 +27,7 @@ #include "classfile/classFileStream.hpp" #include "classfile/classLoader.hpp" +#include "classfile/systemDictionary_ext.hpp" #include "oops/objArrayOop.hpp" #include "oops/symbol.hpp" #include "runtime/java.hpp" @@ -194,15 +195,18 @@ class Ticks; do_klass(Integer_klass, java_lang_Integer, Pre ) \ do_klass(Long_klass, java_lang_Long, Pre ) \ \ + /* Extensions */ \ + WK_KLASSES_DO_EXT(do_klass) \ /* JVMCI classes. These are loaded on-demand. */ \ - JVMCI_WK_KLASSES_DO(do_klass) \ - + JVMCI_WK_KLASSES_DO(do_klass) \ + \ /*end*/ class SystemDictionary : AllStatic { friend class VMStructs; friend class SystemDictionaryHandles; + friend class SharedClassUtil; public: enum WKID { @@ -667,11 +671,6 @@ protected: // Basic find on classes in the midst of being loaded static Symbol* find_placeholder(Symbol* name, ClassLoaderData* loader_data); - // Updating entry in dictionary - // Add a completely loaded class - static void add_klass(int index, Symbol* class_name, - ClassLoaderData* loader_data, KlassHandle obj); - // Add a placeholder for a class being loaded static void add_placeholder(int index, Symbol* class_name, diff --git a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp index bc688798ce8..246ed1dfea6 100644 --- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,11 +22,13 @@ * */ - #ifndef SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP #define SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP #include "classfile/systemDictionary.hpp" +#include "classfile/dictionary.hpp" + +class ClassFileStream; class SystemDictionaryShared: public SystemDictionary { public: @@ -42,6 +44,30 @@ public: oop class_loader = loader_data->class_loader(); return (class_loader == NULL); } + + static Klass* dump_time_resolve_super_or_fail(Symbol* child_name, + Symbol* class_name, + Handle class_loader, + Handle protection_domain, + bool is_superclass, + TRAPS) { + return NULL; + } + + static size_t dictionary_entry_size() { + return sizeof(DictionaryEntry); + } + + static void init_shared_dictionary_entry(Klass* k, DictionaryEntry* entry) {} + + static InstanceKlass* lookup_from_stream(Symbol* class_name, + Handle class_loader, + Handle protection_domain, + ClassFileStream* st, + bool verify, + TRAPS) { + return NULL; + } }; #endif // SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP diff --git a/hotspot/src/share/vm/classfile/systemDictionary_ext.hpp b/hotspot/src/share/vm/classfile/systemDictionary_ext.hpp new file mode 100644 index 00000000000..698805b657d --- /dev/null +++ b/hotspot/src/share/vm/classfile/systemDictionary_ext.hpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_CLASSFILE_SYSTEMDICTIONARY_EXT_HPP +#define SHARE_VM_CLASSFILE_SYSTEMDICTIONARY_EXT_HPP + +#define WK_KLASSES_DO_EXT(do_klass) + +#endif // SHARE_VM_CLASSFILE_SYSTEMDICTIONARY_EXT_HPP diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index f98f400064d..91ceb9b4925 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_VM_CLASSFILE_VMSYMBOLS_HPP #define SHARE_VM_CLASSFILE_VMSYMBOLS_HPP +#include "classfile/vmSymbols_ext.hpp" #include "oops/symbol.hpp" #include "memory/iterator.hpp" #include "trace/traceMacros.hpp" @@ -617,6 +618,9 @@ /* trace signatures */ \ TRACE_TEMPLATES(template) \ \ + /* extensions */ \ + VM_SYMBOLS_DO_EXT(template, do_alias) \ + \ /*end*/ // Here are all the intrinsics known to the runtime and the CI. diff --git a/hotspot/src/share/vm/classfile/vmSymbols_ext.hpp b/hotspot/src/share/vm/classfile/vmSymbols_ext.hpp new file mode 100644 index 00000000000..4b68d8f234b --- /dev/null +++ b/hotspot/src/share/vm/classfile/vmSymbols_ext.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_CLASSFILE_VMSYMBOLS_EXT_HPP +#define SHARE_VM_CLASSFILE_VMSYMBOLS_EXT_HPP + +#define VM_SYMBOLS_DO_EXT(template, do_alias) + +#endif // SHARE_VM_CLASSFILE_VMSYMBOLS_EXT_HPP + diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index 0af64dbed96..a703ad4e607 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -23,6 +23,8 @@ */ #include "precompiled.hpp" +#include "classfile/classListParser.hpp" +#include "classfile/classLoaderExt.hpp" #include "classfile/dictionary.hpp" #include "classfile/loaderConstraints.hpp" #include "classfile/placeholders.hpp" @@ -42,6 +44,7 @@ #include "runtime/signature.hpp" #include "runtime/vmThread.hpp" #include "runtime/vm_operations.hpp" +#include "utilities/defaultStream.hpp" #include "utilities/hashtable.inline.hpp" int MetaspaceShared::_max_alignment = 0; @@ -97,6 +100,10 @@ static void collect_classes(Klass* k) { } } +static void collect_classes2(Klass* k, ClassLoaderData* class_data) { + collect_classes(k); +} + static void remove_unshareable_in_classes() { for (int i = 0; i < _global_klass_objects->length(); i++) { Klass* k = _global_klass_objects->at(i); @@ -422,12 +429,15 @@ private: VirtualSpace _mc_vs; CompactHashtableWriter* _string_cht; GrowableArray *_string_regions; + char* _md_alloc_low; + char* _md_alloc_top; + char* _md_alloc_max; + static VM_PopulateDumpSharedSpace* _instance; public: VM_PopulateDumpSharedSpace(ClassLoaderData* loader_data, GrowableArray *class_promote_order) : _loader_data(loader_data) { - // Split up and initialize the misc code and data spaces ReservedSpace* shared_rs = MetaspaceShared::shared_rs(); size_t metadata_size = SharedReadOnlySize + SharedReadWriteSize; @@ -440,11 +450,43 @@ public: _md_vs.initialize(md_rs, SharedMiscDataSize); _mc_vs.initialize(mc_rs, SharedMiscCodeSize); _class_promote_order = class_promote_order; + + _md_alloc_low = _md_vs.low(); + _md_alloc_top = _md_alloc_low + sizeof(char*); + _md_alloc_max = _md_vs.low() + SharedMiscDataSize; + + assert(_instance == NULL, "must be singleton"); + _instance = this; + } + + ~VM_PopulateDumpSharedSpace() { + assert(_instance == this, "must be singleton"); + _instance = NULL; + } + + static VM_PopulateDumpSharedSpace* instance() { + assert(_instance != NULL, "sanity"); + return _instance; } VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; } void doit(); // outline because gdb sucks + char* misc_data_space_alloc(size_t num_bytes) { + size_t alignment = sizeof(char*); + num_bytes = align_size_up(num_bytes, alignment); + _md_alloc_top = (char*)align_ptr_up(_md_alloc_top, alignment); + if (_md_alloc_top + num_bytes > _md_alloc_max) { + report_out_of_shared_space(SharedMiscData); + } + + char* p = _md_alloc_top; + _md_alloc_top += num_bytes; + + memset(p, 0, num_bytes); + return p; + } + private: void handle_misc_data_space_failure(bool success) { if (!success) { @@ -453,6 +495,7 @@ private: } }; // class VM_PopulateDumpSharedSpace +VM_PopulateDumpSharedSpace* VM_PopulateDumpSharedSpace::_instance; void VM_PopulateDumpSharedSpace::doit() { Thread* THREAD = VMThread::vm_thread(); @@ -475,7 +518,11 @@ void VM_PopulateDumpSharedSpace::doit() { // that so we don't have to walk the SystemDictionary again. _global_klass_objects = new GrowableArray(1000); Universe::basic_type_classes_do(collect_classes); - SystemDictionary::classes_do(collect_classes); + + // Need to call SystemDictionary::classes_do(void f(Klass*, ClassLoaderData*)) + // as we may have some classes with NULL ClassLoaderData* in the dictionary. Other + // variants of SystemDictionary::classes_do will skip those classes. + SystemDictionary::classes_do(collect_classes2); tty->print_cr("Number of classes %d", _global_klass_objects->length()); { @@ -515,6 +562,10 @@ void VM_PopulateDumpSharedSpace::doit() { char* mc_top = mc_low; char* mc_end = _mc_vs.high(); + assert(_md_alloc_top != NULL, "sanity"); + *(char**)_md_alloc_low = _md_alloc_top; + md_top = _md_alloc_top; + // Reserve space for the list of Klass*s whose vtables are used // for patching others as needed. @@ -735,6 +786,7 @@ void MetaspaceShared::prepare_for_dumping() { void MetaspaceShared::preload_and_dump(TRAPS) { TraceTime timer("Dump Shared Spaces", TraceStartupTime); ResourceMark rm; + char class_list_path_str[JVM_MAXPATHLEN]; tty->print_cr("Allocated shared space: " SIZE_FORMAT " bytes at " PTR_FORMAT, MetaspaceShared::shared_rs()->size(), @@ -747,7 +799,6 @@ void MetaspaceShared::preload_and_dump(TRAPS) { // Construct the path to the class list (in jre/lib) // Walk up two directories from the location of the VM and // optionally tack on "lib" (depending on platform) - char class_list_path_str[JVM_MAXPATHLEN]; os::jvm_path(class_list_path_str, sizeof(class_list_path_str)); for (int i = 0; i < 3; i++) { char *end = strrchr(class_list_path_str, *os::file_separator()); @@ -785,6 +836,11 @@ void MetaspaceShared::preload_and_dump(TRAPS) { static const char map_entry_array_sig[] = "[Ljava/util/Map$Entry;"; SymbolTable::new_permanent_symbol(map_entry_array_sig, THREAD); + // Need to allocate the op here: + // op.misc_data_space_alloc() will be called during preload_and_dump(). + ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); + VM_PopulateDumpSharedSpace op(loader_data, class_promote_order); + tty->print_cr("Loading classes to share ..."); _has_error_classes = false; class_count += preload_and_dump(class_list_path, class_promote_order, @@ -809,44 +865,27 @@ void MetaspaceShared::preload_and_dump(TRAPS) { link_and_cleanup_shared_classes(CATCH); tty->print_cr("Rewriting and linking classes: done"); - // Create and dump the shared spaces. Everything so far is loaded - // with the null class loader. - ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); - VM_PopulateDumpSharedSpace op(loader_data, class_promote_order); VMThread::execute(&op); - // Since various initialization steps have been undone by this process, // it is not reasonable to continue running a java process. exit(0); } -int MetaspaceShared::preload_and_dump(const char * class_list_path, + +int MetaspaceShared::preload_and_dump(const char* class_list_path, GrowableArray* class_promote_order, TRAPS) { - FILE* file = fopen(class_list_path, "r"); - char class_name[256]; + ClassListParser parser(class_list_path); int class_count = 0; - if (file != NULL) { - while ((fgets(class_name, sizeof class_name, file)) != NULL) { - if (*class_name == '#') { // comment - continue; - } - // Remove trailing newline - size_t name_len = strlen(class_name); - if (class_name[name_len-1] == '\n') { - class_name[name_len-1] = '\0'; - } + while (parser.parse_one_line()) { + Klass* klass = ClassLoaderExt::load_one_class(&parser, THREAD); - // Got a class name - load it. - TempNewSymbol class_name_symbol = SymbolTable::new_permanent_symbol(class_name, THREAD); - guarantee(!HAS_PENDING_EXCEPTION, "Exception creating a symbol."); - Klass* klass = SystemDictionary::resolve_or_null(class_name_symbol, - THREAD); CLEAR_PENDING_EXCEPTION; if (klass != NULL) { if (PrintSharedSpaces && Verbose && WizardMode) { - tty->print_cr("Shared spaces preloaded: %s", class_name); + ResourceMark rm; + tty->print_cr("Shared spaces preloaded: %s", klass->external_name()); } InstanceKlass* ik = InstanceKlass::cast(klass); @@ -862,17 +901,8 @@ int MetaspaceShared::preload_and_dump(const char * class_list_path, guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class"); class_count++; - } else { - //tty->print_cr("Preload failed: %s", class_name); } } - fclose(file); - } else { - char errmsg[JVM_MAXPATHLEN]; - os::lasterror(errmsg, JVM_MAXPATHLEN); - tty->print_cr("Loading classlist failed: %s", errmsg); - exit(1); - } return class_count; } @@ -908,6 +938,11 @@ bool MetaspaceShared::try_link_class(InstanceKlass* ik, TRAPS) { } } +// Allocate misc data blocks during dumping. +char* MetaspaceShared::misc_data_space_alloc(size_t num_bytes) { + return VM_PopulateDumpSharedSpace::instance()->misc_data_space_alloc(num_bytes); +} + // Closure for serializing initialization data in from a data area // (ptr_array) read from the shared file. @@ -1033,6 +1068,8 @@ void MetaspaceShared::initialize_shared_spaces() { char* buffer = mapinfo->header()->region_addr(md); + buffer = *((char**)buffer); // skip over the md_alloc'ed blocks + // Skip over (reserve space for) a list of addresses of C++ vtables // for Klass objects. They get filled in later. diff --git a/hotspot/src/share/vm/memory/metaspaceShared.hpp b/hotspot/src/share/vm/memory/metaspaceShared.hpp index dbb328ee4e8..6d56012c0f2 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.hpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp @@ -160,5 +160,8 @@ class MetaspaceShared : AllStatic { static int count_class(const char* classlist_file); static void estimate_regions_size() NOT_CDS_RETURN; + + // Allocate a block of memory from the "md" region. + static char* misc_data_space_alloc(size_t num_bytes); }; #endif // SHARE_VM_MEMORY_METASPACESHARED_HPP diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index a386a3f5313..6c68a00d29c 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -1271,6 +1271,10 @@ WB_ENTRY(void, WB_AssertMatchingSafepointCalls(JNIEnv* env, jobject o, jboolean attemptedNoSafepointValue == JNI_TRUE); WB_END +WB_ENTRY(jboolean, WB_IsSharedClass(JNIEnv* env, jobject wb, jclass clazz)) + return (jboolean)MetaspaceShared::is_in_shared_space(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); +WB_END + WB_ENTRY(jboolean, WB_IsMonitorInflated(JNIEnv* env, jobject wb, jobject obj)) oop obj_oop = JNIHandles::resolve(obj); return (jboolean) obj_oop->mark()->has_monitor(); @@ -1471,6 +1475,7 @@ static JNINativeMethod methods[] = { {CC"runMemoryUnitTests", CC"()V", (void*)&WB_RunMemoryUnitTests}, {CC"readFromNoaccessArea",CC"()V", (void*)&WB_ReadFromNoaccessArea}, {CC"stressVirtualSpaceResize",CC"(JJJ)I", (void*)&WB_StressVirtualSpaceResize}, + {CC"isSharedClass", CC"(Ljava/lang/Class;)Z", (void*)&WB_IsSharedClass }, #if INCLUDE_ALL_GCS {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark}, {CC"g1IsHumongous0", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous }, diff --git a/hotspot/src/share/vm/utilities/hashtable.cpp b/hotspot/src/share/vm/utilities/hashtable.cpp index d9044fb259c..b62c52b5e54 100644 --- a/hotspot/src/share/vm/utilities/hashtable.cpp +++ b/hotspot/src/share/vm/utilities/hashtable.cpp @@ -365,6 +365,7 @@ template class RehashableHashtable; template class RehashableHashtable; template class Hashtable; template class Hashtable; +template class Hashtable; template class Hashtable; #if defined(SOLARIS) || defined(CHECK_UNHANDLED_OOPS) template class Hashtable; @@ -378,6 +379,7 @@ template class HashtableEntry; template class BasicHashtableEntry; template class BasicHashtableEntry; template class BasicHashtable; +template class BasicHashtable; template class BasicHashtable; template class BasicHashtable; template class BasicHashtable; From d84d65893bd83e5d25c745b511c6c8d22cdcf49b Mon Sep 17 00:00:00 2001 From: Derek White Date: Thu, 19 Nov 2015 12:43:08 -0500 Subject: [PATCH 004/260] 8143252: Clean up G1CollectedHeap interface Delete unused methods and parameters Reviewed-by: mgerdin, tschatzl, pliden --- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 34 +++++++----------- .../src/share/vm/gc/g1/g1CollectedHeap.hpp | 35 +++++-------------- 2 files changed, 21 insertions(+), 48 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index 2b63e5dd67e..7b319955f19 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -1202,9 +1202,8 @@ void G1CollectedHeap::print_hrm_post_compaction() { heap_region_iterate(&cl); } -bool G1CollectedHeap::do_collection(bool explicit_gc, - bool clear_all_soft_refs, - size_t word_size) { +bool G1CollectedHeap::do_full_collection(bool explicit_gc, + bool clear_all_soft_refs) { assert_at_safepoint(true /* should_be_vm_thread */); if (GC_locker::check_active_before_gc()) { @@ -1362,8 +1361,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, clear_rsets_post_compaction(); check_gc_time_stamps(); - // Resize the heap if necessary. - resize_if_necessary_after_full_collection(explicit_gc ? 0 : word_size); + resize_if_necessary_after_full_collection(); if (_hr_printer.is_active()) { // We should do this after we potentially resize the heap so @@ -1471,22 +1469,15 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, } void G1CollectedHeap::do_full_collection(bool clear_all_soft_refs) { - // do_collection() will return whether it succeeded in performing - // the GC. Currently, there is no facility on the - // do_full_collection() API to notify the caller than the collection - // did not succeed (e.g., because it was locked out by the GC - // locker). So, right now, we'll ignore the return value. - bool dummy = do_collection(true, /* explicit_gc */ - clear_all_soft_refs, - 0 /* word_size */); + // Currently, there is no facility in the do_full_collection(bool) API to notify + // the caller that the collection did not succeed (e.g., because it was locked + // out by the GC locker). So, right now, we'll ignore the return value. + bool dummy = do_full_collection(true, /* explicit_gc */ + clear_all_soft_refs); } -// This code is mostly copied from TenuredGeneration. -void -G1CollectedHeap:: -resize_if_necessary_after_full_collection(size_t word_size) { - // Include the current allocation, if any, and bytes that will be - // pre-allocated to support collections, as "used". +void G1CollectedHeap::resize_if_necessary_after_full_collection() { + // Include bytes that will be pre-allocated to support collections, as "used". const size_t used_after_gc = used(); const size_t capacity_after_gc = capacity(); const size_t free_after_gc = capacity_after_gc - used_after_gc; @@ -1598,9 +1589,8 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size, if (do_gc) { // Expansion didn't work, we'll try to do a Full GC. - *gc_succeeded = do_collection(false, /* explicit_gc */ - clear_all_soft_refs, - word_size); + *gc_succeeded = do_full_collection(false, /* explicit_gc */ + clear_all_soft_refs); } return NULL; diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index e34e1684493..8acf26779e7 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -471,26 +471,20 @@ protected: void retire_gc_alloc_region(HeapRegion* alloc_region, size_t allocated_bytes, InCSetState dest); - // - if explicit_gc is true, the GC is for a System.gc() or a heap - // inspection request and should collect the entire heap + // - if explicit_gc is true, the GC is for a System.gc() etc, + // otherwise it's for a failed allocation. // - if clear_all_soft_refs is true, all soft references should be - // cleared during the GC - // - if explicit_gc is false, word_size describes the allocation that - // the GC should attempt (at least) to satisfy + // cleared during the GC. // - it returns false if it is unable to do the collection due to the - // GC locker being active, true otherwise - bool do_collection(bool explicit_gc, - bool clear_all_soft_refs, - size_t word_size); + // GC locker being active, true otherwise. + bool do_full_collection(bool explicit_gc, + bool clear_all_soft_refs); - // Callback from VM_G1CollectFull operation. - // Perform a full collection. + // Callback from VM_G1CollectFull operation, or collect_as_vm_thread. virtual void do_full_collection(bool clear_all_soft_refs); - // Resize the heap if necessary after a full collection. If this is - // after a collect-for allocation, "word_size" is the allocation size, - // and will be considered part of the used portion of the heap. - void resize_if_necessary_after_full_collection(size_t word_size); + // Resize the heap if necessary after a full collection. + void resize_if_necessary_after_full_collection(); // Callback from VM_G1CollectForAllocation operation. // This function does everything necessary/possible to satisfy a @@ -1150,9 +1144,6 @@ public: // "CollectedHeap" supports. virtual void collect(GCCause::Cause cause); - // The same as above but assume that the caller holds the Heap_lock. - void collect_locked(GCCause::Cause cause); - virtual bool copy_allocation_context_stats(const jint* contexts, jlong* totals, jbyte* accuracy, @@ -1352,14 +1343,6 @@ public: return (region_size / 2); } - // Update mod union table with the set of dirty cards. - void updateModUnion(); - - // Set the mod union bits corresponding to the given memRegion. Note - // that this is always a safe operation, since it doesn't clear any - // bits. - void markModUnionRange(MemRegion mr); - // Print the maximum heap capacity. virtual size_t max_capacity() const; From 97470c5146d300415659339e4d462cbd56e8cc39 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Thu, 19 Nov 2015 16:32:41 -0600 Subject: [PATCH 005/260] 8138983: Runtime: implement ranges for Shared*** flags Implement ranges. Reviewed-by: ddmitriev, dholmes, jiangli --- .../share/vm/classfile/compactHashtable.cpp | 2 +- hotspot/src/share/vm/memory/metaspace.cpp | 30 --- .../src/share/vm/memory/metaspaceShared.hpp | 76 +++++--- .../runtime/commandLineFlagConstraintList.cpp | 2 +- .../vm/runtime/commandLineFlagRangeList.cpp | 2 +- .../vm/runtime/commandLineFlagRangeList.hpp | 1 + hotspot/src/share/vm/runtime/globals.hpp | 15 +- .../TestOptionsWithRanges.java | 21 ++- .../optionsvalidation/IntJVMOption.java | 4 +- .../optionsvalidation/JVMOptionsUtils.java | 89 ++++++++- .../SharedArchiveFile/LimitSharedSizes.java | 178 ++++++++++-------- 11 files changed, 274 insertions(+), 146 deletions(-) diff --git a/hotspot/src/share/vm/classfile/compactHashtable.cpp b/hotspot/src/share/vm/classfile/compactHashtable.cpp index 39dd55f9a17..c951c512558 100644 --- a/hotspot/src/share/vm/classfile/compactHashtable.cpp +++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp @@ -137,7 +137,7 @@ juint* CompactHashtableWriter::dump_buckets(juint* compact_table, juint* p, if (_type == CompactHashtable::_symbol_table) { base_address = uintx(MetaspaceShared::shared_rs()->base()); max_delta = uintx(MetaspaceShared::shared_rs()->size()); - assert(max_delta <= 0x7fffffff, "range check"); + assert(max_delta <= MAX_SHARED_DELTA, "range check"); } else { assert((_type == CompactHashtable::_string_table), "unknown table"); assert(UseCompressedOops, "UseCompressedOops is required"); diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index f4e40db3193..74ee0877ba9 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -3230,36 +3230,6 @@ void Metaspace::global_initialize() { SharedMiscDataSize = align_size_up(SharedMiscDataSize, max_alignment); SharedMiscCodeSize = align_size_up(SharedMiscCodeSize, max_alignment); - // make sure SharedReadOnlySize and SharedReadWriteSize are not less than - // the minimum values. - if (SharedReadOnlySize < MetaspaceShared::min_ro_size){ - report_out_of_shared_space(SharedReadOnly); - } - - if (SharedReadWriteSize < MetaspaceShared::min_rw_size){ - report_out_of_shared_space(SharedReadWrite); - } - - // the min_misc_data_size and min_misc_code_size estimates are based on - // MetaspaceShared::generate_vtable_methods(). - // The minimum size only accounts for the vtable methods. Any size less than the - // minimum required size would cause vm crash when allocating the vtable methods. - uint min_misc_data_size = align_size_up( - MetaspaceShared::num_virtuals * MetaspaceShared::vtbl_list_size * sizeof(void*), max_alignment); - - if (SharedMiscDataSize < min_misc_data_size) { - report_out_of_shared_space(SharedMiscData); - } - - uintx min_misc_code_size = align_size_up( - (MetaspaceShared::num_virtuals * MetaspaceShared::vtbl_list_size) * - (sizeof(void*) + MetaspaceShared::vtbl_method_size) + MetaspaceShared::vtbl_common_code_size, - max_alignment); - - if (SharedMiscCodeSize < min_misc_code_size) { - report_out_of_shared_space(SharedMiscCode); - } - // Initialize with the sum of the shared space sizes. The read-only // and read write metaspace chunks will be allocated out of this and the // remainder is the misc code and data chunks. diff --git a/hotspot/src/share/vm/memory/metaspaceShared.hpp b/hotspot/src/share/vm/memory/metaspaceShared.hpp index dbb328ee4e8..46bdfd986a0 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.hpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp @@ -32,14 +32,55 @@ #include "utilities/exceptions.hpp" #include "utilities/macros.hpp" -#define LargeSharedArchiveSize (300*M) -#define HugeSharedArchiveSize (800*M) -#define ReadOnlyRegionPercentage 0.4 -#define ReadWriteRegionPercentage 0.55 -#define MiscDataRegionPercentage 0.03 -#define MiscCodeRegionPercentage 0.02 -#define LargeThresholdClassCount 5000 -#define HugeThresholdClassCount 40000 +#define DEFAULT_VTBL_LIST_SIZE (17) // number of entries in the shared space vtable list. +#define DEFAULT_VTBL_VIRTUALS_COUNT (200) // maximum number of virtual functions +// If virtual functions are added to Metadata, +// this number needs to be increased. Also, +// SharedMiscCodeSize will need to be increased. +// The following 2 sizes were based on +// MetaspaceShared::generate_vtable_methods() +#define DEFAULT_VTBL_METHOD_SIZE (16) // conservative size of the mov1 and jmp instructions +// for the x64 platform +#define DEFAULT_VTBL_COMMON_CODE_SIZE (1*K) // conservative size of the "common_code" for the x64 platform + +#define DEFAULT_SHARED_READ_WRITE_SIZE (NOT_LP64(12*M) LP64_ONLY(16*M)) +#define MIN_SHARED_READ_WRITE_SIZE (NOT_LP64(7*M) LP64_ONLY(12*M)) + +#define DEFAULT_SHARED_READ_ONLY_SIZE (NOT_LP64(12*M) LP64_ONLY(16*M)) +#define MIN_SHARED_READ_ONLY_SIZE (NOT_LP64(8*M) LP64_ONLY(9*M)) + +// the MIN_SHARED_MISC_DATA_SIZE and MIN_SHARED_MISC_CODE_SIZE estimates are based on +// MetaspaceShared::generate_vtable_methods(). +// The minimum size only accounts for the vtable methods. Any size less than the +// minimum required size would cause vm crash when allocating the vtable methods. +#define SHARED_MISC_SIZE_FOR(size) (DEFAULT_VTBL_VIRTUALS_COUNT*DEFAULT_VTBL_LIST_SIZE*size) + +#define DEFAULT_SHARED_MISC_DATA_SIZE (NOT_LP64(2*M) LP64_ONLY(4*M)) +#define MIN_SHARED_MISC_DATA_SIZE (SHARED_MISC_SIZE_FOR(sizeof(void*))) + +#define DEFAULT_SHARED_MISC_CODE_SIZE (120*K) +#define MIN_SHARED_MISC_CODE_SIZE (SHARED_MISC_SIZE_FOR(sizeof(void*))+SHARED_MISC_SIZE_FOR(DEFAULT_VTBL_METHOD_SIZE)+DEFAULT_VTBL_COMMON_CODE_SIZE) + +#define DEFAULT_COMBINED_SIZE (DEFAULT_SHARED_READ_WRITE_SIZE+DEFAULT_SHARED_READ_ONLY_SIZE+DEFAULT_SHARED_MISC_DATA_SIZE+DEFAULT_SHARED_MISC_CODE_SIZE) + +// the max size is the MAX size (ie. 0x7FFFFFFF) - the total size of +// the other 3 sections - page size (to avoid overflow in case the final +// size will get aligned up on page size) +#define SHARED_PAGE ((size_t)os::vm_page_size()) +#define MAX_SHARED_DELTA (0x7FFFFFFF) +#define MAX_SHARED_READ_WRITE_SIZE (MAX_SHARED_DELTA-(MIN_SHARED_READ_ONLY_SIZE+MIN_SHARED_MISC_DATA_SIZE+MIN_SHARED_MISC_CODE_SIZE)-SHARED_PAGE) +#define MAX_SHARED_READ_ONLY_SIZE (MAX_SHARED_DELTA-(MIN_SHARED_READ_WRITE_SIZE+MIN_SHARED_MISC_DATA_SIZE+MIN_SHARED_MISC_CODE_SIZE)-SHARED_PAGE) +#define MAX_SHARED_MISC_DATA_SIZE (MAX_SHARED_DELTA-(MIN_SHARED_READ_WRITE_SIZE+MIN_SHARED_READ_ONLY_SIZE+MIN_SHARED_MISC_CODE_SIZE)-SHARED_PAGE) +#define MAX_SHARED_MISC_CODE_SIZE (MAX_SHARED_DELTA-(MIN_SHARED_READ_WRITE_SIZE+MIN_SHARED_READ_ONLY_SIZE+MIN_SHARED_MISC_DATA_SIZE)-SHARED_PAGE) + +#define LargeSharedArchiveSize (300*M) +#define HugeSharedArchiveSize (800*M) +#define ReadOnlyRegionPercentage 0.4 +#define ReadWriteRegionPercentage 0.55 +#define MiscDataRegionPercentage 0.03 +#define MiscCodeRegionPercentage 0.02 +#define LargeThresholdClassCount 5000 +#define HugeThresholdClassCount 40000 #define SET_ESTIMATED_SIZE(type, region) \ Shared ##region## Size = FLAG_IS_DEFAULT(Shared ##region## Size) ? \ @@ -69,21 +110,10 @@ class MetaspaceShared : AllStatic { static bool _archive_loading_failed; public: enum { - vtbl_list_size = 17, // number of entries in the shared space vtable list. - num_virtuals = 200, // maximum number of virtual functions - // If virtual functions are added to Metadata, - // this number needs to be increased. Also, - // SharedMiscCodeSize will need to be increased. - // The following 2 sizes were based on - // MetaspaceShared::generate_vtable_methods() - vtbl_method_size = 16, // conservative size of the mov1 and jmp instructions - // for the x64 platform - vtbl_common_code_size = (1*K) // conservative size of the "common_code" for the x64 platform - }; - - enum { - min_ro_size = NOT_LP64(8*M) LP64_ONLY(9*M), // minimum ro and rw regions sizes based on dumping - min_rw_size = NOT_LP64(7*M) LP64_ONLY(12*M) // of a shared archive using the default classlist + vtbl_list_size = DEFAULT_VTBL_LIST_SIZE, + num_virtuals = DEFAULT_VTBL_VIRTUALS_COUNT, + vtbl_method_size = DEFAULT_VTBL_METHOD_SIZE, + vtbl_common_code_size = DEFAULT_VTBL_COMMON_CODE_SIZE }; enum { diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp index 5371aa30da2..27ef604b6e7 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp @@ -223,7 +223,7 @@ void emit_constraint_double(const char* name, CommandLineFlagConstraintFunc_doub #define EMIT_CONSTRAINT_CHECK(func, type) , func, CommandLineFlagConstraint::type // the "name" argument must be a string literal -#define INITIAL_CONSTRAINTS_SIZE 45 +#define INITIAL_CONSTRAINTS_SIZE 69 GrowableArray* CommandLineFlagConstraintList::_constraints = NULL; CommandLineFlagConstraint::ConstraintType CommandLineFlagConstraintList::_validating_type = CommandLineFlagConstraint::AtParse; diff --git a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp index ef45b27f0c6..a1a7cb76bb9 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp @@ -279,7 +279,7 @@ void emit_range_double(const char* name, double min, double max) { // Generate func argument to pass into emit_range_xxx functions #define EMIT_RANGE_CHECK(a, b) , a, b -#define INITIAL_RANGES_SIZE 205 +#define INITIAL_RANGES_SIZE 320 GrowableArray* CommandLineFlagRangeList::_ranges = NULL; // Check the ranges of all flags that have them diff --git a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp index e4be9903214..a6777524890 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP #define SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP +#include "memory/metaspaceShared.hpp" #include "runtime/globals.hpp" #include "utilities/growableArray.hpp" diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index eeb61ea36a6..9724ebdd6d4 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -4110,21 +4110,26 @@ public: "If PrintSharedArchiveAndExit is true, also print the shared " \ "dictionary") \ \ - product(size_t, SharedReadWriteSize, NOT_LP64(12*M) LP64_ONLY(16*M), \ + product(size_t, SharedReadWriteSize, DEFAULT_SHARED_READ_WRITE_SIZE, \ "Size of read-write space for metadata (in bytes)") \ + range(MIN_SHARED_READ_WRITE_SIZE, MAX_SHARED_READ_WRITE_SIZE) \ \ - product(size_t, SharedReadOnlySize, NOT_LP64(12*M) LP64_ONLY(16*M), \ + product(size_t, SharedReadOnlySize, DEFAULT_SHARED_READ_ONLY_SIZE, \ "Size of read-only space for metadata (in bytes)") \ + range(MIN_SHARED_READ_ONLY_SIZE, MAX_SHARED_READ_ONLY_SIZE) \ \ - product(uintx, SharedMiscDataSize, NOT_LP64(2*M) LP64_ONLY(4*M), \ + product(size_t, SharedMiscDataSize, DEFAULT_SHARED_MISC_DATA_SIZE, \ "Size of the shared miscellaneous data area (in bytes)") \ + range(MIN_SHARED_MISC_DATA_SIZE, MAX_SHARED_MISC_DATA_SIZE) \ \ - product(uintx, SharedMiscCodeSize, 120*K, \ + product(size_t, SharedMiscCodeSize, DEFAULT_SHARED_MISC_CODE_SIZE, \ "Size of the shared miscellaneous code area (in bytes)") \ + range(MIN_SHARED_MISC_CODE_SIZE, MAX_SHARED_MISC_CODE_SIZE) \ \ - product(uintx, SharedBaseAddress, LP64_ONLY(32*G) \ + product(size_t, SharedBaseAddress, LP64_ONLY(32*G) \ NOT_LP64(LINUX_ONLY(2*G) NOT_LINUX(0)), \ "Address to allocate shared memory region for class data") \ + range(0, SIZE_MAX) \ \ product(uintx, SharedSymbolTableBucketSize, 4, \ "Average number of symbols per bucket in shared table") \ diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java index fa9ad87eb52..5c9e0b43913 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java @@ -55,9 +55,28 @@ public class TestOptionsWithRanges { * JDK-8136766 * Temporarily remove ThreadStackSize from testing because Windows can set it to 0 * (for default OS size) but other platforms insist it must be greater than 0 - */ + */ allOptionsAsMap.remove("ThreadStackSize"); + /* + * JDK-8141650 + * Temporarily exclude SharedMiscDataSize as it will exit the VM with exit code 2 and + * "The shared miscellaneous data space is not large enough to preload requested classes." + * message at min value. + */ + allOptionsAsMap.remove("SharedMiscDataSize"); + + /* + * JDK-8142874 + * Temporarily exclude Shared* flagse as they will exit the VM with exit code 2 and + * "The shared miscellaneous data space is not large enough to preload requested classes." + * message at max values. + */ + allOptionsAsMap.remove("SharedReadWriteSize"); + allOptionsAsMap.remove("SharedReadOnlySize"); + allOptionsAsMap.remove("SharedMiscDataSize"); + allOptionsAsMap.remove("SharedMiscCodeSize"); + /* * Exclude MallocMaxTestWords as it is expected to exit VM at small values (>=0) */ diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java index 90270e96613..a7685f37ae5 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java @@ -223,7 +223,7 @@ public class IntJVMOption extends JVMOption { validValues.add("1"); } - if (max.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == 1) { + if ((min.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == -1) && (max.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == 1)) { /* * Check for overflow when flag is assigned to the * 4 byte int variable @@ -231,7 +231,7 @@ public class IntJVMOption extends JVMOption { validValues.add(MAX_4_BYTE_INT_PLUS_ONE.toString()); } - if (max.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == 1) { + if ((min.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == -1) && (max.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == 1)) { /* * Check for overflow when flag is assigned to the * 4 byte unsigned int variable diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java index 7158b356eed..a5c8ab0d6f8 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java @@ -27,6 +27,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -49,6 +50,8 @@ public class JVMOptionsUtils { /* Used to start the JVM with the same type as current */ static String VMType; + private static Map optionsAsMap; + static { if (Platform.isServer()) { VMType = "-server"; @@ -63,6 +66,84 @@ public class JVMOptionsUtils { } } + public static boolean fitsRange(String optionName, BigDecimal number) throws Exception { + JVMOption option; + String minRangeString = null; + String maxRangeString = null; + boolean fits = true; + + if (optionsAsMap == null) { + optionsAsMap = getOptionsWithRangeAsMap(); + } + + option = optionsAsMap.get(optionName); + if (option != null) { + minRangeString = option.getMin(); + if (minRangeString != null) { + fits = (number.compareTo(new BigDecimal(minRangeString)) >= 0); + } + maxRangeString = option.getMax(); + if (maxRangeString != null) { + fits &= (number.compareTo(new BigDecimal(maxRangeString)) <= 0); + } + } + + return fits; + } + + public static boolean fitsRange(String optionName, String number) throws Exception { + String lowerCase = number.toLowerCase(); + String multiplier = "1"; + if (lowerCase.endsWith("k")) { + multiplier = "1024"; + lowerCase = lowerCase.substring(0, lowerCase.length()-1); + } else if (lowerCase.endsWith("m")) { + multiplier = "1048576"; //1024*1024 + lowerCase = lowerCase.substring(0, lowerCase.length()-1); + } else if (lowerCase.endsWith("g")) { + multiplier = "1073741824"; //1024*1024*1024 + lowerCase = lowerCase.substring(0, lowerCase.length()-1); + } else if (lowerCase.endsWith("t")) { + multiplier = "1099511627776"; //1024*1024*1024*1024 + lowerCase = lowerCase.substring(0, lowerCase.length()-1); + } + BigDecimal valueBig = new BigDecimal(lowerCase); + BigDecimal multiplierBig = new BigDecimal(multiplier); + return fitsRange(optionName, valueBig.multiply(multiplierBig)); + } + + public static String getMinOptionRange(String optionName) throws Exception { + JVMOption option; + String minRange = null; + + if (optionsAsMap == null) { + optionsAsMap = getOptionsWithRangeAsMap(); + } + + option = optionsAsMap.get(optionName); + if (option != null) { + minRange = option.getMin(); + } + + return minRange; + } + + public static String getMaxOptionRange(String optionName) throws Exception { + JVMOption option; + String maxRange = null; + + if (optionsAsMap == null) { + optionsAsMap = getOptionsWithRangeAsMap(); + } + + option = optionsAsMap.get(optionName); + if (option != null) { + maxRange = option.getMax(); + } + + return maxRange; + } + /** * Add dependency for option depending on it's name. E.g. enable G1 GC for * G1 options or add prepend options to not hit constraints. @@ -80,6 +161,13 @@ public class JVMOptionsUtils { option.addPrepend("-XX:+UseConcMarkSweepGC"); } + if (name.startsWith("Shared")) { + option.addPrepend("-XX:+UnlockDiagnosticVMOptions"); + String fileName = "Test" + name + ".jsa"; + option.addPrepend("-XX:SharedArchiveFile=" + fileName); + option.addPrepend("-Xshare:dump"); + } + switch (name) { case "MinHeapFreeRatio": option.addPrepend("-XX:MaxHeapFreeRatio=100"); @@ -112,7 +200,6 @@ public class JVMOptionsUtils { /* Do nothing */ break; } - } /** diff --git a/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java b/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java index 1cb136c3b57..824fd94f41f 100644 --- a/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java +++ b/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java @@ -23,50 +23,72 @@ /* @test LimitSharedSizes * @summary Test handling of limits on shared space size - * @library /testlibrary + * @library /testlibrary /runtime/CommandLine/OptionsValidation/common * @modules java.base/sun.misc * java.management * @run main LimitSharedSizes */ import jdk.test.lib.*; +import optionsvalidation.JVMOptionsUtils; public class LimitSharedSizes { + static enum Result { + OUT_OF_RANGE, + TOO_SMALL, + VALID, + VALID_ARCHIVE + } + static enum Region { RO, RW, MD, MC } + private static final boolean fitsRange(String name, String value) throws RuntimeException { + boolean fits = true; + try { + fits = JVMOptionsUtils.fitsRange(name, value); + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + return fits; + } + private static class SharedSizeTestData { public String optionName; public String optionValue; - public String expectedErrorMsg; + public Result optionResult; - public SharedSizeTestData(Region region, String value, String msg) { - optionName = getName(region); + public SharedSizeTestData(Region region, String value) { + optionName = "-XX:"+getName(region); optionValue = value; - expectedErrorMsg = msg; + if (fitsRange(getName(region), value) == false) { + optionResult = Result.OUT_OF_RANGE; + } else { + optionResult = Result.TOO_SMALL; + } } - public SharedSizeTestData(Region region, String msg) { - optionName = getName(region); - optionValue = getValue(region); - expectedErrorMsg = msg; + public SharedSizeTestData(Region region, String value, Result result) { + optionName = "-XX:"+getName(region); + optionValue = value; + optionResult = result; } private String getName(Region region) { String name; switch (region) { case RO: - name = "-XX:SharedReadOnlySize"; + name = "SharedReadOnlySize"; break; case RW: - name = "-XX:SharedReadWriteSize"; + name = "SharedReadWriteSize"; break; case MD: - name = "-XX:SharedMiscDataSize"; + name = "SharedMiscDataSize"; break; case MC: - name = "-XX:SharedMiscCodeSize"; + name = "SharedMiscCodeSize"; break; default: name = "Unknown"; @@ -75,53 +97,37 @@ public class LimitSharedSizes { return name; } - private String getValue(Region region) { - String value; - switch (region) { - case RO: - value = Platform.is64bit() ? "9M" : "8M"; - break; - case RW: - value = Platform.is64bit() ? "12M" : "7M"; - break; - case MD: - value = Platform.is64bit() ? "4M" : "2M"; - break; - case MC: - value = "120k"; - break; - default: - value = "0M"; - break; - } - return value; + public Result getResult() { + return optionResult; } } private static final SharedSizeTestData[] testTable = { // Too small of a region size should not cause a vm crash. - // It should result in an error message like the following: + // It should result in an error message either like the following #1: // The shared miscellaneous code space is not large enough // to preload requested classes. Use -XX:SharedMiscCodeSize= // to increase the initial size of shared miscellaneous code space. - new SharedSizeTestData(Region.RO, "4M", "read only"), - new SharedSizeTestData(Region.RW, "4M", "read write"), - new SharedSizeTestData(Region.MD, "50k", "miscellaneous data"), - new SharedSizeTestData(Region.MC, "20k", "miscellaneous code"), + // or #2: + // The shared miscellaneous code space is outside the allowed range + new SharedSizeTestData(Region.RO, "4M"), + new SharedSizeTestData(Region.RW, "4M"), + new SharedSizeTestData(Region.MD, "50k"), + new SharedSizeTestData(Region.MC, "20k"), - // these values are larger than default ones, but should + // these values are larger than default ones, and should // be acceptable and not cause failure - new SharedSizeTestData(Region.RO, "20M", null), - new SharedSizeTestData(Region.RW, "20M", null), - new SharedSizeTestData(Region.MD, "20M", null), - new SharedSizeTestData(Region.MC, "20M", null), + new SharedSizeTestData(Region.RO, "20M", Result.VALID), + new SharedSizeTestData(Region.RW, "20M", Result.VALID), + new SharedSizeTestData(Region.MD, "20M", Result.VALID), + new SharedSizeTestData(Region.MC, "20M", Result.VALID), // test with sizes which just meet the minimum required sizes // the following tests also attempt to use the shared archive - new SharedSizeTestData(Region.RO, "UseArchive"), - new SharedSizeTestData(Region.RW, "UseArchive"), - new SharedSizeTestData(Region.MD, "UseArchive"), - new SharedSizeTestData(Region.MC, "UseArchive") + new SharedSizeTestData(Region.RO, Platform.is64bit() ? "9M":"8M", Result.VALID_ARCHIVE), + new SharedSizeTestData(Region.RW, Platform.is64bit() ? "12M":"7M", Result.VALID_ARCHIVE), + new SharedSizeTestData(Region.MD, Platform.is64bit() ? "4M":"2M", Result.VALID_ARCHIVE), + new SharedSizeTestData(Region.MC, "120k", Result.VALID_ARCHIVE), }; public static void main(String[] args) throws Exception { @@ -131,6 +137,7 @@ public class LimitSharedSizes { counter++; String option = td.optionName + "=" + td.optionValue; + System.out.println("testing option number <" + counter + ">"); System.out.println("testing option <" + option + ">"); ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( @@ -141,43 +148,52 @@ public class LimitSharedSizes { OutputAnalyzer output = new OutputAnalyzer(pb.start()); - if (td.expectedErrorMsg != null) { - if (!td.expectedErrorMsg.equals("UseArchive")) { - output.shouldContain("The shared " + td.expectedErrorMsg - + " space is not large enough"); + switch (td.getResult()) { + case VALID: + case VALID_ARCHIVE: + { + output.shouldNotContain("space is not large enough"); + output.shouldHaveExitValue(0); - output.shouldHaveExitValue(2); - } else { - output.shouldNotContain("space is not large enough"); - output.shouldHaveExitValue(0); + if (td.getResult() == Result.VALID_ARCHIVE) { + // try to use the archive + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./" + fileName, + "-XX:+PrintSharedArchiveAndExit", + "-version"); - // try to use the archive - pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UnlockDiagnosticVMOptions", - "-XX:SharedArchiveFile=./" + fileName, - "-XX:+PrintSharedArchiveAndExit", - "-version"); - - try { - output = new OutputAnalyzer(pb.start()); - output.shouldContain("archive is valid"); - } catch (RuntimeException e) { - // if sharing failed due to ASLR or similar reasons, - // check whether sharing was attempted at all (UseSharedSpaces) - if ((output.getOutput().contains("Unable to use shared archive") || - output.getOutput().contains("Unable to map ReadOnly shared space at required address.") || - output.getOutput().contains("Unable to map ReadWrite shared space at required address.") || - output.getOutput().contains("Unable to reserve shared space at required address")) && - output.getExitValue() == 1) { - System.out.println("Unable to use shared archive: test not executed; assumed passed"); - return; - } - } - output.shouldHaveExitValue(0); + try { + output = new OutputAnalyzer(pb.start()); + output.shouldContain("archive is valid"); + } catch (RuntimeException e) { + // if sharing failed due to ASLR or similar reasons, + // check whether sharing was attempted at all (UseSharedSpaces) + if ((output.getOutput().contains("Unable to use shared archive") || + output.getOutput().contains("Unable to map ReadOnly shared space at required address.") || + output.getOutput().contains("Unable to map ReadWrite shared space at required address.") || + output.getOutput().contains("Unable to reserve shared space at required address")) && + output.getExitValue() == 1) { + System.out.println("Unable to use shared archive: test not executed; assumed passed"); + return; + } + } + output.shouldHaveExitValue(0); + } } - } else { - output.shouldNotContain("space is not large enough"); - output.shouldHaveExitValue(0); + break; + case TOO_SMALL: + { + output.shouldContain("space is not large enough"); + output.shouldHaveExitValue(2); + } + break; + case OUT_OF_RANGE: + { + output.shouldContain("outside the allowed range"); + output.shouldHaveExitValue(1); + } + break; } } } From 57776e7af1ba7006fd70eea9a6662015a2f80ebc Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Fri, 11 Sep 2015 15:18:43 +0200 Subject: [PATCH 006/260] 8142399: G1ParCopyClosure does not need do_oop_work Reviewed-by: stefank, tschatzl --- hotspot/src/share/vm/gc/g1/g1OopClosures.hpp | 5 +---- hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp index 4ea0c653c44..cc5dbd9cf7f 100644 --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp @@ -123,16 +123,13 @@ enum G1Mark { template class G1ParCopyClosure : public G1ParCopyHelper { -private: - template void do_oop_work(T* p); - public: G1ParCopyClosure(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) : G1ParCopyHelper(g1, par_scan_state) { assert(ref_processor() == NULL, "sanity"); } - template void do_oop_nv(T* p) { do_oop_work(p); } + template void do_oop_nv(T* p); virtual void do_oop(oop* p) { do_oop_nv(p); } virtual void do_oop(narrowOop* p) { do_oop_nv(p); } }; diff --git a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp index 176191f7445..4794afec93b 100644 --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp @@ -251,7 +251,7 @@ void G1ParCopyHelper::mark_forwarded_object(oop from_obj, oop to_obj) { template template -void G1ParCopyClosure::do_oop_work(T* p) { +void G1ParCopyClosure::do_oop_nv(T* p) { T heap_oop = oopDesc::load_heap_oop(p); if (oopDesc::is_null(heap_oop)) { From 9a5f4d56ffc94a8db2d0a1b69c5575c8f4b71f2b Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Wed, 21 Oct 2015 10:37:50 +0200 Subject: [PATCH 007/260] 8138894: C1: Support IRIW on weak memory platforms Reviewed-by: twisti, goetz --- hotspot/src/share/vm/c1/c1_GraphBuilder.cpp | 7 ++++++- hotspot/src/share/vm/c1/c1_IR.cpp | 3 ++- hotspot/src/share/vm/c1/c1_IR.hpp | 6 ++++-- hotspot/src/share/vm/c1/c1_LIRGenerator.cpp | 12 ++++++++++-- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp index b924f85905c..15a7fb88311 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp @@ -1438,7 +1438,9 @@ void GraphBuilder::method_return(Value x) { bool need_mem_bar = false; if (method()->name() == ciSymbol::object_initializer_name() && - (scope()->wrote_final() || (AlwaysSafeConstructors && scope()->wrote_fields()))) { + (scope()->wrote_final() || (AlwaysSafeConstructors && scope()->wrote_fields()) + || (support_IRIW_for_not_multiple_copy_atomic_cpu && scope()->wrote_volatile()) + )){ need_mem_bar = true; } @@ -1554,6 +1556,9 @@ void GraphBuilder::access_field(Bytecodes::Code code) { if (code == Bytecodes::_putfield) { scope()->set_wrote_fields(); + if (field->is_volatile()) { + scope()->set_wrote_volatile(); + } } const int offset = !needs_patching ? field->offset() : -1; diff --git a/hotspot/src/share/vm/c1/c1_IR.cpp b/hotspot/src/share/vm/c1/c1_IR.cpp index e2f33a21170..6b015b44d85 100644 --- a/hotspot/src/share/vm/c1/c1_IR.cpp +++ b/hotspot/src/share/vm/c1/c1_IR.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -143,6 +143,7 @@ IRScope::IRScope(Compilation* compilation, IRScope* caller, int caller_bci, ciMe _monitor_pairing_ok = method->has_balanced_monitors(); _wrote_final = false; _wrote_fields = false; + _wrote_volatile = false; _start = NULL; if (osr_bci == -1) { diff --git a/hotspot/src/share/vm/c1/c1_IR.hpp b/hotspot/src/share/vm/c1/c1_IR.hpp index e3dc4ba1950..31d3b01aff2 100644 --- a/hotspot/src/share/vm/c1/c1_IR.hpp +++ b/hotspot/src/share/vm/c1/c1_IR.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -151,6 +151,7 @@ class IRScope: public CompilationResourceObj { bool _monitor_pairing_ok; // the monitor pairing info bool _wrote_final; // has written final field bool _wrote_fields; // has written fields + bool _wrote_volatile; // has written volatile field BlockBegin* _start; // the start block, successsors are method entries BitMap _requires_phi_function; // bit is set if phi functions at loop headers are necessary for a local variable @@ -187,7 +188,8 @@ class IRScope: public CompilationResourceObj { bool wrote_final () const { return _wrote_final; } void set_wrote_fields() { _wrote_fields = true; } bool wrote_fields () const { return _wrote_fields; } - + void set_wrote_volatile() { _wrote_volatile = true; } + bool wrote_volatile () const { return _wrote_volatile; } }; diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index f188dfb942d..8088f047c8d 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -1761,7 +1761,7 @@ void LIRGenerator::do_StoreField(StoreField* x) { post_barrier(object.result(), value.result()); } - if (is_volatile && os::is_MP()) { + if (!support_IRIW_for_not_multiple_copy_atomic_cpu && is_volatile && os::is_MP()) { __ membar(); } } @@ -1822,6 +1822,10 @@ void LIRGenerator::do_LoadField(LoadField* x) { address = generate_address(object.result(), x->offset(), field_type); } + 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); @@ -2238,6 +2242,10 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) { LIR_Opr value = rlock_result(x, x->basic_type()); + if (support_IRIW_for_not_multiple_copy_atomic_cpu && x->is_volatile() && os::is_MP()) { + __ membar(); + } + get_Object_unsafe(value, src.result(), off.result(), type, x->is_volatile()); #if INCLUDE_ALL_GCS @@ -2395,7 +2403,7 @@ void LIRGenerator::do_UnsafePutObject(UnsafePutObject* x) { if (x->is_volatile() && os::is_MP()) __ membar_release(); put_Object_unsafe(src.result(), off.result(), data.result(), type, x->is_volatile()); - if (x->is_volatile() && os::is_MP()) __ membar(); + if (!support_IRIW_for_not_multiple_copy_atomic_cpu && x->is_volatile() && os::is_MP()) __ membar(); } From 45b3ce816a7a56bb3bc8c32e11a4ef3dc2a4a51b Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 28 Oct 2015 10:20:33 +0100 Subject: [PATCH 008/260] 8140309: [REDO] failed: no mismatched stores, except on raw memory: StoreB StoreI Mismatched stores on same slice possible with Unsafe.Put*Unaligned methods Reviewed-by: kvn, thartmann --- hotspot/src/share/vm/opto/graphKit.cpp | 32 +++- hotspot/src/share/vm/opto/graphKit.hpp | 32 ++-- hotspot/src/share/vm/opto/idealKit.cpp | 6 +- hotspot/src/share/vm/opto/idealKit.hpp | 4 +- hotspot/src/share/vm/opto/library_call.cpp | 153 ++++++++++-------- hotspot/src/share/vm/opto/memnode.cpp | 15 +- hotspot/src/share/vm/opto/memnode.hpp | 16 +- ...TestUnsafeUnalignedMismatchedAccesses.java | 122 ++++++++++++++ 8 files changed, 288 insertions(+), 92 deletions(-) create mode 100644 hotspot/test/compiler/intrinsics/unsafe/TestUnsafeUnalignedMismatchedAccesses.java diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index 397e6cb1c81..4d8896dadb7 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -1457,7 +1457,11 @@ void GraphKit::set_all_memory_call(Node* call, bool separate_io_proj) { // factory methods in "int adr_idx" Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, int adr_idx, - MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency, bool require_atomic_access) { + MemNode::MemOrd mo, + LoadNode::ControlDependency control_dependency, + bool require_atomic_access, + bool unaligned, + bool mismatched) { assert(adr_idx != Compile::AliasIdxTop, "use other make_load factory" ); const TypePtr* adr_type = NULL; // debug-mode-only argument debug_only(adr_type = C->get_adr_type(adr_idx)); @@ -1470,6 +1474,12 @@ Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, } else { ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency); } + if (unaligned) { + ld->as_Load()->set_unaligned_access(); + } + if (mismatched) { + ld->as_Load()->set_mismatched_access(); + } ld = _gvn.transform(ld); if ((bt == T_OBJECT) && C->do_escape_analysis() || C->eliminate_boxing()) { // Improve graph before escape analysis and boxing elimination. @@ -1481,7 +1491,9 @@ Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt, int adr_idx, MemNode::MemOrd mo, - bool require_atomic_access) { + bool require_atomic_access, + bool unaligned, + bool mismatched) { assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" ); const TypePtr* adr_type = NULL; debug_only(adr_type = C->get_adr_type(adr_idx)); @@ -1494,6 +1506,12 @@ Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt, } else { st = StoreNode::make(_gvn, ctl, mem, adr, adr_type, val, bt, mo); } + if (unaligned) { + st->as_Store()->set_unaligned_access(); + } + if (mismatched) { + st->as_Store()->set_mismatched_access(); + } st = _gvn.transform(st); set_memory(st, adr_idx); // Back-to-back stores can only remove intermediate store with DU info @@ -1587,7 +1605,8 @@ Node* GraphKit::store_oop(Node* ctl, const TypeOopPtr* val_type, BasicType bt, bool use_precise, - MemNode::MemOrd mo) { + MemNode::MemOrd mo, + bool mismatched) { // Transformation of a value which could be NULL pointer (CastPP #NULL) // could be delayed during Parse (for example, in adjust_map_after_if()). // Execute transformation here to avoid barrier generation in such case. @@ -1607,7 +1626,7 @@ Node* GraphKit::store_oop(Node* ctl, NULL /* pre_val */, bt); - Node* store = store_to_memory(control(), adr, val, bt, adr_idx, mo); + Node* store = store_to_memory(control(), adr, val, bt, adr_idx, mo, mismatched); post_barrier(control(), store, obj, adr, adr_idx, val, bt, use_precise); return store; } @@ -1619,7 +1638,8 @@ Node* GraphKit::store_oop_to_unknown(Node* ctl, const TypePtr* adr_type, Node* val, BasicType bt, - MemNode::MemOrd mo) { + MemNode::MemOrd mo, + bool mismatched) { Compile::AliasType* at = C->alias_type(adr_type); const TypeOopPtr* val_type = NULL; if (adr_type->isa_instptr()) { @@ -1638,7 +1658,7 @@ Node* GraphKit::store_oop_to_unknown(Node* ctl, if (val_type == NULL) { val_type = TypeInstPtr::BOTTOM; } - return store_oop(ctl, obj, adr, adr_type, val, val_type, bt, true, mo); + return store_oop(ctl, obj, adr, adr_type, val, val_type, bt, true, mo, mismatched); } diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp index a47047d64ae..4b4be335cd3 100644 --- a/hotspot/src/share/vm/opto/graphKit.hpp +++ b/hotspot/src/share/vm/opto/graphKit.hpp @@ -513,23 +513,28 @@ class GraphKit : public Phase { // of volatile fields. Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, - bool require_atomic_access = false) { + bool require_atomic_access = false, bool unaligned = false, + bool mismatched = false) { // This version computes alias_index from bottom_type return make_load(ctl, adr, t, bt, adr->bottom_type()->is_ptr(), - mo, control_dependency, require_atomic_access); + mo, control_dependency, require_atomic_access, + unaligned, mismatched); } Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, const TypePtr* adr_type, MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, - bool require_atomic_access = false) { + bool require_atomic_access = false, bool unaligned = false, + bool mismatched = false) { // This version computes alias_index from an address type assert(adr_type != NULL, "use other make_load factory"); return make_load(ctl, adr, t, bt, C->get_alias_index(adr_type), - mo, control_dependency, require_atomic_access); + mo, control_dependency, require_atomic_access, + unaligned, mismatched); } // This is the base version which is given an alias index. Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, int adr_idx, MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest, - bool require_atomic_access = false); + bool require_atomic_access = false, bool unaligned = false, + bool mismatched = false); // Create & transform a StoreNode and store the effect into the // parser's memory state. @@ -542,19 +547,24 @@ class GraphKit : public Phase { Node* store_to_memory(Node* ctl, Node* adr, Node* val, BasicType bt, const TypePtr* adr_type, MemNode::MemOrd mo, - bool require_atomic_access = false) { + bool require_atomic_access = false, + bool unaligned = false, + bool mismatched = false) { // This version computes alias_index from an address type assert(adr_type != NULL, "use other store_to_memory factory"); return store_to_memory(ctl, adr, val, bt, C->get_alias_index(adr_type), - mo, require_atomic_access); + mo, require_atomic_access, + unaligned, mismatched); } // This is the base version which is given alias index // Return the new StoreXNode Node* store_to_memory(Node* ctl, Node* adr, Node* val, BasicType bt, int adr_idx, MemNode::MemOrd, - bool require_atomic_access = false); + bool require_atomic_access = false, + bool unaligned = false, + bool mismatched = false); // All in one pre-barrier, store, post_barrier @@ -577,7 +587,8 @@ class GraphKit : public Phase { const TypeOopPtr* val_type, BasicType bt, bool use_precise, - MemNode::MemOrd mo); + MemNode::MemOrd mo, + bool mismatched = false); Node* store_oop_to_object(Node* ctl, Node* obj, // containing obj @@ -608,7 +619,8 @@ class GraphKit : public Phase { const TypePtr* adr_type, Node* val, BasicType bt, - MemNode::MemOrd mo); + MemNode::MemOrd mo, + bool mismatched = false); // For the few case where the barriers need special help void pre_barrier(bool do_load, Node* ctl, diff --git a/hotspot/src/share/vm/opto/idealKit.cpp b/hotspot/src/share/vm/opto/idealKit.cpp index cbba57eba95..94d7ef4033c 100644 --- a/hotspot/src/share/vm/opto/idealKit.cpp +++ b/hotspot/src/share/vm/opto/idealKit.cpp @@ -368,7 +368,8 @@ Node* IdealKit::load(Node* ctl, Node* IdealKit::store(Node* ctl, Node* adr, Node *val, BasicType bt, int adr_idx, - MemNode::MemOrd mo, bool require_atomic_access) { + MemNode::MemOrd mo, bool require_atomic_access, + bool mismatched) { assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory"); const TypePtr* adr_type = NULL; debug_only(adr_type = C->get_adr_type(adr_idx)); @@ -379,6 +380,9 @@ Node* IdealKit::store(Node* ctl, Node* adr, Node *val, BasicType bt, } else { st = StoreNode::make(_gvn, ctl, mem, adr, adr_type, val, bt, mo); } + if (mismatched) { + st->as_Store()->set_mismatched_access(); + } st = transform(st); set_memory(st, adr_idx); diff --git a/hotspot/src/share/vm/opto/idealKit.hpp b/hotspot/src/share/vm/opto/idealKit.hpp index 73db4771509..79e1c7f81c6 100644 --- a/hotspot/src/share/vm/opto/idealKit.hpp +++ b/hotspot/src/share/vm/opto/idealKit.hpp @@ -229,7 +229,9 @@ class IdealKit: public StackObj { BasicType bt, int adr_idx, MemNode::MemOrd mo, - bool require_atomic_access = false); + bool require_atomic_access = false, + bool mismatched = false + ); // Store a card mark ordered after store_oop Node* storeCM(Node* ctl, diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 50dc1d93843..ffec41c9ff7 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -238,7 +238,7 @@ class LibraryCallKit : public GraphKit { // Generates the guards that check whether the result of // Unsafe.getObject should be recorded in an SATB log buffer. void insert_pre_barrier(Node* base_oop, Node* offset, Node* pre_val, bool need_mem_bar); - bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile); + bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool is_unaligned); static bool klass_needs_init_guard(Node* kls); bool inline_unsafe_allocate(); bool inline_unsafe_copyMemory(); @@ -544,72 +544,72 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_inflateStringC: case vmIntrinsics::_inflateStringB: return inline_string_copy(!is_compress); - case vmIntrinsics::_getObject: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, !is_volatile); - case vmIntrinsics::_getBoolean: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, !is_volatile); - case vmIntrinsics::_getByte: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, !is_volatile); - case vmIntrinsics::_getShort: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, !is_volatile); - case vmIntrinsics::_getChar: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, !is_volatile); - case vmIntrinsics::_getInt: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, !is_volatile); - case vmIntrinsics::_getLong: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile); - case vmIntrinsics::_getFloat: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, !is_volatile); - case vmIntrinsics::_getDouble: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, !is_volatile); - case vmIntrinsics::_putObject: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, !is_volatile); - case vmIntrinsics::_putBoolean: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, !is_volatile); - case vmIntrinsics::_putByte: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, !is_volatile); - case vmIntrinsics::_putShort: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, !is_volatile); - case vmIntrinsics::_putChar: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, !is_volatile); - case vmIntrinsics::_putInt: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, !is_volatile); - case vmIntrinsics::_putLong: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, !is_volatile); - case vmIntrinsics::_putFloat: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, !is_volatile); - case vmIntrinsics::_putDouble: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, !is_volatile); + case vmIntrinsics::_getObject: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, !is_volatile, false); + case vmIntrinsics::_getBoolean: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, !is_volatile, false); + case vmIntrinsics::_getByte: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, !is_volatile, false); + case vmIntrinsics::_getShort: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, !is_volatile, false); + case vmIntrinsics::_getChar: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, !is_volatile, false); + case vmIntrinsics::_getInt: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, !is_volatile, false); + case vmIntrinsics::_getLong: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile, false); + case vmIntrinsics::_getFloat: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, !is_volatile, false); + case vmIntrinsics::_getDouble: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, !is_volatile, false); + case vmIntrinsics::_putObject: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, !is_volatile, false); + case vmIntrinsics::_putBoolean: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, !is_volatile, false); + case vmIntrinsics::_putByte: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, !is_volatile, false); + case vmIntrinsics::_putShort: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, !is_volatile, false); + case vmIntrinsics::_putChar: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, !is_volatile, false); + case vmIntrinsics::_putInt: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, !is_volatile, false); + case vmIntrinsics::_putLong: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, !is_volatile, false); + case vmIntrinsics::_putFloat: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, !is_volatile, false); + case vmIntrinsics::_putDouble: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, !is_volatile, false); - case vmIntrinsics::_getByte_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_BYTE, !is_volatile); - case vmIntrinsics::_getShort_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_SHORT, !is_volatile); - case vmIntrinsics::_getChar_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_CHAR, !is_volatile); - case vmIntrinsics::_getInt_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_INT, !is_volatile); - case vmIntrinsics::_getLong_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_LONG, !is_volatile); - case vmIntrinsics::_getFloat_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_FLOAT, !is_volatile); - case vmIntrinsics::_getDouble_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_DOUBLE, !is_volatile); - case vmIntrinsics::_getAddress_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_ADDRESS, !is_volatile); + case vmIntrinsics::_getByte_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_BYTE, !is_volatile, false); + case vmIntrinsics::_getShort_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_SHORT, !is_volatile, false); + case vmIntrinsics::_getChar_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_CHAR, !is_volatile, false); + case vmIntrinsics::_getInt_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_INT, !is_volatile, false); + case vmIntrinsics::_getLong_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_LONG, !is_volatile, false); + case vmIntrinsics::_getFloat_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_FLOAT, !is_volatile, false); + case vmIntrinsics::_getDouble_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_DOUBLE, !is_volatile, false); + case vmIntrinsics::_getAddress_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_ADDRESS, !is_volatile, false); - case vmIntrinsics::_putByte_raw: return inline_unsafe_access( is_native_ptr, is_store, T_BYTE, !is_volatile); - case vmIntrinsics::_putShort_raw: return inline_unsafe_access( is_native_ptr, is_store, T_SHORT, !is_volatile); - case vmIntrinsics::_putChar_raw: return inline_unsafe_access( is_native_ptr, is_store, T_CHAR, !is_volatile); - case vmIntrinsics::_putInt_raw: return inline_unsafe_access( is_native_ptr, is_store, T_INT, !is_volatile); - case vmIntrinsics::_putLong_raw: return inline_unsafe_access( is_native_ptr, is_store, T_LONG, !is_volatile); - case vmIntrinsics::_putFloat_raw: return inline_unsafe_access( is_native_ptr, is_store, T_FLOAT, !is_volatile); - case vmIntrinsics::_putDouble_raw: return inline_unsafe_access( is_native_ptr, is_store, T_DOUBLE, !is_volatile); - case vmIntrinsics::_putAddress_raw: return inline_unsafe_access( is_native_ptr, is_store, T_ADDRESS, !is_volatile); + case vmIntrinsics::_putByte_raw: return inline_unsafe_access( is_native_ptr, is_store, T_BYTE, !is_volatile, false); + case vmIntrinsics::_putShort_raw: return inline_unsafe_access( is_native_ptr, is_store, T_SHORT, !is_volatile, false); + case vmIntrinsics::_putChar_raw: return inline_unsafe_access( is_native_ptr, is_store, T_CHAR, !is_volatile, false); + case vmIntrinsics::_putInt_raw: return inline_unsafe_access( is_native_ptr, is_store, T_INT, !is_volatile, false); + case vmIntrinsics::_putLong_raw: return inline_unsafe_access( is_native_ptr, is_store, T_LONG, !is_volatile, false); + case vmIntrinsics::_putFloat_raw: return inline_unsafe_access( is_native_ptr, is_store, T_FLOAT, !is_volatile, false); + case vmIntrinsics::_putDouble_raw: return inline_unsafe_access( is_native_ptr, is_store, T_DOUBLE, !is_volatile, false); + case vmIntrinsics::_putAddress_raw: return inline_unsafe_access( is_native_ptr, is_store, T_ADDRESS, !is_volatile, false); - case vmIntrinsics::_getObjectVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, is_volatile); - case vmIntrinsics::_getBooleanVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, is_volatile); - case vmIntrinsics::_getByteVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, is_volatile); - case vmIntrinsics::_getShortVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, is_volatile); - case vmIntrinsics::_getCharVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, is_volatile); - case vmIntrinsics::_getIntVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, is_volatile); - case vmIntrinsics::_getLongVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, is_volatile); - case vmIntrinsics::_getFloatVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, is_volatile); - case vmIntrinsics::_getDoubleVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, is_volatile); + case vmIntrinsics::_getObjectVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, is_volatile, false); + case vmIntrinsics::_getBooleanVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, is_volatile, false); + case vmIntrinsics::_getByteVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, is_volatile, false); + case vmIntrinsics::_getShortVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, is_volatile, false); + case vmIntrinsics::_getCharVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, is_volatile, false); + case vmIntrinsics::_getIntVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, is_volatile, false); + case vmIntrinsics::_getLongVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, is_volatile, false); + case vmIntrinsics::_getFloatVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, is_volatile, false); + case vmIntrinsics::_getDoubleVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, is_volatile, false); - case vmIntrinsics::_putObjectVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, is_volatile); - case vmIntrinsics::_putBooleanVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, is_volatile); - case vmIntrinsics::_putByteVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, is_volatile); - case vmIntrinsics::_putShortVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, is_volatile); - case vmIntrinsics::_putCharVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, is_volatile); - case vmIntrinsics::_putIntVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, is_volatile); - case vmIntrinsics::_putLongVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, is_volatile); - case vmIntrinsics::_putFloatVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, is_volatile); - case vmIntrinsics::_putDoubleVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, is_volatile); + case vmIntrinsics::_putObjectVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, is_volatile, false); + case vmIntrinsics::_putBooleanVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, is_volatile, false); + case vmIntrinsics::_putByteVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, is_volatile, false); + case vmIntrinsics::_putShortVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, is_volatile, false); + case vmIntrinsics::_putCharVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, is_volatile, false); + case vmIntrinsics::_putIntVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, is_volatile, false); + case vmIntrinsics::_putLongVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, is_volatile, false); + case vmIntrinsics::_putFloatVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, is_volatile, false); + case vmIntrinsics::_putDoubleVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, is_volatile, false); - case vmIntrinsics::_getShortUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, !is_volatile); - case vmIntrinsics::_getCharUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, !is_volatile); - case vmIntrinsics::_getIntUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, !is_volatile); - case vmIntrinsics::_getLongUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile); + case vmIntrinsics::_getShortUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, !is_volatile, true); + case vmIntrinsics::_getCharUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, !is_volatile, true); + case vmIntrinsics::_getIntUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, !is_volatile, true); + case vmIntrinsics::_getLongUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile, true); - case vmIntrinsics::_putShortUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, !is_volatile); - case vmIntrinsics::_putCharUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, !is_volatile); - case vmIntrinsics::_putIntUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, !is_volatile); - case vmIntrinsics::_putLongUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, !is_volatile); + case vmIntrinsics::_putShortUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, !is_volatile, true); + case vmIntrinsics::_putCharUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, !is_volatile, true); + case vmIntrinsics::_putIntUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, !is_volatile, true); + case vmIntrinsics::_putLongUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, !is_volatile, true); case vmIntrinsics::_compareAndSwapObject: return inline_unsafe_load_store(T_OBJECT, LS_cmpxchg); case vmIntrinsics::_compareAndSwapInt: return inline_unsafe_load_store(T_INT, LS_cmpxchg); @@ -2385,7 +2385,7 @@ const TypeOopPtr* LibraryCallKit::sharpen_unsafe_type(Compile::AliasType* alias_ return NULL; } -bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile) { +bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool unaligned) { if (callee()->is_static()) return false; // caller must have the capability! #ifndef PRODUCT @@ -2527,7 +2527,24 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas // of safe & unsafe memory. if (need_mem_bar) insert_mem_bar(Op_MemBarCPUOrder); - if (!is_store) { + assert(alias_type->adr_type() == TypeRawPtr::BOTTOM || alias_type->adr_type() == TypeOopPtr::BOTTOM || + alias_type->field() != NULL || alias_type->element() != NULL, "field, array element or unknown"); + bool mismatched = false; + if (alias_type->element() != NULL || alias_type->field() != NULL) { + BasicType bt; + if (alias_type->element() != NULL) { + const Type* element = alias_type->element(); + bt = element->isa_narrowoop() ? T_OBJECT : element->array_element_basic_type(); + } else { + bt = alias_type->field()->type()->basic_type(); + } + if (bt != type) { + mismatched = true; + } + } + assert(type != T_OBJECT || !unaligned, "unaligned access not supported with object type"); + + if (!is_store) { Node* p = NULL; // Try to constant fold a load from a constant field ciField* field = alias_type->field(); @@ -2543,7 +2560,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas MemNode::MemOrd mo = is_volatile ? MemNode::acquire : MemNode::unordered; // To be valid, unsafe loads may depend on other conditions than // the one that guards them: pin the Load node - p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, is_volatile); + p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, is_volatile, unaligned, mismatched); // load value switch (type) { case T_BOOLEAN: @@ -2590,12 +2607,12 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas MemNode::MemOrd mo = is_volatile ? MemNode::release : MemNode::unordered; if (type != T_OBJECT ) { - (void) store_to_memory(control(), adr, val, type, adr_type, mo, is_volatile); + (void) store_to_memory(control(), adr, val, type, adr_type, mo, is_volatile, unaligned, mismatched); } else { // Possibly an oop being stored to Java heap or native memory if (!TypePtr::NULL_PTR->higher_equal(_gvn.type(heap_base_oop))) { // oop to Java heap. - (void) store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type, mo); + (void) store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type, mo, mismatched); } else { // We can't tell at compile time if we are storing in the Java heap or outside // of it. So we need to emit code to conditionally do the proper type of @@ -2607,11 +2624,11 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas __ if_then(heap_base_oop, BoolTest::ne, null(), PROB_UNLIKELY(0.999)); { // Sync IdealKit and graphKit. sync_kit(ideal); - Node* st = store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type, mo); + Node* st = store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type, mo, mismatched); // Update IdealKit memory. __ sync_kit(this); } __ else_(); { - __ store(__ ctrl(), adr, val, type, alias_type->index(), mo, is_volatile); + __ store(__ ctrl(), adr, val, type, alias_type->index(), mo, is_volatile, mismatched); } __ end_if(); // Final sync IdealKit and GraphKit. final_sync(ideal); diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index d7da53ef871..863255dabdb 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -72,8 +72,15 @@ void MemNode::dump_spec(outputStream *st) const { dump_adr_type(this, _adr_type, st); Compile* C = Compile::current(); - if( C->alias_type(_adr_type)->is_volatile() ) + if (C->alias_type(_adr_type)->is_volatile()) { st->print(" Volatile!"); + } + if (_unaligned_access) { + st->print(" unaligned"); + } + if (_mismatched_access) { + st->print(" mismatched"); + } } void MemNode::dump_adr_type(const Node* mem, const TypePtr* adr_type, outputStream *st) { @@ -2393,7 +2400,8 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) { st->Opcode() == Op_StoreVector || Opcode() == Op_StoreVector || phase->C->get_alias_index(adr_type()) == Compile::AliasIdxRaw || - (Opcode() == Op_StoreL && st->Opcode() == Op_StoreI), // expanded ClearArrayNode + (Opcode() == Op_StoreL && st->Opcode() == Op_StoreI) || // expanded ClearArrayNode + (is_mismatched_access() || st->as_Store()->is_mismatched_access()), "no mismatched stores, except on raw memory: %s %s", NodeClassNames[Opcode()], NodeClassNames[st->Opcode()]); if (st->in(MemNode::Address)->eqv_uncast(address) && @@ -3213,6 +3221,9 @@ bool InitializeNode::detect_init_independence(Node* n, int& count) { // within the initialized memory. intptr_t InitializeNode::can_capture_store(StoreNode* st, PhaseTransform* phase, bool can_reshape) { const int FAIL = 0; + if (st->is_unaligned_access()) { + return FAIL; + } if (st->req() != MemNode::ValueIn + 1) return FAIL; // an inscrutable StoreNode (card mark?) Node* ctl = st->in(MemNode::Control); diff --git a/hotspot/src/share/vm/opto/memnode.hpp b/hotspot/src/share/vm/opto/memnode.hpp index 1abfede267b..f62ffad7da7 100644 --- a/hotspot/src/share/vm/opto/memnode.hpp +++ b/hotspot/src/share/vm/opto/memnode.hpp @@ -39,11 +39,14 @@ class PhaseTransform; //------------------------------MemNode---------------------------------------- // Load or Store, possibly throwing a NULL pointer exception class MemNode : public Node { +private: + bool _unaligned_access; // Unaligned access from unsafe + bool _mismatched_access; // Mismatched access from unsafe: byte read in integer array for instance protected: #ifdef ASSERT const TypePtr* _adr_type; // What kind of memory is being addressed? #endif - virtual uint size_of() const; // Size is bigger (ASSERT only) + virtual uint size_of() const; public: enum { Control, // When is it safe to do this load? Memory, // Chunk of memory is being loaded from @@ -57,17 +60,17 @@ public: } MemOrd; protected: MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at ) - : Node(c0,c1,c2 ) { + : Node(c0,c1,c2 ), _unaligned_access(false), _mismatched_access(false) { init_class_id(Class_Mem); debug_only(_adr_type=at; adr_type();) } MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at, Node *c3 ) - : Node(c0,c1,c2,c3) { + : Node(c0,c1,c2,c3), _unaligned_access(false), _mismatched_access(false) { init_class_id(Class_Mem); debug_only(_adr_type=at; adr_type();) } MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at, Node *c3, Node *c4) - : Node(c0,c1,c2,c3,c4) { + : Node(c0,c1,c2,c3,c4), _unaligned_access(false), _mismatched_access(false) { init_class_id(Class_Mem); debug_only(_adr_type=at; adr_type();) } @@ -127,6 +130,11 @@ public: // the given memory state? (The state may or may not be in(Memory).) Node* can_see_stored_value(Node* st, PhaseTransform* phase) const; + void set_unaligned_access() { _unaligned_access = true; } + bool is_unaligned_access() const { return _unaligned_access; } + void set_mismatched_access() { _mismatched_access = true; } + bool is_mismatched_access() const { return _mismatched_access; } + #ifndef PRODUCT static void dump_adr_type(const Node* mem, const TypePtr* adr_type, outputStream *st); virtual void dump_spec(outputStream *st) const; diff --git a/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeUnalignedMismatchedAccesses.java b/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeUnalignedMismatchedAccesses.java new file mode 100644 index 00000000000..464c13cba56 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeUnalignedMismatchedAccesses.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8136473 + * @summary Mismatched stores on same slice possible with Unsafe.Put*Unaligned methods + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation TestUnsafeUnalignedMismatchedAccesses + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+UnlockDiagnosticVMOptions -XX:-UseUnalignedAccesses TestUnsafeUnalignedMismatchedAccesses + * + */ + +import java.lang.reflect.*; +import sun.misc.Unsafe; + +public class TestUnsafeUnalignedMismatchedAccesses { + + private static final Unsafe UNSAFE; + + static { + try { + Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + UNSAFE = (Unsafe) unsafeField.get(null); + } + catch (Exception e) { + throw new AssertionError(e); + } + } + + static void test1(byte[] array) { + array[0] = 0; + UNSAFE.putIntUnaligned(array, UNSAFE.ARRAY_BYTE_BASE_OFFSET, 0); + array[0] = 0; + } + + static void test2(byte[] array) { + array[0] = 0; + UNSAFE.putIntUnaligned(array, UNSAFE.ARRAY_BYTE_BASE_OFFSET+1, 0); + array[0] = 0; + } + + static void test3(byte[] array) { + array[0] = 0; + UNSAFE.putIntUnaligned(array, UNSAFE.ARRAY_BYTE_BASE_OFFSET+2, 0); + array[0] = 0; + } + + static void test4(byte[] array) { + array[0] = 0; + UNSAFE.putIntUnaligned(array, UNSAFE.ARRAY_BYTE_BASE_OFFSET+3, 0); + array[0] = 0; + } + + static void test5(byte[] array) { + array[0] = 0; + UNSAFE.putInt(array, UNSAFE.ARRAY_BYTE_BASE_OFFSET, 0); + array[0] = 0; + } + + // unaligned access and non escaping allocation + static void test6() { + byte[] array = new byte[10]; + UNSAFE.putIntUnaligned(array, UNSAFE.ARRAY_BYTE_BASE_OFFSET+1, -1); + array[0] = 0; + } + + // unaligned access and non escaping allocation + static int test7() { + byte[] array = new byte[10]; + UNSAFE.putIntUnaligned(array, UNSAFE.ARRAY_BYTE_BASE_OFFSET+1, -1); + array[0] = 0; + array[2] = 0; + return array[0] + array[1] + array[2] + array[3] + array[4]; + } + + // unaligned access with vectorization + static void test8(int[] src1, int[] src2, int[] dst) { + for (int i = 0; i < dst.length-1; i++) { + int res = src1[i] + src2[i]; + UNSAFE.putIntUnaligned(dst, UNSAFE.ARRAY_INT_BASE_OFFSET + i*4+1, res); + } + } + + static public void main(String[] args) throws Exception { + byte[] byte_array = new byte[100]; + int[] int_array = new int[100]; + Object[] obj_array = new Object[100]; + TestUnsafeUnalignedMismatchedAccesses test = new TestUnsafeUnalignedMismatchedAccesses(); + for (int i = 0; i < 20000; i++) { + test1(byte_array); + test2(byte_array); + test3(byte_array); + test4(byte_array); + test5(byte_array); + test6(); + test7(); + test8(int_array, int_array, int_array); + } + } +} From 0092880b1fc5393a19f6334b6551cc223a6b0986 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Thu, 5 Nov 2015 12:37:03 +0100 Subject: [PATCH 009/260] 8141424: [Testbug] CompilerDirectivesDCMDTest.java testing flag that is missing in product builds Test a flag that is in all builds instead Reviewed-by: roland --- hotspot/test/serviceability/dcmd/compiler/control2.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/test/serviceability/dcmd/compiler/control2.txt b/hotspot/test/serviceability/dcmd/compiler/control2.txt index 03a32cf91e9..805ce3a5ab0 100644 --- a/hotspot/test/serviceability/dcmd/compiler/control2.txt +++ b/hotspot/test/serviceability/dcmd/compiler/control2.txt @@ -11,7 +11,7 @@ }, inline : [ "+javax/util.*", "-comx/sun.*"], PrintAssembly: false, - IGVPrintLevel: 2 + MaxNodeLimit: 80001 }, { match: ["baz.*","frob.*"], From af2e00ae909cee9abbe0b8a157d1c22a40cd1e40 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Fri, 6 Nov 2015 09:36:47 +0100 Subject: [PATCH 010/260] 8140574: C2 must re-execute checks after deoptimizing from merged uncommon traps Before merging uncommon traps we have to check for proper bci domination and compatible JVMStates to guarantee correct re-execution of the checks. Reviewed-by: kvn, roland --- hotspot/src/share/vm/ci/ciTypeFlow.cpp | 92 +++++++++++++++- hotspot/src/share/vm/ci/ciTypeFlow.hpp | 10 ++ hotspot/src/share/vm/opto/ifnode.cpp | 35 +++++- .../rangechecks/TestUncommonTrapMerging.java | 100 ++++++++++++++++++ 4 files changed, 234 insertions(+), 3 deletions(-) create mode 100644 hotspot/test/compiler/rangechecks/TestUncommonTrapMerging.java diff --git a/hotspot/src/share/vm/ci/ciTypeFlow.cpp b/hotspot/src/share/vm/ci/ciTypeFlow.cpp index 8a5ad392bed..a1675d17a14 100644 --- a/hotspot/src/share/vm/ci/ciTypeFlow.cpp +++ b/hotspot/src/share/vm/ci/ciTypeFlow.cpp @@ -1588,6 +1588,7 @@ ciTypeFlow::Block::Block(ciTypeFlow* outer, _exceptions = NULL; _exc_klasses = NULL; _successors = NULL; + _predecessors = new (outer->arena()) GrowableArray(outer->arena(), 1, 0, NULL); _state = new (outer->arena()) StateVector(outer); JsrSet* new_jsrs = new (outer->arena()) JsrSet(outer->arena(), jsrs->size()); @@ -1771,6 +1772,12 @@ ciTypeFlow::Block::successors(ciBytecodeStream* str, break; } } + + // Set predecessor information + for (int i = 0; i < _successors->length(); i++) { + Block* block = _successors->at(i); + block->predecessors()->append(this); + } } return _successors; } @@ -1813,7 +1820,9 @@ void ciTypeFlow::Block::compute_exceptions() { } else { klass = handler->catch_klass(); } - _exceptions->append(analyzer->block_at(bci, _jsrs)); + Block* block = analyzer->block_at(bci, _jsrs); + _exceptions->append(block); + block->predecessors()->append(this); _exc_klasses->append(klass); } } @@ -1909,6 +1918,18 @@ void ciTypeFlow::Block::print_on(outputStream* st) const { st->cr(); } } + if (_predecessors == NULL) { + st->print_cr(" No predecessor information"); + } else { + int num_predecessors = _predecessors->length(); + st->print_cr(" Predecessors : %d", num_predecessors); + for (int i = 0; i < num_predecessors; i++) { + Block* predecessor = _predecessors->at(i); + st->print(" "); + predecessor->print_value_on(st); + st->cr(); + } + } if (_exceptions == NULL) { st->print_cr(" No exception information"); } else { @@ -2270,6 +2291,9 @@ ciTypeFlow::Block* ciTypeFlow::clone_loop_head(Loop* lp, StateVector* temp_vecto for (SuccIter iter(tail); !iter.done(); iter.next()) { if (iter.succ() == head) { iter.set_succ(clone); + // Update predecessor information + head->predecessors()->remove(tail); + clone->predecessors()->append(tail); } } flow_block(tail, temp_vector, temp_set); @@ -2279,6 +2303,9 @@ ciTypeFlow::Block* ciTypeFlow::clone_loop_head(Loop* lp, StateVector* temp_vecto for (SuccIter iter(clone); !iter.done(); iter.next()) { if (iter.succ() == head) { iter.set_succ(clone); + // Update predecessor information + head->predecessors()->remove(clone); + clone->predecessors()->append(clone); break; } } @@ -2883,6 +2910,69 @@ void ciTypeFlow::do_flow() { } } +// ------------------------------------------------------------------ +// ciTypeFlow::is_dominated_by +// +// Determine if the instruction at bci is dominated by the instruction at dom_bci. +bool ciTypeFlow::is_dominated_by(int bci, int dom_bci) { + assert(!method()->has_jsrs(), "jsrs are not supported"); + + ResourceMark rm; + JsrSet* jsrs = new ciTypeFlow::JsrSet(NULL); + int index = _methodBlocks->block_containing(bci)->index(); + int dom_index = _methodBlocks->block_containing(dom_bci)->index(); + Block* block = get_block_for(index, jsrs, ciTypeFlow::no_create); + Block* dom_block = get_block_for(dom_index, jsrs, ciTypeFlow::no_create); + + // Start block dominates all other blocks + if (start_block()->rpo() == dom_block->rpo()) { + return true; + } + + // Dominated[i] is true if block i is dominated by dom_block + int num_blocks = _methodBlocks->num_blocks(); + bool* dominated = NEW_RESOURCE_ARRAY(bool, num_blocks); + for (int i = 0; i < num_blocks; ++i) { + dominated[i] = true; + } + dominated[start_block()->rpo()] = false; + + // Iterative dominator algorithm + bool changed = true; + while (changed) { + changed = false; + // Use reverse postorder iteration + for (Block* blk = _rpo_list; blk != NULL; blk = blk->rpo_next()) { + if (blk->is_start()) { + // Ignore start block + continue; + } + // The block is dominated if it is the dominating block + // itself or if all predecessors are dominated. + int index = blk->rpo(); + bool dom = (index == dom_block->rpo()); + if (!dom) { + // Check if all predecessors are dominated + dom = true; + for (int i = 0; i < blk->predecessors()->length(); ++i) { + Block* pred = blk->predecessors()->at(i); + if (!dominated[pred->rpo()]) { + dom = false; + break; + } + } + } + // Update dominator information + if (dominated[index] != dom) { + changed = true; + dominated[index] = dom; + } + } + } + // block dominated by dom_block? + return dominated[block->rpo()]; +} + // ------------------------------------------------------------------ // ciTypeFlow::record_failure() // The ciTypeFlow object keeps track of failure reasons separately from the ciEnv. diff --git a/hotspot/src/share/vm/ci/ciTypeFlow.hpp b/hotspot/src/share/vm/ci/ciTypeFlow.hpp index 012ffb05ed0..381fff86a14 100644 --- a/hotspot/src/share/vm/ci/ciTypeFlow.hpp +++ b/hotspot/src/share/vm/ci/ciTypeFlow.hpp @@ -529,6 +529,7 @@ public: GrowableArray* _exceptions; GrowableArray* _exc_klasses; GrowableArray* _successors; + GrowableArray* _predecessors; StateVector* _state; JsrSet* _jsrs; @@ -617,6 +618,12 @@ public: return _successors; } + // Predecessors of this block (including exception edges) + GrowableArray* predecessors() { + assert(_predecessors != NULL, "must be filled in"); + return _predecessors; + } + // Get the exceptional successors for this Block. GrowableArray* exceptions() { if (_exceptions == NULL) { @@ -941,6 +948,9 @@ public: // Perform type inference flow analysis. void do_flow(); + // Determine if bci is dominated by dom_bci + bool is_dominated_by(int bci, int dom_bci); + void print_on(outputStream* st) const PRODUCT_RETURN; void rpo_print_on(outputStream* st) const PRODUCT_RETURN; diff --git a/hotspot/src/share/vm/opto/ifnode.cpp b/hotspot/src/share/vm/opto/ifnode.cpp index 5d22abd6729..e560e6533e7 100644 --- a/hotspot/src/share/vm/opto/ifnode.cpp +++ b/hotspot/src/share/vm/opto/ifnode.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "ci/ciTypeFlow.hpp" #include "memory/allocation.inline.hpp" #include "opto/addnode.hpp" #include "opto/castnode.hpp" @@ -771,6 +772,11 @@ bool IfNode::has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNod CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(Deoptimization::Reason_none); if (otherproj->outcnt() == 1 && dom_unc != NULL) { + // We need to re-execute the folded Ifs after deoptimization from the merged traps + if (!dom_unc->jvms()->should_reexecute()) { + return false; + } + CallStaticJavaNode* unc = NULL; ProjNode* unc_proj = uncommon_trap_proj(unc); if (unc_proj != NULL && unc_proj->outcnt() == 1) { @@ -784,12 +790,37 @@ bool IfNode::has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNod } else if (dom_unc->in(0) != otherproj || unc->in(0) != unc_proj) { 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->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; + } + // See merge_uncommon_traps: the reason of the uncommon trap // 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 - if (!igvn->C->too_many_traps(dom_unc->jvms()->method(), dom_unc->jvms()->bci(), Deoptimization::Reason_unstable_fused_if) && - !igvn->C->too_many_traps(dom_unc->jvms()->method(), dom_unc->jvms()->bci(), Deoptimization::Reason_range_check)) { + 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; fail = unc_proj->other_if_proj(); return true; diff --git a/hotspot/test/compiler/rangechecks/TestUncommonTrapMerging.java b/hotspot/test/compiler/rangechecks/TestUncommonTrapMerging.java new file mode 100644 index 00000000000..bbdda630811 --- /dev/null +++ b/hotspot/test/compiler/rangechecks/TestUncommonTrapMerging.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8140574 + * @summary Verify proper re-execution of checks after merging of uncommon traps + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileCommand=compileonly,TestUncommonTrapMerging::test* TestUncommonTrapMerging Test1 + * @run main/othervm -XX:CompileCommand=compileonly,TestUncommonTrapMerging::test* TestUncommonTrapMerging Test2 + */ +public class TestUncommonTrapMerging { + + public static void main(String[] args) throws Throwable { + if (args.length < 1) { + throw new RuntimeException("Not enough arguments!"); + } + TestUncommonTrapMerging mytest = new TestUncommonTrapMerging(); + String testcase = args[0]; + if (testcase.equals("Test1")) { + try { + // '42' should hit the 'arg > 0' check + mytest.test(42); + + } catch (OutOfMemoryError e) { + // expected + } + } else if (testcase.equals("Test2")) { + // Compile test2 with uncommon traps at path 1 and path 2 + for (int i = 0; i < 100_000; i++) { + mytest.test2(-1, 0); + } + + // Compile test3 which inlines test2 with uncommon traps at + // path 1 and path 2. Because test3 always passes 'value = 1', + // C2 will remove the 'value > 0' check and then merge the two + // uncommon traps. + for (int i = 0; i < 100_000; i++) { + mytest.test3(0); + } + + // This should return through path 2 + if (!mytest.test3(42)) { + throw new RuntimeException("test2 returned through wrong path!"); + } + } + } + + public void test(int arg) throws Throwable { + // The following two checks should not be merged if the + // uncommon trap of the dominating if has 'Reason_unloaded' + // because we need to re-execute both checks after deopt. + if (arg < 0) { + throw new RuntimeException("Should not reach here"); + } else if (arg > 0) { + throw new OutOfMemoryError(); + } + throw new RuntimeException("Should not reach here"); + } + + public boolean test2(int arg, int value) { + if (arg < 0) { + if (value > 0) { + // path 1 + return false; + } + } else if (arg > 0) { + // path 2 + return true; + } + // path 3 + return false; + } + + public boolean test3(int arg) { + int i; + for (i = 0; i < 1; ++i) { } + // i == 1 + return test2(arg, i); + } +} From 26f02e4686e6e4363639bac1cb30b140d53f7a43 Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Fri, 6 Nov 2015 10:06:51 -1000 Subject: [PATCH 011/260] 8139589: [JVMCI] throw exceptions in faulty code installation operations Reviewed-by: twisti --- .../aarch64/vm/jvmciCodeInstaller_aarch64.cpp | 14 +- .../src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp | 14 +- .../cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp | 38 +- .../src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp | 37 +- .../src/jdk/vm/ci/hotspot/CompilerToVM.java | 3 + .../src/share/vm/jvmci/jvmciCodeInstaller.cpp | 529 +++++++++++------- .../src/share/vm/jvmci/jvmciCodeInstaller.hpp | 56 +- .../src/share/vm/jvmci/jvmciCompilerToVM.cpp | 4 +- hotspot/src/share/vm/jvmci/jvmciRuntime.cpp | 10 +- hotspot/src/share/vm/jvmci/jvmciRuntime.hpp | 13 +- .../src/share/vm/jvmci/vmSymbols_jvmci.hpp | 1 + .../jvmci/errors/CodeInstallerTest.java | 85 +++ .../errors/TestInvalidCompilationResult.java | 241 ++++++++ .../jvmci/errors/TestInvalidDebugInfo.java | 212 +++++++ .../jvmci/errors/TestInvalidOopMap.java | 127 +++++ 15 files changed, 1084 insertions(+), 300 deletions(-) create mode 100644 hotspot/test/compiler/jvmci/errors/CodeInstallerTest.java create mode 100644 hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java create mode 100644 hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java create mode 100644 hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java diff --git a/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp index f68c3e854da..c96bf597d80 100644 --- a/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp @@ -29,16 +29,16 @@ #include "runtime/sharedRuntime.hpp" #include "vmreg_aarch64.inline.hpp" -jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS) { Unimplemented(); return 0; } -void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) { Unimplemented(); } -void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle& constant) { +void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) { Unimplemented(); } @@ -46,20 +46,20 @@ void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset Unimplemented(); } -void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS) { Unimplemented(); } -void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { +void CodeInstaller::pd_relocate_JavaMethod(Handle hotspot_method, jint pc_offset, TRAPS) { Unimplemented(); } -void CodeInstaller::pd_relocate_poll(address pc, jint mark) { +void CodeInstaller::pd_relocate_poll(address pc, jint mark, TRAPS) { Unimplemented(); } // convert JVMCI register indices (as used in oop maps) to HotSpot registers -VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, TRAPS) { return NULL; } diff --git a/hotspot/src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp b/hotspot/src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp index 13185cc36bf..e5d4a9b0e51 100644 --- a/hotspot/src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp @@ -29,16 +29,16 @@ #include "runtime/sharedRuntime.hpp" #include "vmreg_ppc.inline.hpp" -jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS) { Unimplemented(); return 0; } -void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) { Unimplemented(); } -void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle& constant) { +void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) { Unimplemented(); } @@ -46,20 +46,20 @@ void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset Unimplemented(); } -void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS) { Unimplemented(); } -void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { +void CodeInstaller::pd_relocate_JavaMethod(Handle hotspot_method, jint pc_offset, TRAPS) { Unimplemented(); } -void CodeInstaller::pd_relocate_poll(address pc, jint mark) { +void CodeInstaller::pd_relocate_poll(address pc, jint mark, TRAPS) { Unimplemented(); } // convert JVMCI register indices (as used in oop maps) to HotSpot registers -VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, TRAPS) { return NULL; } diff --git a/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp b/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp index 45b27ab0a78..c50844963d0 100644 --- a/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp @@ -29,7 +29,7 @@ #include "runtime/sharedRuntime.hpp" #include "vmreg_sparc.inline.hpp" -jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS) { if (inst->is_call() || inst->is_jump()) { return pc_offset + NativeCall::instruction_size; } else if (inst->is_call_reg()) { @@ -37,12 +37,12 @@ jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop } else if (inst->is_sethi()) { return pc_offset + NativeFarCall::instruction_size; } else { - fatal("unsupported type of instruction for call site"); + JVMCI_ERROR_0("unsupported type of instruction for call site"); return 0; } } -void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) { address pc = _instructions->start() + pc_offset; Handle obj = HotSpotObjectConstantImpl::object(constant); jobject value = JNIHandles::make_local(obj()); @@ -52,7 +52,7 @@ void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { RelocationHolder rspec = oop_Relocation::spec(oop_index); _instructions->relocate(pc, rspec, 1); #else - fatal("compressed oop on 32bit"); + JVMCI_ERROR("compressed oop on 32bit"); #endif } else { NativeMovConstReg* move = nativeMovConstReg_at(pc); @@ -66,20 +66,20 @@ void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { } } -void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle& constant) { +void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) { address pc = _instructions->start() + pc_offset; if (HotSpotMetaspaceConstantImpl::compressed(constant)) { #ifdef _LP64 NativeMovConstReg32* move = nativeMovConstReg32_at(pc); - narrowKlass narrowOop = record_narrow_metadata_reference(constant); + narrowKlass narrowOop = record_narrow_metadata_reference(constant, CHECK); move->set_data((intptr_t)narrowOop); TRACE_jvmci_3("relocating (narrow metaspace constant) at %p/%p", pc, narrowOop); #else - fatal("compressed Klass* on 32bit"); + JVMCI_ERROR("compressed Klass* on 32bit"); #endif } else { NativeMovConstReg* move = nativeMovConstReg_at(pc); - Metadata* reference = record_metadata_reference(constant); + Metadata* reference = record_metadata_reference(constant, CHECK); move->set_data((intptr_t)reference); TRACE_jvmci_3("relocating (metaspace constant) at %p/%p", pc, reference); } @@ -106,7 +106,7 @@ void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset } } -void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS) { address pc = (address) inst; if (inst->is_call()) { NativeCall* call = nativeCall_at(pc); @@ -117,17 +117,17 @@ void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong forei jump->set_jump_destination((address) foreign_call_destination); _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec()); } else { - fatal(err_msg("unknown call or jump instruction at " PTR_FORMAT, p2i(pc))); + JVMCI_ERROR("unknown call or jump instruction at " PTR_FORMAT, p2i(pc)); } TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst)); } -void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { +void CodeInstaller::pd_relocate_JavaMethod(Handle hotspot_method, jint pc_offset, TRAPS) { #ifdef ASSERT Method* method = NULL; // we need to check, this might also be an unresolved method if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) { - method = getMethodFromHotSpotMethod(hotspot_method); + method = getMethodFromHotSpotMethod(hotspot_method()); } #endif switch (_next_call_type) { @@ -156,33 +156,33 @@ void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { break; } default: - fatal("invalid _next_call_type value"); + JVMCI_ERROR("invalid _next_call_type value"); break; } } -void CodeInstaller::pd_relocate_poll(address pc, jint mark) { +void CodeInstaller::pd_relocate_poll(address pc, jint mark, TRAPS) { switch (mark) { case POLL_NEAR: - fatal("unimplemented"); + JVMCI_ERROR("unimplemented"); break; case POLL_FAR: _instructions->relocate(pc, relocInfo::poll_type); break; case POLL_RETURN_NEAR: - fatal("unimplemented"); + JVMCI_ERROR("unimplemented"); break; case POLL_RETURN_FAR: _instructions->relocate(pc, relocInfo::poll_return_type); break; default: - fatal("invalid mark value"); + JVMCI_ERROR("invalid mark value"); break; } } // convert JVMCI register indices (as used in oop maps) to HotSpot registers -VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, TRAPS) { // JVMCI Registers are numbered as follows: // 0..31: Thirty-two General Purpose registers (CPU Registers) // 32..63: Thirty-two single precision float registers @@ -199,7 +199,7 @@ VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { } else if(jvmci_reg < 112) { floatRegisterNumber = 4 * (jvmci_reg - 96); } else { - fatal("Unknown jvmci register"); + JVMCI_ERROR_NULL("invalid register number: %d", jvmci_reg); } return as_FloatRegister(floatRegisterNumber)->as_VMReg(); } diff --git a/hotspot/src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp b/hotspot/src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp index a7d5c62ef38..d70dbaccb73 100644 --- a/hotspot/src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp +++ b/hotspot/src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp @@ -36,7 +36,7 @@ #include "code/vmreg.hpp" #include "vmreg_x86.inline.hpp" -jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS) { if (inst->is_call() || inst->is_jump()) { assert(NativeCall::instruction_size == (int)NativeJump::instruction_size, "unexpected size"); return (pc_offset + NativeCall::instruction_size); @@ -53,18 +53,17 @@ jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop return (offset); } else if (inst->is_call_reg()) { // the inlined vtable stub contains a "call register" instruction - assert(method != NULL, "only valid for virtual calls"); + assert(method.not_null(), "only valid for virtual calls"); return (pc_offset + ((NativeCallReg *) inst)->next_instruction_offset()); } else if (inst->is_cond_jump()) { address pc = (address) (inst); return pc_offset + (jint) (Assembler::locate_next_instruction(pc) - pc); } else { - fatal("unsupported type of instruction for call site"); - return 0; + JVMCI_ERROR_0("unsupported type of instruction for call site"); } } -void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) { address pc = _instructions->start() + pc_offset; Handle obj = HotSpotObjectConstantImpl::object(constant); jobject value = JNIHandles::make_local(obj()); @@ -75,7 +74,7 @@ void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { _instructions->relocate(pc, oop_Relocation::spec(oop_index), Assembler::narrow_oop_operand); TRACE_jvmci_3("relocating (narrow oop constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(operand)); #else - fatal("compressed oop on 32bit"); + JVMCI_ERROR("compressed oop on 32bit"); #endif } else { address operand = Assembler::locate_operand(pc, Assembler::imm_operand); @@ -85,19 +84,19 @@ void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { } } -void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle& constant) { +void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) { address pc = _instructions->start() + pc_offset; if (HotSpotMetaspaceConstantImpl::compressed(constant)) { #ifdef _LP64 address operand = Assembler::locate_operand(pc, Assembler::narrow_oop_operand); - *((narrowKlass*) operand) = record_narrow_metadata_reference(constant); + *((narrowKlass*) operand) = record_narrow_metadata_reference(constant, CHECK); TRACE_jvmci_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(operand)); #else - fatal("compressed Klass* on 32bit"); + JVMCI_ERROR("compressed Klass* on 32bit"); #endif } else { address operand = Assembler::locate_operand(pc, Assembler::imm_operand); - *((Metadata**) operand) = record_metadata_reference(constant); + *((Metadata**) operand) = record_metadata_reference(constant, CHECK); TRACE_jvmci_3("relocating (metaspace constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(operand)); } } @@ -117,7 +116,7 @@ void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset TRACE_jvmci_3("relocating at " PTR_FORMAT "/" PTR_FORMAT " with destination at " PTR_FORMAT " (%d)", p2i(pc), p2i(operand), p2i(dest), data_offset); } -void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS) { address pc = (address) inst; if (inst->is_call()) { // NOTE: for call without a mov, the offset must fit a 32-bit immediate @@ -139,18 +138,18 @@ void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong forei *(jint*) disp += ((address) foreign_call_destination) - old_dest; _instructions->relocate(pc, runtime_call_Relocation::spec(), Assembler::call32_operand); } else { - fatal("unsupported relocation for foreign call"); + JVMCI_ERROR("unsupported relocation for foreign call"); } TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst)); } -void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { +void CodeInstaller::pd_relocate_JavaMethod(Handle hotspot_method, jint pc_offset, TRAPS) { #ifdef ASSERT Method* method = NULL; // we need to check, this might also be an unresolved method if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) { - method = getMethodFromHotSpotMethod(hotspot_method); + method = getMethodFromHotSpotMethod(hotspot_method()); } #endif switch (_next_call_type) { @@ -185,6 +184,7 @@ void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { break; } default: + JVMCI_ERROR("invalid _next_call_type value"); break; } } @@ -198,7 +198,7 @@ static void relocate_poll_near(address pc) { } -void CodeInstaller::pd_relocate_poll(address pc, jint mark) { +void CodeInstaller::pd_relocate_poll(address pc, jint mark, TRAPS) { switch (mark) { case POLL_NEAR: { relocate_poll_near(pc); @@ -222,13 +222,13 @@ void CodeInstaller::pd_relocate_poll(address pc, jint mark) { _instructions->relocate(pc, relocInfo::poll_return_type, Assembler::imm_operand); break; default: - fatal("invalid mark value"); + JVMCI_ERROR("invalid mark value: %d", mark); break; } } // convert JVMCI register indices (as used in oop maps) to HotSpot registers -VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, TRAPS) { if (jvmci_reg < RegisterImpl::number_of_registers) { return as_Register(jvmci_reg)->as_VMReg(); } else { @@ -236,8 +236,7 @@ VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { if (floatRegisterNumber < XMMRegisterImpl::number_of_registers) { return as_XMMRegister(floatRegisterNumber)->as_VMReg(); } - ShouldNotReachHere(); - return NULL; + JVMCI_ERROR_NULL("invalid register number: %d", jvmci_reg); } } diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java index 536c93af36e..4f4e7e4e9b9 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java @@ -32,6 +32,7 @@ import java.lang.reflect.Method; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.code.InvalidInstalledCodeException; import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.hotspotvmconfig.HotSpotVMField; import jdk.vm.ci.inittimer.InitTimer; import jdk.vm.ci.meta.JavaType; @@ -308,6 +309,8 @@ final class CompilerToVM { * {@link HotSpotVMConfig#codeInstallResultCodeTooLarge}, * {@link HotSpotVMConfig#codeInstallResultDependenciesFailed} or * {@link HotSpotVMConfig#codeInstallResultDependenciesInvalid}. + * @throws JVMCIError if there is something wrong with the compiled code or the associated + * metadata. */ native int installCode(TargetDescription target, HotSpotCompiledCode compiledCode, InstalledCode code, HotSpotSpeculationLog speculationLog); diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp index 3a46b2281fd..53d78754386 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp @@ -71,62 +71,97 @@ Method* getMethodFromHotSpotMethod(oop hotspot_method) { return CompilerToVM::asMethod(hotspot_method); } -VMReg getVMRegFromLocation(oop location, int total_frame_size) { - oop reg = code_Location::reg(location); +VMReg getVMRegFromLocation(Handle location, int total_frame_size, TRAPS) { + if (location.is_null()) { + THROW_NULL(vmSymbols::java_lang_NullPointerException()); + } + + Handle reg = code_Location::reg(location); jint offset = code_Location::offset(location); - if (reg != NULL) { + if (reg.not_null()) { // register jint number = code_Register::number(reg); - VMReg vmReg = CodeInstaller::get_hotspot_reg(number); - assert(offset % 4 == 0, "must be aligned"); - return vmReg->next(offset / 4); + VMReg vmReg = CodeInstaller::get_hotspot_reg(number, CHECK_NULL); + if (offset % 4 == 0) { + return vmReg->next(offset / 4); + } else { + JVMCI_ERROR_NULL("unaligned subregister offset %d in oop map", offset); + } } else { // stack slot - assert(offset % 4 == 0, "must be aligned"); - return VMRegImpl::stack2reg(offset / 4); + if (offset % 4 == 0) { + return VMRegImpl::stack2reg(offset / 4); + } else { + JVMCI_ERROR_NULL("unaligned stack offset %d in oop map", offset); + } } } // creates a HotSpot oop map out of the byte arrays provided by DebugInfo -OopMap* CodeInstaller::create_oop_map(oop debug_info) { - oop reference_map = DebugInfo::referenceMap(debug_info); +OopMap* CodeInstaller::create_oop_map(Handle debug_info, TRAPS) { + Handle reference_map = DebugInfo::referenceMap(debug_info); + if (reference_map.is_null()) { + THROW_NULL(vmSymbols::java_lang_NullPointerException()); + } + if (!reference_map->is_a(HotSpotReferenceMap::klass())) { + JVMCI_ERROR_NULL("unknown reference map: %s", reference_map->klass()->signature_name()); + } if (HotSpotReferenceMap::maxRegisterSize(reference_map) > 16) { _has_wide_vector = true; } OopMap* map = new OopMap(_total_frame_size, _parameter_count); - objArrayOop objects = HotSpotReferenceMap::objects(reference_map); - objArrayOop derivedBase = HotSpotReferenceMap::derivedBase(reference_map); - typeArrayOop sizeInBytes = HotSpotReferenceMap::sizeInBytes(reference_map); + objArrayHandle objects = HotSpotReferenceMap::objects(reference_map); + objArrayHandle derivedBase = HotSpotReferenceMap::derivedBase(reference_map); + typeArrayHandle sizeInBytes = HotSpotReferenceMap::sizeInBytes(reference_map); + if (objects.is_null() || derivedBase.is_null() || sizeInBytes.is_null()) { + THROW_NULL(vmSymbols::java_lang_NullPointerException()); + } + if (objects->length() != derivedBase->length() || objects->length() != sizeInBytes->length()) { + JVMCI_ERROR_NULL("arrays in reference map have different sizes: %d %d %d", objects->length(), derivedBase->length(), sizeInBytes->length()); + } for (int i = 0; i < objects->length(); i++) { - oop location = objects->obj_at(i); - oop baseLocation = derivedBase->obj_at(i); + Handle location = objects->obj_at(i); + Handle baseLocation = derivedBase->obj_at(i); int bytes = sizeInBytes->int_at(i); - VMReg vmReg = getVMRegFromLocation(location, _total_frame_size); - if (baseLocation != NULL) { + VMReg vmReg = getVMRegFromLocation(location, _total_frame_size, CHECK_NULL); + if (baseLocation.not_null()) { // derived oop - assert(bytes == 8, "derived oop can't be compressed"); - VMReg baseReg = getVMRegFromLocation(baseLocation, _total_frame_size); - map->set_derived_oop(vmReg, baseReg); +#ifdef _LP64 + if (bytes == 8) { +#else + if (bytes == 4) { +#endif + VMReg baseReg = getVMRegFromLocation(baseLocation, _total_frame_size, CHECK_NULL); + map->set_derived_oop(vmReg, baseReg); + } else { + JVMCI_ERROR_NULL("invalid derived oop size in ReferenceMap: %d", bytes); + } +#ifdef _LP64 } else if (bytes == 8) { // wide oop map->set_oop(vmReg); - } else { + } else if (bytes == 4) { // narrow oop - assert(bytes == 4, "wrong size"); map->set_narrowoop(vmReg); +#else + } else if (bytes == 4) { + map->set_oop(vmReg); +#endif + } else { + JVMCI_ERROR_NULL("invalid oop size in ReferenceMap: %d", bytes); } } - oop callee_save_info = (oop) DebugInfo::calleeSaveInfo(debug_info); - if (callee_save_info != NULL) { - objArrayOop registers = RegisterSaveLayout::registers(callee_save_info); - typeArrayOop slots = RegisterSaveLayout::slots(callee_save_info); + Handle callee_save_info = (oop) DebugInfo::calleeSaveInfo(debug_info); + if (callee_save_info.not_null()) { + objArrayHandle registers = RegisterSaveLayout::registers(callee_save_info); + typeArrayHandle slots = RegisterSaveLayout::slots(callee_save_info); for (jint i = 0; i < slots->length(); i++) { - oop jvmci_reg = registers->obj_at(i); + Handle jvmci_reg = registers->obj_at(i); jint jvmci_reg_number = code_Register::number(jvmci_reg); - VMReg hotspot_reg = CodeInstaller::get_hotspot_reg(jvmci_reg_number); + VMReg hotspot_reg = CodeInstaller::get_hotspot_reg(jvmci_reg_number, CHECK_NULL); // HotSpot stack slots are 4 bytes jint jvmci_slot = slots->int_at(i); jint hotspot_slot = jvmci_slot * VMRegImpl::slots_per_word; @@ -142,7 +177,7 @@ OopMap* CodeInstaller::create_oop_map(oop debug_info) { return map; } -Metadata* CodeInstaller::record_metadata_reference(Handle& constant) { +Metadata* CodeInstaller::record_metadata_reference(Handle constant, TRAPS) { oop obj = HotSpotMetaspaceConstantImpl::metaspaceObject(constant); if (obj->is_a(HotSpotResolvedObjectTypeImpl::klass())) { Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(obj)); @@ -157,16 +192,18 @@ Metadata* CodeInstaller::record_metadata_reference(Handle& constant) { TRACE_jvmci_3("metadata[%d of %d] = %s", index, _oop_recorder->metadata_count(), method->name()->as_C_string()); return method; } else { - fatal("unexpected metadata reference for constant of type %s", obj->klass()->name()->as_C_string()); - return NULL; + JVMCI_ERROR_NULL("unexpected metadata reference for constant of type %s", obj->klass()->signature_name()); } } #ifdef _LP64 -narrowKlass CodeInstaller::record_narrow_metadata_reference(Handle& constant) { +narrowKlass CodeInstaller::record_narrow_metadata_reference(Handle constant, TRAPS) { oop obj = HotSpotMetaspaceConstantImpl::metaspaceObject(constant); assert(HotSpotMetaspaceConstantImpl::compressed(constant), "unexpected uncompressed pointer"); - assert(obj->is_a(HotSpotResolvedObjectTypeImpl::klass()), "unexpected compressed pointer of type %s", obj->klass()->name()->as_C_string()); + + if (!obj->is_a(HotSpotResolvedObjectTypeImpl::klass())) { + JVMCI_ERROR_0("unexpected compressed pointer of type %s", obj->klass()->signature_name()); + } Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(obj)); int index = _oop_recorder->find_index(klass); @@ -175,9 +212,9 @@ narrowKlass CodeInstaller::record_narrow_metadata_reference(Handle& constant) { } #endif -Location::Type CodeInstaller::get_oop_type(oop value) { - oop lirKind = Value::lirKind(value); - oop platformKind = LIRKind::platformKind(lirKind); +Location::Type CodeInstaller::get_oop_type(Handle value) { + Handle lirKind = Value::lirKind(value); + Handle platformKind = LIRKind::platformKind(lirKind); assert(LIRKind::referenceMask(lirKind) == 1, "unexpected referenceMask"); if (platformKind == word_kind()) { @@ -187,24 +224,29 @@ Location::Type CodeInstaller::get_oop_type(oop value) { } } -ScopeValue* CodeInstaller::get_scope_value(oop value, BasicType type, GrowableArray* objects, ScopeValue* &second) { +ScopeValue* CodeInstaller::get_scope_value(Handle value, BasicType type, GrowableArray* objects, ScopeValue* &second, TRAPS) { second = NULL; - if (value == Value::ILLEGAL()) { - assert(type == T_ILLEGAL, "expected legal value"); + if (value.is_null()) { + THROW_NULL(vmSymbols::java_lang_NullPointerException()); + } else if (value == Value::ILLEGAL()) { + if (type != T_ILLEGAL) { + JVMCI_ERROR_NULL("unexpected illegal value, expected %s", basictype_to_str(type)); + } return _illegal_value; } else if (value->is_a(RegisterValue::klass())) { - oop reg = RegisterValue::reg(value); + Handle reg = RegisterValue::reg(value); jint number = code_Register::number(reg); - VMReg hotspotRegister = get_hotspot_reg(number); + VMReg hotspotRegister = get_hotspot_reg(number, CHECK_NULL); if (is_general_purpose_reg(hotspotRegister)) { Location::Type locationType; if (type == T_OBJECT) { locationType = get_oop_type(value); } else if (type == T_LONG) { locationType = Location::lng; - } else { - assert(type == T_INT || type == T_FLOAT || type == T_SHORT || type == T_CHAR || type == T_BYTE || type == T_BOOLEAN, "unexpected type in cpu register"); + } else if (type == T_INT || type == T_FLOAT || type == T_SHORT || type == T_CHAR || type == T_BYTE || type == T_BOOLEAN) { locationType = Location::int_in_long; + } else { + JVMCI_ERROR_NULL("unexpected type %s in cpu register", basictype_to_str(type)); } ScopeValue* value = new LocationValue(Location::new_reg_loc(locationType, hotspotRegister)); if (type == T_LONG) { @@ -212,13 +254,14 @@ ScopeValue* CodeInstaller::get_scope_value(oop value, BasicType type, GrowableAr } return value; } else { - assert(type == T_FLOAT || type == T_DOUBLE, "only float and double expected in xmm register"); Location::Type locationType; if (type == T_FLOAT) { // this seems weird, but the same value is used in c1_LinearScan locationType = Location::normal; - } else { + } else if (type == T_DOUBLE) { locationType = Location::dbl; + } else { + JVMCI_ERROR_NULL("unexpected type %s in floating point register", basictype_to_str(type)); } ScopeValue* value = new LocationValue(Location::new_reg_loc(locationType, hotspotRegister)); if (type == T_DOUBLE) { @@ -239,9 +282,10 @@ ScopeValue* CodeInstaller::get_scope_value(oop value, BasicType type, GrowableAr locationType = Location::lng; } else if (type == T_DOUBLE) { locationType = Location::dbl; - } else { - assert(type == T_INT || type == T_FLOAT || type == T_SHORT || type == T_CHAR || type == T_BYTE || type == T_BOOLEAN, "unexpected type in stack slot"); + } else if (type == T_INT || type == T_FLOAT || type == T_SHORT || type == T_CHAR || type == T_BYTE || type == T_BOOLEAN) { locationType = Location::normal; + } else { + JVMCI_ERROR_NULL("unexpected type %s in stack slot", basictype_to_str(type)); } ScopeValue* value = new LocationValue(Location::new_stk_loc(locationType, offset)); if (type == T_DOUBLE || type == T_LONG) { @@ -254,7 +298,10 @@ ScopeValue* CodeInstaller::get_scope_value(oop value, BasicType type, GrowableAr jlong prim = PrimitiveConstant::primitive(value); return new ConstantLongValue(prim); } else { - assert(type == JVMCIRuntime::kindToBasicType(JavaKind::typeChar(PrimitiveConstant::kind(value))), "primitive constant type doesn't match"); + BasicType constantType = JVMCIRuntime::kindToBasicType(PrimitiveConstant::kind(value), CHECK_NULL); + if (type != constantType) { + JVMCI_ERROR_NULL("primitive constant type doesn't match, expected %s but got %s", basictype_to_str(type), basictype_to_str(constantType)); + } if (type == T_INT || type == T_FLOAT) { jint prim = (jint)PrimitiveConstant::primitive(value); switch (prim) { @@ -264,53 +311,63 @@ ScopeValue* CodeInstaller::get_scope_value(oop value, BasicType type, GrowableAr case 2: return _int_2_scope_value; default: return new ConstantIntValue(prim); } - } else { - assert(type == T_LONG || type == T_DOUBLE, "unexpected primitive constant type"); + } else if (type == T_LONG || type == T_DOUBLE) { jlong prim = PrimitiveConstant::primitive(value); second = _int_1_scope_value; return new ConstantLongValue(prim); + } else { + JVMCI_ERROR_NULL("unexpected primitive constant type %s", basictype_to_str(type)); } } - } else { - assert(type == T_OBJECT, "unexpected object constant"); - if (value->is_a(NullConstant::klass()) || value->is_a(HotSpotCompressedNullConstant::klass())) { + } else if (value->is_a(NullConstant::klass()) || value->is_a(HotSpotCompressedNullConstant::klass())) { + if (type == T_OBJECT) { return _oop_null_scope_value; } else { - assert(value->is_a(HotSpotObjectConstantImpl::klass()), "unexpected constant type"); + JVMCI_ERROR_NULL("unexpected null constant, expected %s", basictype_to_str(type)); + } + } else if (value->is_a(HotSpotObjectConstantImpl::klass())) { + if (type == T_OBJECT) { oop obj = HotSpotObjectConstantImpl::object(value); - assert(obj != NULL, "null value must be in NullConstant"); + if (obj == NULL) { + JVMCI_ERROR_NULL("null value must be in NullConstant"); + } return new ConstantOopWriteValue(JNIHandles::make_local(obj)); + } else { + JVMCI_ERROR_NULL("unexpected object constant, expected %s", basictype_to_str(type)); } } } else if (value->is_a(VirtualObject::klass())) { - assert(type == T_OBJECT, "unexpected virtual object"); - int id = VirtualObject::id(value); - ScopeValue* object = objects->at(id); - assert(object != NULL, "missing value"); - return object; - } else { - value->klass()->print(); - value->print(); + if (type == T_OBJECT) { + int id = VirtualObject::id(value); + if (0 <= id && id < objects->length()) { + ScopeValue* object = objects->at(id); + if (object != NULL) { + return object; + } + } + JVMCI_ERROR_NULL("unknown virtual object id %d", id); + } else { + JVMCI_ERROR_NULL("unexpected virtual object, expected %s", basictype_to_str(type)); + } } - ShouldNotReachHere(); - return NULL; + + JVMCI_ERROR_NULL("unexpected value in scope: %s", value->klass()->signature_name()) } -void CodeInstaller::record_object_value(ObjectValue* sv, oop value, GrowableArray* objects) { - oop type = VirtualObject::type(value); +void CodeInstaller::record_object_value(ObjectValue* sv, Handle value, GrowableArray* objects, TRAPS) { + Handle type = VirtualObject::type(value); int id = VirtualObject::id(value); oop javaMirror = HotSpotResolvedObjectTypeImpl::javaClass(type); Klass* klass = java_lang_Class::as_Klass(javaMirror); bool isLongArray = klass == Universe::longArrayKlassObj(); - objArrayOop values = VirtualObject::values(value); - objArrayOop slotKinds = VirtualObject::slotKinds(value); + objArrayHandle values = VirtualObject::values(value); + objArrayHandle slotKinds = VirtualObject::slotKinds(value); for (jint i = 0; i < values->length(); i++) { ScopeValue* cur_second = NULL; - oop object = values->obj_at(i); - oop kind = slotKinds->obj_at(i); - BasicType type = JVMCIRuntime::kindToBasicType(JavaKind::typeChar(kind)); - ScopeValue* value = get_scope_value(object, type, objects, cur_second); + Handle object = values->obj_at(i); + BasicType type = JVMCIRuntime::kindToBasicType(slotKinds->obj_at(i), CHECK); + ScopeValue* value = get_scope_value(object, type, objects, cur_second, CHECK); if (isLongArray && cur_second == NULL) { // we're trying to put ints into a long array... this isn't really valid, but it's used for some optimizations. @@ -326,14 +383,19 @@ void CodeInstaller::record_object_value(ObjectValue* sv, oop value, GrowableArra } } -MonitorValue* CodeInstaller::get_monitor_value(oop value, GrowableArray* objects) { - guarantee(value->is_a(StackLockValue::klass()), "Monitors must be of type StackLockValue"); +MonitorValue* CodeInstaller::get_monitor_value(Handle value, GrowableArray* objects, TRAPS) { + if (value.is_null()) { + THROW_NULL(vmSymbols::java_lang_NullPointerException()); + } + if (!value->is_a(StackLockValue::klass())) { + JVMCI_ERROR_NULL("Monitors must be of type StackLockValue, got %s", value->klass()->signature_name()); + } ScopeValue* second = NULL; - ScopeValue* owner_value = get_scope_value(StackLockValue::owner(value), T_OBJECT, objects, second); + ScopeValue* owner_value = get_scope_value(StackLockValue::owner(value), T_OBJECT, objects, second, CHECK_NULL); assert(second == NULL, "monitor cannot occupy two stack slots"); - ScopeValue* lock_data_value = get_scope_value(StackLockValue::slot(value), T_LONG, objects, second); + ScopeValue* lock_data_value = get_scope_value(StackLockValue::slot(value), T_LONG, objects, second, CHECK_NULL); assert(second == lock_data_value, "monitor is LONG value that occupies two stack slots"); assert(lock_data_value->is_location(), "invalid monitor location"); Location lock_data_loc = ((LocationValue*)lock_data_value)->location(); @@ -346,7 +408,7 @@ MonitorValue* CodeInstaller::get_monitor_value(oop value, GrowableArrayis_Compiler_thread() ? thread->as_CompilerThread() : NULL; _oop_recorder = recorder; @@ -368,8 +430,7 @@ void CodeInstaller::initialize_dependencies(oop compiled_code, OopRecorder* reco } else if (assumption->klass() == Assumptions_CallSiteTargetValue::klass()) { assumption_CallSiteTargetValue(assumption); } else { - assumption->print(); - fatal("unexpected Assumption subclass"); + JVMCI_ERROR("unexpected Assumption subclass %s", assumption->klass()->signature_name()); } } } @@ -414,18 +475,19 @@ void RelocBuffer::ensure_size(size_t bytes) { _size = bytes; } -JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle& compiled_code, CodeMetadata& metadata) { +JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle& compiled_code, CodeMetadata& metadata, TRAPS) { CodeBuffer buffer("JVMCI Compiler CodeBuffer for Metadata"); jobject compiled_code_obj = JNIHandles::make_local(compiled_code()); - initialize_dependencies(JNIHandles::resolve(compiled_code_obj), NULL); + initialize_dependencies(JNIHandles::resolve(compiled_code_obj), NULL, CHECK_OK); // Get instructions and constants CodeSections early because we need it. _instructions = buffer.insts(); _constants = buffer.consts(); - initialize_fields(target(), JNIHandles::resolve(compiled_code_obj)); - if (!initialize_buffer(buffer)) { - return JVMCIEnv::code_too_large; + initialize_fields(target(), JNIHandles::resolve(compiled_code_obj), CHECK_OK); + JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, CHECK_OK); + if (result != JVMCIEnv::ok) { + return result; } process_exception_handlers(); @@ -446,18 +508,18 @@ JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle } // constructor used to create a method -JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Handle target, Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log) { +JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Handle target, Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log, TRAPS) { CodeBuffer buffer("JVMCI Compiler CodeBuffer"); jobject compiled_code_obj = JNIHandles::make_local(compiled_code()); OopRecorder* recorder = new OopRecorder(&_arena, true); - initialize_dependencies(JNIHandles::resolve(compiled_code_obj), recorder); + initialize_dependencies(JNIHandles::resolve(compiled_code_obj), recorder, CHECK_OK); // Get instructions and constants CodeSections early because we need it. _instructions = buffer.insts(); _constants = buffer.consts(); - initialize_fields(target(), JNIHandles::resolve(compiled_code_obj)); - JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer); + initialize_fields(target(), JNIHandles::resolve(compiled_code_obj), CHECK_OK); + JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, CHECK_OK); if (result != JVMCIEnv::ok) { return result; } @@ -500,7 +562,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Hand return result; } -void CodeInstaller::initialize_fields(oop target, oop compiled_code) { +void CodeInstaller::initialize_fields(oop target, oop compiled_code, TRAPS) { if (compiled_code->is_a(HotSpotCompiledNmethod::klass())) { Handle hotspotJavaMethod = HotSpotCompiledNmethod::method(compiled_code); methodHandle method = getMethodFromHotSpotMethod(hotspotJavaMethod()); @@ -521,7 +583,9 @@ void CodeInstaller::initialize_fields(oop target, oop compiled_code) { // Pre-calculate the constants section size. This is required for PC-relative addressing. _data_section_handle = JNIHandles::make_local(HotSpotCompiledCode::dataSection(compiled_code)); - guarantee(HotSpotCompiledCode::dataSectionAlignment(compiled_code) <= _constants->alignment(), "Alignment inside constants section is restricted by alignment of section begin"); + if ((_constants->alignment() % HotSpotCompiledCode::dataSectionAlignment(compiled_code)) != 0) { + JVMCI_ERROR("invalid data section alignment: %d", HotSpotCompiledCode::dataSectionAlignment(compiled_code)); + } _constants_size = data_section()->length(); _data_section_patches_handle = JNIHandles::make_local(HotSpotCompiledCode::dataSectionPatches(compiled_code)); @@ -538,16 +602,18 @@ void CodeInstaller::initialize_fields(oop target, oop compiled_code) { _word_kind_handle = JNIHandles::make_local(Architecture::wordKind(arch)); } -int CodeInstaller::estimate_stubs_size() { +int CodeInstaller::estimate_stubs_size(TRAPS) { // Estimate the number of static call stubs that might be emitted. int static_call_stubs = 0; objArrayOop sites = this->sites(); for (int i = 0; i < sites->length(); i++) { oop site = sites->obj_at(i); - if (site->is_a(CompilationResult_Mark::klass())) { + if (site != NULL && site->is_a(CompilationResult_Mark::klass())) { oop id_obj = CompilationResult_Mark::id(site); if (id_obj != NULL) { - assert(java_lang_boxing_object::is_instance(id_obj, T_INT), "Integer id expected"); + if (!java_lang_boxing_object::is_instance(id_obj, T_INT)) { + JVMCI_ERROR_0("expected Integer id, got %s", id_obj->klass()->signature_name()); + } jint id = id_obj->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT)); if (id == INVOKESTATIC || id == INVOKESPECIAL) { static_call_stubs++; @@ -559,7 +625,7 @@ int CodeInstaller::estimate_stubs_size() { } // perform data and call relocation on the CodeBuffer -JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer) { +JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer, TRAPS) { HandleMark hm; objArrayHandle sites = this->sites(); int locs_buffer_size = sites->length() * (relocInfo::length_limit + sizeof(relocInfo)); @@ -568,7 +634,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer) // stubs. Stubs have extra relocs but they are managed by the stub // section itself so they don't need to be accounted for in the // locs_buffer above. - int stubs_size = estimate_stubs_size(); + int stubs_size = estimate_stubs_size(CHECK_OK); int total_size = round_to(_code_size, buffer.insts()->alignment()) + round_to(_constants_size, buffer.consts()->alignment()) + round_to(stubs_size, buffer.stubs()->alignment()); if (total_size > JVMCINMethodSizeLimit) { @@ -600,19 +666,30 @@ JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer) for (int i = 0; i < data_section_patches()->length(); i++) { Handle patch = data_section_patches()->obj_at(i); + if (patch.is_null()) { + THROW_(vmSymbols::java_lang_NullPointerException(), JVMCIEnv::ok); + } Handle reference = CompilationResult_DataPatch::reference(patch); - assert(reference->is_a(CompilationResult_ConstantReference::klass()), "patch in data section must be a ConstantReference"); + if (reference.is_null()) { + THROW_(vmSymbols::java_lang_NullPointerException(), JVMCIEnv::ok); + } + if (!reference->is_a(CompilationResult_ConstantReference::klass())) { + JVMCI_ERROR_OK("invalid patch in data section: %s", reference->klass()->signature_name()); + } Handle constant = CompilationResult_ConstantReference::constant(reference); + if (constant.is_null()) { + THROW_(vmSymbols::java_lang_NullPointerException(), JVMCIEnv::ok); + } address dest = _constants->start() + CompilationResult_Site::pcOffset(patch); if (constant->is_a(HotSpotMetaspaceConstantImpl::klass())) { if (HotSpotMetaspaceConstantImpl::compressed(constant)) { #ifdef _LP64 - *((narrowKlass*) dest) = record_narrow_metadata_reference(constant); + *((narrowKlass*) dest) = record_narrow_metadata_reference(constant, CHECK_OK); #else - fatal("unexpected compressed Klass* in 32-bit mode"); + JVMCI_ERROR_OK("unexpected compressed Klass* in 32-bit mode"); #endif } else { - *((Metadata**) dest) = record_metadata_reference(constant); + *((Metadata**) dest) = record_metadata_reference(constant, CHECK_OK); } } else if (constant->is_a(HotSpotObjectConstantImpl::klass())) { Handle obj = HotSpotObjectConstantImpl::object(constant); @@ -623,48 +700,49 @@ JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer) #ifdef _LP64 _constants->relocate(dest, oop_Relocation::spec(oop_index), relocInfo::narrow_oop_in_const); #else - fatal("unexpected compressed oop in 32-bit mode"); + JVMCI_ERROR_OK("unexpected compressed oop in 32-bit mode"); #endif } else { _constants->relocate(dest, oop_Relocation::spec(oop_index)); } } else { - ShouldNotReachHere(); + JVMCI_ERROR_OK("invalid constant in data section: %s", constant->klass()->signature_name()); } } jint last_pc_offset = -1; for (int i = 0; i < sites->length(); i++) { - { - No_Safepoint_Verifier no_safepoint; - oop site = sites->obj_at(i); - jint pc_offset = CompilationResult_Site::pcOffset(site); - - if (site->is_a(CompilationResult_Call::klass())) { - TRACE_jvmci_4("call at %i", pc_offset); - site_Call(buffer, pc_offset, site); - } else if (site->is_a(CompilationResult_Infopoint::klass())) { - // three reasons for infopoints denote actual safepoints - oop reason = CompilationResult_Infopoint::reason(site); - if (InfopointReason::SAFEPOINT() == reason || InfopointReason::CALL() == reason || InfopointReason::IMPLICIT_EXCEPTION() == reason) { - TRACE_jvmci_4("safepoint at %i", pc_offset); - site_Safepoint(buffer, pc_offset, site); - } else { - // if the infopoint is not an actual safepoint, it must have one of the other reasons - // (safeguard against new safepoint types that require handling above) - assert(InfopointReason::METHOD_START() == reason || InfopointReason::METHOD_END() == reason || InfopointReason::LINE_NUMBER() == reason, ""); - site_Infopoint(buffer, pc_offset, site); - } - } else if (site->is_a(CompilationResult_DataPatch::klass())) { - TRACE_jvmci_4("datapatch at %i", pc_offset); - site_DataPatch(buffer, pc_offset, site); - } else if (site->is_a(CompilationResult_Mark::klass())) { - TRACE_jvmci_4("mark at %i", pc_offset); - site_Mark(buffer, pc_offset, site); - } else { - fatal("unexpected Site subclass"); - } - last_pc_offset = pc_offset; + Handle site = sites->obj_at(i); + if (site.is_null()) { + THROW_(vmSymbols::java_lang_NullPointerException(), JVMCIEnv::ok); } + + jint pc_offset = CompilationResult_Site::pcOffset(site); + + if (site->is_a(CompilationResult_Call::klass())) { + TRACE_jvmci_4("call at %i", pc_offset); + site_Call(buffer, pc_offset, site, CHECK_OK); + } else if (site->is_a(CompilationResult_Infopoint::klass())) { + // three reasons for infopoints denote actual safepoints + oop reason = CompilationResult_Infopoint::reason(site); + if (InfopointReason::SAFEPOINT() == reason || InfopointReason::CALL() == reason || InfopointReason::IMPLICIT_EXCEPTION() == reason) { + TRACE_jvmci_4("safepoint at %i", pc_offset); + site_Safepoint(buffer, pc_offset, site, CHECK_OK); + } else if (InfopointReason::METHOD_START() == reason || InfopointReason::METHOD_END() == reason || InfopointReason::LINE_NUMBER() == reason) { + site_Infopoint(buffer, pc_offset, site, CHECK_OK); + } else { + JVMCI_ERROR_OK("unknown infopoint reason at %i", pc_offset); + } + } else if (site->is_a(CompilationResult_DataPatch::klass())) { + TRACE_jvmci_4("datapatch at %i", pc_offset); + site_DataPatch(buffer, pc_offset, site, CHECK_OK); + } else if (site->is_a(CompilationResult_Mark::klass())) { + TRACE_jvmci_4("mark at %i", pc_offset); + site_Mark(buffer, pc_offset, site, CHECK_OK); + } else { + JVMCI_ERROR_OK("unexpected site subclass: %s", site->klass()->signature_name()); + } + last_pc_offset = pc_offset; + if (CodeInstallSafepointChecks && SafepointSynchronize::do_call_back()) { // this is a hacky way to force a safepoint check but nothing else was jumping out at me. ThreadToNativeFromVM ttnfv(JavaThread::current()); @@ -673,7 +751,6 @@ JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer) #ifndef PRODUCT if (comments() != NULL) { - No_Safepoint_Verifier no_safepoint; for (int i = 0; i < comments()->length(); i++) { oop comment = comments()->obj_at(i); assert(comment->is_a(HotSpotCompiledCode_Comment::klass()), "cce"); @@ -759,56 +836,61 @@ static bool bytecode_should_reexecute(Bytecodes::Code code) { return true; } -GrowableArray* CodeInstaller::record_virtual_objects(oop debug_info) { - objArrayOop virtualObjects = DebugInfo::virtualObjectMapping(debug_info); - if (virtualObjects == NULL) { +GrowableArray* CodeInstaller::record_virtual_objects(Handle debug_info, TRAPS) { + objArrayHandle virtualObjects = DebugInfo::virtualObjectMapping(debug_info); + if (virtualObjects.is_null()) { return NULL; } GrowableArray* objects = new GrowableArray(virtualObjects->length(), virtualObjects->length(), NULL); // Create the unique ObjectValues for (int i = 0; i < virtualObjects->length(); i++) { - oop value = virtualObjects->obj_at(i); + Handle value = virtualObjects->obj_at(i); int id = VirtualObject::id(value); - oop type = VirtualObject::type(value); + Handle type = VirtualObject::type(value); oop javaMirror = HotSpotResolvedObjectTypeImpl::javaClass(type); ObjectValue* sv = new ObjectValue(id, new ConstantOopWriteValue(JNIHandles::make_local(Thread::current(), javaMirror))); - assert(objects->at(id) == NULL, "once"); + if (id < 0 || id >= objects->length()) { + JVMCI_ERROR_NULL("virtual object id %d out of bounds", id); + } + if (objects->at(id) != NULL) { + JVMCI_ERROR_NULL("duplicate virtual object id %d", id); + } objects->at_put(id, sv); } // All the values which could be referenced by the VirtualObjects // exist, so now describe all the VirtualObjects themselves. for (int i = 0; i < virtualObjects->length(); i++) { - oop value = virtualObjects->obj_at(i); + Handle value = virtualObjects->obj_at(i); int id = VirtualObject::id(value); - record_object_value(objects->at(id)->as_ObjectValue(), value, objects); + record_object_value(objects->at(id)->as_ObjectValue(), value, objects, CHECK_NULL); } _debug_recorder->dump_object_pool(objects); return objects; } -void CodeInstaller::record_scope(jint pc_offset, oop debug_info) { - oop position = DebugInfo::bytecodePosition(debug_info); - if (position == NULL) { +void CodeInstaller::record_scope(jint pc_offset, Handle debug_info, TRAPS) { + Handle position = DebugInfo::bytecodePosition(debug_info); + if (position.is_null()) { // Stubs do not record scope info, just oop maps return; } - GrowableArray* objectMapping = record_virtual_objects(debug_info); - record_scope(pc_offset, position, objectMapping); + GrowableArray* objectMapping = record_virtual_objects(debug_info, CHECK); + record_scope(pc_offset, position, objectMapping, CHECK); } -void CodeInstaller::record_scope(jint pc_offset, oop position, GrowableArray* objects) { - oop frame = NULL; +void CodeInstaller::record_scope(jint pc_offset, Handle position, GrowableArray* objects, TRAPS) { + Handle frame; if (position->is_a(BytecodeFrame::klass())) { frame = position; } - oop caller_frame = BytecodePosition::caller(position); - if (caller_frame != NULL) { - record_scope(pc_offset, caller_frame, objects); + Handle caller_frame = BytecodePosition::caller(position); + if (caller_frame.not_null()) { + record_scope(pc_offset, caller_frame, objects, CHECK); } - oop hotspot_method = BytecodePosition::method(position); - Method* method = getMethodFromHotSpotMethod(hotspot_method); + Handle hotspot_method = BytecodePosition::method(position); + Method* method = getMethodFromHotSpotMethod(hotspot_method()); jint bci = BytecodePosition::bci(position); if (bci == BytecodeFrame::BEFORE_BCI()) { bci = SynchronizationEntryBCI; @@ -817,13 +899,13 @@ void CodeInstaller::record_scope(jint pc_offset, oop position, GrowableArrayname_and_sig_as_C_string()); bool reexecute = false; - if (frame != NULL) { + if (frame.not_null()) { if (bci == SynchronizationEntryBCI){ reexecute = false; } else { Bytecodes::Code code = Bytecodes::java_code_at(method, method->bcp_from(bci)); reexecute = bytecode_should_reexecute(code); - if (frame != NULL) { + if (frame.not_null()) { reexecute = (BytecodeFrame::duringCall(frame) == JNI_FALSE); } } @@ -834,15 +916,22 @@ void CodeInstaller::record_scope(jint pc_offset, oop position, GrowableArraylength(), "unexpected values length"); - assert(local_count + expression_count == slotKinds->length(), "unexpected slotKinds length"); + if (values.is_null() || slotKinds.is_null()) { + THROW(vmSymbols::java_lang_NullPointerException()); + } + if (local_count + expression_count + monitor_count != values->length()) { + JVMCI_ERROR("unexpected values length %d in scope (%d locals, %d expressions, %d monitors)", values->length(), local_count, expression_count, monitor_count); + } + if (local_count + expression_count != slotKinds->length()) { + JVMCI_ERROR("unexpected slotKinds length %d in scope (%d locals, %d expressions)", slotKinds->length(), local_count, expression_count); + } GrowableArray* locals = local_count > 0 ? new GrowableArray (local_count) : NULL; GrowableArray* expressions = expression_count > 0 ? new GrowableArray (expression_count) : NULL; @@ -853,30 +942,30 @@ void CodeInstaller::record_scope(jint pc_offset, oop position, GrowableArraylength(); i++) { ScopeValue* second = NULL; - oop value = values->obj_at(i); + Handle value = values->obj_at(i); if (i < local_count) { - oop kind = slotKinds->obj_at(i); - BasicType type = JVMCIRuntime::kindToBasicType(JavaKind::typeChar(kind)); - ScopeValue* first = get_scope_value(value, type, objects, second); + BasicType type = JVMCIRuntime::kindToBasicType(slotKinds->obj_at(i), CHECK); + ScopeValue* first = get_scope_value(value, type, objects, second, CHECK); if (second != NULL) { locals->append(second); } locals->append(first); } else if (i < local_count + expression_count) { - oop kind = slotKinds->obj_at(i); - BasicType type = JVMCIRuntime::kindToBasicType(JavaKind::typeChar(kind)); - ScopeValue* first = get_scope_value(value, type, objects, second); + BasicType type = JVMCIRuntime::kindToBasicType(slotKinds->obj_at(i), CHECK); + ScopeValue* first = get_scope_value(value, type, objects, second, CHECK); if (second != NULL) { expressions->append(second); } expressions->append(first); } else { - monitors->append(get_monitor_value(value, objects)); + MonitorValue *monitor = get_monitor_value(value, objects, CHECK); + monitors->append(monitor); } if (second != NULL) { i++; - assert(i < values->length(), "double-slot value not followed by Value.ILLEGAL"); - assert(values->obj_at(i) == Value::ILLEGAL(), "double-slot value not followed by Value.ILLEGAL"); + if (i >= values->length() || values->obj_at(i) != Value::ILLEGAL()) { + JVMCI_ERROR("double-slot value not followed by Value.ILLEGAL"); + } } } @@ -891,32 +980,37 @@ void CodeInstaller::record_scope(jint pc_offset, oop position, GrowableArraystart() + pc_offset; // jint next_pc_offset = Assembler::locate_next_instruction(instruction) - _instructions->start(); - _debug_recorder->add_safepoint(pc_offset, create_oop_map(debug_info)); - record_scope(pc_offset, debug_info); + OopMap *map = create_oop_map(debug_info, CHECK); + _debug_recorder->add_safepoint(pc_offset, map); + record_scope(pc_offset, debug_info, CHECK); _debug_recorder->end_safepoint(pc_offset); } -void CodeInstaller::site_Infopoint(CodeBuffer& buffer, jint pc_offset, oop site) { - oop debug_info = CompilationResult_Infopoint::debugInfo(site); - assert(debug_info != NULL, "debug info expected"); +void CodeInstaller::site_Infopoint(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS) { + Handle debug_info = CompilationResult_Infopoint::debugInfo(site); + if (debug_info.is_null()) { + JVMCI_ERROR("debug info expected at infopoint at %i", pc_offset); + } _debug_recorder->add_non_safepoint(pc_offset); - record_scope(pc_offset, debug_info); + record_scope(pc_offset, debug_info, CHECK); _debug_recorder->end_non_safepoint(pc_offset); } -void CodeInstaller::site_Call(CodeBuffer& buffer, jint pc_offset, oop site) { - oop target = CompilationResult_Call::target(site); +void CodeInstaller::site_Call(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS) { + Handle target = CompilationResult_Call::target(site); InstanceKlass* target_klass = InstanceKlass::cast(target->klass()); - oop hotspot_method = NULL; // JavaMethod - oop foreign_call = NULL; + Handle hotspot_method; // JavaMethod + Handle foreign_call; if (target_klass->is_subclass_of(SystemDictionary::HotSpotForeignCallTarget_klass())) { foreign_call = target; @@ -924,27 +1018,29 @@ void CodeInstaller::site_Call(CodeBuffer& buffer, jint pc_offset, oop site) { hotspot_method = target; } - oop debug_info = CompilationResult_Call::debugInfo(site); + Handle debug_info = CompilationResult_Call::debugInfo(site); - assert(!!hotspot_method ^ !!foreign_call, "Call site needs exactly one type"); + assert(hotspot_method.not_null() ^ foreign_call.not_null(), "Call site needs exactly one type"); NativeInstruction* inst = nativeInstruction_at(_instructions->start() + pc_offset); - jint next_pc_offset = CodeInstaller::pd_next_offset(inst, pc_offset, hotspot_method); + jint next_pc_offset = CodeInstaller::pd_next_offset(inst, pc_offset, hotspot_method, CHECK); - if (debug_info != NULL) { - _debug_recorder->add_safepoint(next_pc_offset, create_oop_map(debug_info)); - record_scope(next_pc_offset, debug_info); + if (debug_info.not_null()) { + OopMap *map = create_oop_map(debug_info, CHECK); + _debug_recorder->add_safepoint(next_pc_offset, map); + record_scope(next_pc_offset, debug_info, CHECK); } - if (foreign_call != NULL) { + if (foreign_call.not_null()) { jlong foreign_call_destination = HotSpotForeignCallTarget::address(foreign_call); - CodeInstaller::pd_relocate_ForeignCall(inst, foreign_call_destination); + CodeInstaller::pd_relocate_ForeignCall(inst, foreign_call_destination, CHECK); } else { // method != NULL - assert(hotspot_method != NULL, "unexpected JavaMethod"); - assert(debug_info != NULL, "debug info expected"); + if (debug_info.is_null()) { + JVMCI_ERROR("debug info expected at call at %i", pc_offset); + } TRACE_jvmci_3("method call"); - CodeInstaller::pd_relocate_JavaMethod(hotspot_method, pc_offset); + CodeInstaller::pd_relocate_JavaMethod(hotspot_method, pc_offset, CHECK); if (_next_call_type == INVOKESTATIC || _next_call_type == INVOKESPECIAL) { // Need a static call stub for transitions from compiled to interpreted. CompiledStaticCall::emit_to_interp_stub(buffer, _instructions->start() + pc_offset); @@ -953,38 +1049,45 @@ void CodeInstaller::site_Call(CodeBuffer& buffer, jint pc_offset, oop site) { _next_call_type = INVOKE_INVALID; - if (debug_info != NULL) { + if (debug_info.not_null()) { _debug_recorder->end_safepoint(next_pc_offset); } } -void CodeInstaller::site_DataPatch(CodeBuffer& buffer, jint pc_offset, oop site) { - oop reference = CompilationResult_DataPatch::reference(site); - if (reference->is_a(CompilationResult_ConstantReference::klass())) { +void CodeInstaller::site_DataPatch(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS) { + Handle reference = CompilationResult_DataPatch::reference(site); + if (reference.is_null()) { + THROW(vmSymbols::java_lang_NullPointerException()); + } else if (reference->is_a(CompilationResult_ConstantReference::klass())) { Handle constant = CompilationResult_ConstantReference::constant(reference); - if (constant->is_a(HotSpotObjectConstantImpl::klass())) { - pd_patch_OopConstant(pc_offset, constant); + if (constant.is_null()) { + THROW(vmSymbols::java_lang_NullPointerException()); + } else if (constant->is_a(HotSpotObjectConstantImpl::klass())) { + pd_patch_OopConstant(pc_offset, constant, CHECK); } else if (constant->is_a(HotSpotMetaspaceConstantImpl::klass())) { - pd_patch_MetaspaceConstant(pc_offset, constant); - } else if (constant->is_a(HotSpotSentinelConstant::klass())) { - fatal("sentinel constant unsupported"); + pd_patch_MetaspaceConstant(pc_offset, constant, CHECK); } else { - fatal("unknown constant type in data patch"); + JVMCI_ERROR("unknown constant type in data patch: %s", constant->klass()->signature_name()); } } else if (reference->is_a(CompilationResult_DataSectionReference::klass())) { int data_offset = CompilationResult_DataSectionReference::offset(reference); - assert(0 <= data_offset && data_offset < _constants_size, "data offset 0x%X points outside data section (size 0x%X)", data_offset, _constants_size); - pd_patch_DataSectionReference(pc_offset, data_offset); + if (0 <= data_offset && data_offset < _constants_size) { + pd_patch_DataSectionReference(pc_offset, data_offset); + } else { + JVMCI_ERROR("data offset 0x%X points outside data section (size 0x%X)", data_offset, _constants_size); + } } else { - fatal("unknown data patch type"); + JVMCI_ERROR("unknown data patch type: %s", reference->klass()->signature_name()); } } -void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, oop site) { - oop id_obj = CompilationResult_Mark::id(site); +void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS) { + Handle id_obj = CompilationResult_Mark::id(site); - if (id_obj != NULL) { - assert(java_lang_boxing_object::is_instance(id_obj, T_INT), "Integer id expected"); + if (id_obj.not_null()) { + if (!java_lang_boxing_object::is_instance(id_obj(), T_INT)) { + JVMCI_ERROR("expected Integer id, got %s", id_obj->klass()->signature_name()); + } jint id = id_obj->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT)); address pc = _instructions->start() + pc_offset; @@ -1017,7 +1120,7 @@ void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, oop site) { case POLL_FAR: case POLL_RETURN_NEAR: case POLL_RETURN_FAR: - pd_relocate_poll(pc, id); + pd_relocate_poll(pc, id, CHECK); break; case CARD_TABLE_SHIFT: case CARD_TABLE_ADDRESS: @@ -1027,7 +1130,7 @@ void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, oop site) { case CRC_TABLE_ADDRESS: break; default: - ShouldNotReachHere(); + JVMCI_ERROR("invalid mark id: %d", id); break; } } diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp index 2ee2cbd742c..2114e0c9166 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp @@ -154,13 +154,13 @@ private: static ConstantIntValue* _int_2_scope_value; static LocationValue* _illegal_value; - jint pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method); - void pd_patch_OopConstant(int pc_offset, Handle& constant); - void pd_patch_MetaspaceConstant(int pc_offset, Handle& constant); + jint pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS); + void pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS); + void pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS); void pd_patch_DataSectionReference(int pc_offset, int data_offset); - void pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination); - void pd_relocate_JavaMethod(oop method, jint pc_offset); - void pd_relocate_poll(address pc, jint mark); + void pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS); + void pd_relocate_JavaMethod(Handle method, jint pc_offset, TRAPS); + void pd_relocate_poll(address pc, jint mark, TRAPS); objArrayOop sites() { return (objArrayOop) JNIHandles::resolve(_sites_handle); } arrayOop code() { return (arrayOop) JNIHandles::resolve(_code_handle); } @@ -177,33 +177,33 @@ public: CodeInstaller() : _arena(mtCompiler) {} - JVMCIEnv::CodeInstallResult gather_metadata(Handle target, Handle& compiled_code, CodeMetadata& metadata); - JVMCIEnv::CodeInstallResult install(JVMCICompiler* compiler, Handle target, Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log); + JVMCIEnv::CodeInstallResult gather_metadata(Handle target, Handle& compiled_code, CodeMetadata& metadata, TRAPS); + JVMCIEnv::CodeInstallResult install(JVMCICompiler* compiler, Handle target, Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log, TRAPS); static address runtime_call_target_address(oop runtime_call); - static VMReg get_hotspot_reg(jint jvmciRegisterNumber); + static VMReg get_hotspot_reg(jint jvmciRegisterNumber, TRAPS); static bool is_general_purpose_reg(VMReg hotspotRegister); const OopMapSet* oopMapSet() const { return _debug_recorder->_oopmaps; } protected: - Location::Type get_oop_type(oop value); - ScopeValue* get_scope_value(oop value, BasicType type, GrowableArray* objects, ScopeValue* &second); - MonitorValue* get_monitor_value(oop value, GrowableArray* objects); + Location::Type get_oop_type(Handle value); + ScopeValue* get_scope_value(Handle value, BasicType type, GrowableArray* objects, ScopeValue* &second, TRAPS); + MonitorValue* get_monitor_value(Handle value, GrowableArray* objects, TRAPS); - Metadata* record_metadata_reference(Handle& constant); + Metadata* record_metadata_reference(Handle constant, TRAPS); #ifdef _LP64 - narrowKlass record_narrow_metadata_reference(Handle& constant); + narrowKlass record_narrow_metadata_reference(Handle constant, TRAPS); #endif // extract the fields of the CompilationResult - void initialize_fields(oop target, oop target_method); - void initialize_dependencies(oop target_method, OopRecorder* oop_recorder); + void initialize_fields(oop target, oop target_method, TRAPS); + void initialize_dependencies(oop target_method, OopRecorder* oop_recorder, TRAPS); - int estimate_stubs_size(); + int estimate_stubs_size(TRAPS); // perform data and call relocation on the CodeBuffer - JVMCIEnv::CodeInstallResult initialize_buffer(CodeBuffer& buffer); + JVMCIEnv::CodeInstallResult initialize_buffer(CodeBuffer& buffer, TRAPS); void assumption_NoFinalizableSubclass(Handle assumption); void assumption_ConcreteSubtype(Handle assumption); @@ -211,19 +211,19 @@ protected: void assumption_ConcreteMethod(Handle assumption); void assumption_CallSiteTargetValue(Handle assumption); - void site_Safepoint(CodeBuffer& buffer, jint pc_offset, oop site); - void site_Infopoint(CodeBuffer& buffer, jint pc_offset, oop site); - void site_Call(CodeBuffer& buffer, jint pc_offset, oop site); - void site_DataPatch(CodeBuffer& buffer, jint pc_offset, oop site); - void site_Mark(CodeBuffer& buffer, jint pc_offset, oop site); + void site_Safepoint(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS); + void site_Infopoint(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS); + void site_Call(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS); + void site_DataPatch(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS); + void site_Mark(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS); - OopMap* create_oop_map(oop debug_info); + OopMap* create_oop_map(Handle debug_info, TRAPS); - void record_scope(jint pc_offset, oop debug_info); - void record_scope(jint pc_offset, oop code_pos, GrowableArray* objects); - void record_object_value(ObjectValue* sv, oop value, GrowableArray* objects); + void record_scope(jint pc_offset, Handle debug_info, TRAPS); + void record_scope(jint pc_offset, Handle code_pos, GrowableArray* objects, TRAPS); + void record_object_value(ObjectValue* sv, Handle value, GrowableArray* objects, TRAPS); - GrowableArray* record_virtual_objects(oop debug_info); + GrowableArray* record_virtual_objects(Handle debug_info, TRAPS); void process_exception_handlers(); int estimateStubSpace(int static_call_stubs); diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp index a746203c570..bc20b2a7354 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -670,7 +670,7 @@ C2V_VMENTRY(jint, installCode, (JNIEnv *jniEnv, jobject, jobject target, jobject TraceTime install_time("installCode", JVMCICompiler::codeInstallTimer()); CodeInstaller installer; - JVMCIEnv::CodeInstallResult result = installer.install(compiler, target_handle, compiled_code_handle, cb, installed_code_handle, speculation_log_handle); + JVMCIEnv::CodeInstallResult result = installer.install(compiler, target_handle, compiled_code_handle, cb, installed_code_handle, speculation_log_handle, CHECK_0); if (PrintCodeCacheOnCompilation) { stringStream s; @@ -726,7 +726,7 @@ C2V_VMENTRY(jint, getMetadata, (JNIEnv *jniEnv, jobject, jobject target, jobject CodeBlob *cb = NULL; CodeInstaller installer; - JVMCIEnv::CodeInstallResult result = installer.gather_metadata(target_handle, compiled_code_handle, code_metadata); //cb, pc_descs, nr_pc_descs, scopes_descs, scopes_size, reloc_buffer); + JVMCIEnv::CodeInstallResult result = installer.gather_metadata(target_handle, compiled_code_handle, code_metadata, CHECK_0); //cb, pc_descs, nr_pc_descs, scopes_descs, scopes_size, reloc_buffer); if (result != JVMCIEnv::ok) { return result; } diff --git a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp index 263f398e8f2..6c60061e4f4 100644 --- a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp @@ -59,7 +59,11 @@ bool JVMCIRuntime::_shutdown_called = false; static const char* OPTION_PREFIX = "jvmci.option."; static const size_t OPTION_PREFIX_LEN = strlen(OPTION_PREFIX); -BasicType JVMCIRuntime::kindToBasicType(jchar ch) { +BasicType JVMCIRuntime::kindToBasicType(Handle kind, TRAPS) { + if (kind.is_null()) { + THROW_(vmSymbols::java_lang_NullPointerException(), T_ILLEGAL); + } + jchar ch = JavaKind::typeChar(kind); switch(ch) { case 'z': return T_BOOLEAN; case 'b': return T_BYTE; @@ -72,10 +76,8 @@ BasicType JVMCIRuntime::kindToBasicType(jchar ch) { case 'a': return T_OBJECT; case '-': return T_ILLEGAL; default: - fatal("unexpected Kind: %c", ch); - break; + JVMCI_ERROR_(T_ILLEGAL, "unexpected Kind: %c", ch); } - return T_ILLEGAL; } // Simple helper to see if the caller of a runtime stub which diff --git a/hotspot/src/share/vm/jvmci/jvmciRuntime.hpp b/hotspot/src/share/vm/jvmci/jvmciRuntime.hpp index 00eae524c15..9e69965f19d 100644 --- a/hotspot/src/share/vm/jvmci/jvmciRuntime.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.hpp @@ -29,6 +29,17 @@ #include "runtime/arguments.hpp" #include "runtime/deoptimization.hpp" +#define JVMCI_ERROR(...) \ + { Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::jdk_vm_ci_common_JVMCIError(), __VA_ARGS__); return; } + +#define JVMCI_ERROR_(ret, ...) \ + { Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::jdk_vm_ci_common_JVMCIError(), __VA_ARGS__); return ret; } + +#define JVMCI_ERROR_0(...) JVMCI_ERROR_(0, __VA_ARGS__) +#define JVMCI_ERROR_NULL(...) JVMCI_ERROR_(NULL, __VA_ARGS__) +#define JVMCI_ERROR_OK(...) JVMCI_ERROR_(JVMCIEnv::ok, __VA_ARGS__) +#define CHECK_OK CHECK_(JVMCIEnv::ok) + class ParseClosure : public StackObj { int _lineNo; char* _filename; @@ -171,7 +182,7 @@ class JVMCIRuntime: public AllStatic { } \ (void)(0 - static BasicType kindToBasicType(jchar ch); + static BasicType kindToBasicType(Handle kind, TRAPS); // The following routines are all called from compiled JVMCI code diff --git a/hotspot/src/share/vm/jvmci/vmSymbols_jvmci.hpp b/hotspot/src/share/vm/jvmci/vmSymbols_jvmci.hpp index 5502f2fa603..8d8af6bd79a 100644 --- a/hotspot/src/share/vm/jvmci/vmSymbols_jvmci.hpp +++ b/hotspot/src/share/vm/jvmci/vmSymbols_jvmci.hpp @@ -86,6 +86,7 @@ template(jdk_vm_ci_code_VirtualObject, "jdk/vm/ci/code/VirtualObject") \ template(jdk_vm_ci_code_RegisterSaveLayout, "jdk/vm/ci/code/RegisterSaveLayout") \ template(jdk_vm_ci_code_InvalidInstalledCodeException, "jdk/vm/ci/code/InvalidInstalledCodeException") \ + template(jdk_vm_ci_common_JVMCIError, "jdk/vm/ci/common/JVMCIError") \ template(compileMethod_name, "compileMethod") \ template(compileMethod_signature, "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;IJI)V") \ template(fromMetaspace_name, "fromMetaspace") \ diff --git a/hotspot/test/compiler/jvmci/errors/CodeInstallerTest.java b/hotspot/test/compiler/jvmci/errors/CodeInstallerTest.java new file mode 100644 index 00000000000..aae95940098 --- /dev/null +++ b/hotspot/test/compiler/jvmci/errors/CodeInstallerTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.jvmci.errors; + +import java.lang.reflect.Method; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.CompilationResult; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; +import jdk.vm.ci.runtime.JVMCI; +import jdk.vm.ci.runtime.JVMCIBackend; + +import org.junit.Assert; + +public class CodeInstallerTest { + + protected final Architecture arch; + protected final CodeCacheProvider codeCache; + protected final MetaAccessProvider metaAccess; + protected final HotSpotConstantReflectionProvider constantReflection; + + protected final ResolvedJavaMethod dummyMethod; + + public static void dummyMethod() { + } + + protected CodeInstallerTest() { + JVMCIBackend backend = JVMCI.getRuntime().getHostJVMCIBackend(); + metaAccess = backend.getMetaAccess(); + codeCache = backend.getCodeCache(); + constantReflection = (HotSpotConstantReflectionProvider) backend.getConstantReflection(); + arch = codeCache.getTarget().arch; + + Method method = null; + try { + method = CodeInstallerTest.class.getMethod("dummyMethod"); + } catch (NoSuchMethodException e) { + Assert.fail(); + } + + dummyMethod = metaAccess.lookupJavaMethod(method); + } + + protected void installCode(CompilationResult result) { + codeCache.addCode(dummyMethod, result, null, null); + } + + protected Register getRegister(PlatformKind kind, int index) { + Register[] allRegs = arch.getAvailableValueRegisters(); + for (int i = 0; i < allRegs.length; i++) { + if (arch.canStoreValue(allRegs[i].getRegisterCategory(), kind)) { + if (index-- == 0) { + return allRegs[i]; + } + } + } + return null; + } +} diff --git a/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java b/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java new file mode 100644 index 00000000000..5e9ab133ffd --- /dev/null +++ b/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile CodeInstallerTest.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.errors.TestInvalidCompilationResult + */ + +package compiler.jvmci.errors; + +import static jdk.vm.ci.code.CompilationResult.ConstantReference; +import static jdk.vm.ci.code.CompilationResult.DataPatch; +import static jdk.vm.ci.code.CompilationResult.DataSectionReference; +import static jdk.vm.ci.code.CompilationResult.Infopoint; +import static jdk.vm.ci.code.CompilationResult.Reference; +import static jdk.vm.ci.code.DataSection.Data; +import static jdk.vm.ci.code.DataSection.DataBuilder; +import static jdk.vm.ci.meta.Assumptions.Assumption; + +import jdk.vm.ci.code.CompilationResult; +import jdk.vm.ci.code.InfopointReason; +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.hotspot.HotSpotConstant; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.VMConstant; + +import org.junit.Test; + +/** + * Tests for errors in the code installer. + */ +public class TestInvalidCompilationResult extends CodeInstallerTest { + + private static class InvalidAssumption extends Assumption { + } + + private static class InvalidVMConstant implements VMConstant { + + public boolean isDefaultForKind() { + return false; + } + + public String toValueString() { + return null; + } + } + + private static class InvalidReference extends Reference { + + @Override + public int hashCode() { + return 0; + } + + @Override + public boolean equals(Object obj) { + return false; + } + } + + @Test(expected = JVMCIError.class) + public void testInvalidAssumption() { + CompilationResult result = new CompilationResult(); + result.setAssumptions(new Assumption[]{new InvalidAssumption()}); + installCode(result); + } + + @Test(expected = JVMCIError.class) + public void testInvalidAlignment() { + CompilationResult result = new CompilationResult(); + result.getDataSection().insertData(new Data(7, 1, DataBuilder.zero(1))); + installCode(result); + } + + @Test(expected = NullPointerException.class) + public void testNullDataPatchInDataSection() { + CompilationResult result = new CompilationResult(); + Data data = new Data(1, 1, (buffer, patch) -> { + patch.accept(null); + buffer.put((byte) 0); + }); + result.getDataSection().insertData(data); + installCode(result); + } + + @Test(expected = NullPointerException.class) + public void testNullReferenceInDataSection() { + CompilationResult result = new CompilationResult(); + Data data = new Data(1, 1, (buffer, patch) -> { + patch.accept(new DataPatch(buffer.position(), null)); + buffer.put((byte) 0); + }); + result.getDataSection().insertData(data); + installCode(result); + } + + @Test(expected = JVMCIError.class) + public void testInvalidDataSectionReference() { + CompilationResult result = new CompilationResult(); + DataSectionReference ref = result.getDataSection().insertData(new Data(1, 1, DataBuilder.zero(1))); + Data data = new Data(1, 1, (buffer, patch) -> { + patch.accept(new DataPatch(buffer.position(), ref)); + buffer.put((byte) 0); + }); + result.getDataSection().insertData(data); + installCode(result); + } + + @Test(expected = JVMCIError.class) + public void testInvalidNarrowMethodInDataSection() { + CompilationResult result = new CompilationResult(); + HotSpotConstant c = (HotSpotConstant) dummyMethod.getEncoding(); + Data data = new Data(4, 4, (buffer, patch) -> { + patch.accept(new DataPatch(buffer.position(), new ConstantReference((VMConstant) c.compress()))); + buffer.putInt(0); + }); + result.getDataSection().insertData(data); + installCode(result); + } + + @Test(expected = NullPointerException.class) + public void testNullConstantInDataSection() { + CompilationResult result = new CompilationResult(); + Data data = new Data(1, 1, (buffer, patch) -> { + patch.accept(new DataPatch(buffer.position(), new ConstantReference(null))); + }); + result.getDataSection().insertData(data); + installCode(result); + } + + @Test(expected = JVMCIError.class) + public void testInvalidConstantInDataSection() { + CompilationResult result = new CompilationResult(); + Data data = new Data(1, 1, (buffer, patch) -> { + patch.accept(new DataPatch(buffer.position(), new ConstantReference(new InvalidVMConstant()))); + }); + result.getDataSection().insertData(data); + installCode(result); + } + + @Test(expected = NullPointerException.class) + public void testNullReferenceInCode() { + CompilationResult result = new CompilationResult(); + result.recordDataPatch(0, null); + installCode(result); + } + + @Test(expected = NullPointerException.class) + public void testNullConstantInCode() { + CompilationResult result = new CompilationResult(); + result.recordDataPatch(0, new ConstantReference(null)); + installCode(result); + } + + @Test(expected = JVMCIError.class) + public void testInvalidConstantInCode() { + CompilationResult result = new CompilationResult(); + result.recordDataPatch(0, new ConstantReference(new InvalidVMConstant())); + installCode(result); + } + + @Test(expected = JVMCIError.class) + public void testInvalidReference() { + CompilationResult result = new CompilationResult(); + result.recordDataPatch(0, new InvalidReference()); + installCode(result); + } + + @Test(expected = JVMCIError.class) + public void testOutOfBoundsDataSectionReference() { + CompilationResult result = new CompilationResult(); + DataSectionReference ref = new DataSectionReference(); + ref.setOffset(0x1000); + result.recordDataPatch(0, ref); + installCode(result); + } + + @Test(expected = JVMCIError.class) + public void testInvalidMark() { + CompilationResult result = new CompilationResult(); + result.recordMark(0, new Object()); + installCode(result); + } + + @Test(expected = JVMCIError.class) + public void testInvalidMarkInt() { + CompilationResult result = new CompilationResult(); + result.recordMark(0, -1); + installCode(result); + } + + @Test(expected = NullPointerException.class) + public void testNullInfopoint() { + CompilationResult result = new CompilationResult(); + result.addInfopoint(null); + installCode(result); + } + + @Test(expected = JVMCIError.class) + public void testUnknownInfopointReason() { + CompilationResult result = new CompilationResult(); + result.addInfopoint(new Infopoint(0, null, InfopointReason.UNKNOWN)); + installCode(result); + } + + @Test(expected = JVMCIError.class) + public void testInfopointMissingDebugInfo() { + CompilationResult result = new CompilationResult(); + result.addInfopoint(new Infopoint(0, null, InfopointReason.METHOD_START)); + installCode(result); + } + + @Test(expected = JVMCIError.class) + public void testSafepointMissingDebugInfo() { + CompilationResult result = new CompilationResult(); + result.addInfopoint(new Infopoint(0, null, InfopointReason.SAFEPOINT)); + installCode(result); + } +} diff --git a/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java b/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java new file mode 100644 index 00000000000..e8a0d1f536d --- /dev/null +++ b/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile CodeInstallerTest.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.errors.TestInvalidDebugInfo + */ + +package compiler.jvmci.errors; + +import static jdk.vm.ci.code.CompilationResult.Infopoint; + +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.CompilationResult; +import jdk.vm.ci.code.DebugInfo; +import jdk.vm.ci.code.InfopointReason; +import jdk.vm.ci.code.Location; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.StackSlot; +import jdk.vm.ci.code.VirtualObject; +import jdk.vm.ci.hotspot.HotSpotReferenceMap; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.JavaValue; +import jdk.vm.ci.meta.LIRKind; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Value; +import jdk.vm.ci.common.JVMCIError; + +import org.junit.Test; + +/** + * Tests for errors in debug info. + */ +public class TestInvalidDebugInfo extends CodeInstallerTest { + + private static class UnknownJavaValue implements JavaValue { + } + + private void test(JavaValue[] values, JavaKind[] slotKinds, int locals, int stack, int locks) { + test(null, values, slotKinds, locals, stack, locks); + } + + private void test(VirtualObject[] vobj, JavaValue[] values, JavaKind[] slotKinds, int locals, int stack, int locks) { + BytecodeFrame frame = new BytecodeFrame(null, dummyMethod, 0, false, false, values, slotKinds, locals, stack, locks); + DebugInfo info = new DebugInfo(frame, vobj); + info.setReferenceMap(new HotSpotReferenceMap(new Location[0], new Location[0], new int[0], 8)); + + CompilationResult result = new CompilationResult(); + result.addInfopoint(new Infopoint(0, info, InfopointReason.SAFEPOINT)); + installCode(result); + } + + @Test(expected = NullPointerException.class) + public void testNullValues() { + test(null, new JavaKind[0], 0, 0, 0); + } + + @Test(expected = NullPointerException.class) + public void testNullSlotKinds() { + test(new JavaValue[0], null, 0, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedScopeValuesLength() { + test(new JavaValue[]{JavaConstant.FALSE}, new JavaKind[0], 0, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedScopeSlotKindsLength() { + test(new JavaValue[0], new JavaKind[]{JavaKind.Boolean}, 0, 0, 0); + } + + @Test(expected = NullPointerException.class) + public void testNullValue() { + test(new JavaValue[]{null}, new JavaKind[]{JavaKind.Int}, 1, 0, 0); + } + + @Test(expected = NullPointerException.class) + public void testNullSlotKind() { + test(new JavaValue[]{JavaConstant.INT_0}, new JavaKind[]{null}, 1, 0, 0); + } + + @Test(expected = NullPointerException.class) + public void testNullMonitor() { + test(new JavaValue[]{null}, new JavaKind[0], 0, 0, 1); + } + + @Test(expected = JVMCIError.class) + public void testWrongMonitorType() { + test(new JavaValue[]{JavaConstant.INT_0}, new JavaKind[0], 0, 0, 1); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedIllegalValue() { + test(new JavaValue[]{Value.ILLEGAL}, new JavaKind[]{JavaKind.Int}, 1, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedTypeInCPURegister() { + Register reg = getRegister(arch.getPlatformKind(JavaKind.Int), 0); + test(new JavaValue[]{reg.asValue()}, new JavaKind[]{JavaKind.Illegal}, 1, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedTypeInFloatRegister() { + Register reg = getRegister(arch.getPlatformKind(JavaKind.Float), 0); + test(new JavaValue[]{reg.asValue()}, new JavaKind[]{JavaKind.Illegal}, 1, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedTypeOnStack() { + LIRKind kind = codeCache.getTarget().getLIRKind(JavaKind.Int); + StackSlot value = StackSlot.get(kind, 8, false); + test(new JavaValue[]{value}, new JavaKind[]{JavaKind.Illegal}, 1, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testWrongConstantType() { + test(new JavaValue[]{JavaConstant.INT_0}, new JavaKind[]{JavaKind.Object}, 1, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testUnsupportedConstantType() { + test(new JavaValue[]{JavaConstant.forShort((short) 0)}, new JavaKind[]{JavaKind.Short}, 1, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedNull() { + test(new JavaValue[]{JavaConstant.NULL_POINTER}, new JavaKind[]{JavaKind.Int}, 1, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedObject() { + JavaValue wrapped = constantReflection.forObject(this); + test(new JavaValue[]{wrapped}, new JavaKind[]{JavaKind.Int}, 1, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testUnknownJavaValue() { + test(new JavaValue[]{new UnknownJavaValue()}, new JavaKind[]{JavaKind.Int}, 1, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testMissingIllegalAfterDouble() { + test(new JavaValue[]{JavaConstant.DOUBLE_0, JavaConstant.INT_0}, new JavaKind[]{JavaKind.Double, JavaKind.Int}, 2, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testInvalidVirtualObjectId() { + ResolvedJavaType obj = metaAccess.lookupJavaType(Object.class); + VirtualObject o = VirtualObject.get(obj, 5); + o.setValues(new JavaValue[0], new JavaKind[0]); + + test(new VirtualObject[]{o}, new JavaValue[0], new JavaKind[0], 0, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testDuplicateVirtualObject() { + ResolvedJavaType obj = metaAccess.lookupJavaType(Object.class); + VirtualObject o1 = VirtualObject.get(obj, 0); + o1.setValues(new JavaValue[0], new JavaKind[0]); + + VirtualObject o2 = VirtualObject.get(obj, 0); + o2.setValues(new JavaValue[0], new JavaKind[0]); + + test(new VirtualObject[]{o1, o2}, new JavaValue[0], new JavaKind[0], 0, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testUnexpectedVirtualObject() { + ResolvedJavaType obj = metaAccess.lookupJavaType(Object.class); + VirtualObject o = VirtualObject.get(obj, 0); + o.setValues(new JavaValue[0], new JavaKind[0]); + + test(new VirtualObject[]{o}, new JavaValue[]{o}, new JavaKind[]{JavaKind.Int}, 1, 0, 0); + } + + @Test(expected = JVMCIError.class) + public void testUndefinedVirtualObject() { + ResolvedJavaType obj = metaAccess.lookupJavaType(Object.class); + VirtualObject o0 = VirtualObject.get(obj, 0); + o0.setValues(new JavaValue[0], new JavaKind[0]); + + VirtualObject o1 = VirtualObject.get(obj, 1); + o1.setValues(new JavaValue[0], new JavaKind[0]); + + test(new VirtualObject[]{o0}, new JavaValue[]{o1}, new JavaKind[]{JavaKind.Object}, 1, 0, 0); + } +} diff --git a/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java b/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java new file mode 100644 index 00000000000..133d659f622 --- /dev/null +++ b/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile CodeInstallerTest.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.errors.TestInvalidOopMap + */ + +package compiler.jvmci.errors; + +import static jdk.vm.ci.code.CompilationResult.Infopoint; + +import jdk.vm.ci.code.BytecodePosition; +import jdk.vm.ci.code.CompilationResult; +import jdk.vm.ci.code.DebugInfo; +import jdk.vm.ci.code.InfopointReason; +import jdk.vm.ci.code.Location; +import jdk.vm.ci.code.ReferenceMap; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.hotspot.HotSpotReferenceMap; +import jdk.vm.ci.hotspot.HotSpotVMConfig; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.LIRKind; +import jdk.vm.ci.meta.PlatformKind; +import jdk.vm.ci.common.JVMCIError; + +import org.junit.Test; + +/** + * Tests for errors in oop maps. + */ +public class TestInvalidOopMap extends CodeInstallerTest { + + private static class InvalidReferenceMap extends ReferenceMap { + } + + private void test(ReferenceMap refMap) { + BytecodePosition pos = new BytecodePosition(null, dummyMethod, 0); + DebugInfo info = new DebugInfo(pos); + info.setReferenceMap(refMap); + + CompilationResult result = new CompilationResult(); + result.addInfopoint(new Infopoint(0, info, InfopointReason.SAFEPOINT)); + installCode(result); + } + + @Test(expected = NullPointerException.class) + public void testMissingReferenceMap() { + test(null); + } + + @Test(expected = JVMCIError.class) + public void testInvalidReferenceMap() { + test(new InvalidReferenceMap()); + } + + @Test(expected = NullPointerException.class) + public void testNullOops() { + test(new HotSpotReferenceMap(null, new Location[0], new int[0], 8)); + } + + @Test(expected = NullPointerException.class) + public void testNullBase() { + test(new HotSpotReferenceMap(new Location[0], null, new int[0], 8)); + } + + @Test(expected = NullPointerException.class) + public void testNullSize() { + test(new HotSpotReferenceMap(new Location[0], new Location[0], null, 8)); + } + + @Test(expected = JVMCIError.class) + public void testInvalidLength() { + test(new HotSpotReferenceMap(new Location[1], new Location[2], new int[3], 8)); + } + + @Test(expected = JVMCIError.class) + public void testInvalidShortOop() { + PlatformKind kind = arch.getPlatformKind(JavaKind.Short); + Register reg = getRegister(kind, 0); + + Location[] oops = new Location[]{Location.register(reg)}; + Location[] base = new Location[]{null}; + int[] size = new int[]{kind.getSizeInBytes()}; + + test(new HotSpotReferenceMap(oops, base, size, 8)); + } + + @Test(expected = JVMCIError.class) + public void testInvalidNarrowDerivedOop() { + if (!HotSpotVMConfig.config().useCompressedOops) { + throw new JVMCIError("skipping test"); + } + + PlatformKind kind = arch.getPlatformKind(JavaKind.Int); + Register reg = getRegister(kind, 0); + Register baseReg = getRegister(arch.getPlatformKind(JavaKind.Object), 1); + + Location[] oops = new Location[]{Location.register(reg)}; + Location[] base = new Location[]{Location.register(baseReg)}; + int[] size = new int[]{kind.getSizeInBytes()}; + + test(new HotSpotReferenceMap(oops, base, size, 8)); + } +} From 48183cc207b0a4d0da2fd9ad2a2d2335e19bd8e8 Mon Sep 17 00:00:00 2001 From: Dmitrij Pochepko Date: Fri, 6 Nov 2015 14:51:15 +0300 Subject: [PATCH 012/260] 8141353: Testlibrary: add various changes into testlibrary Utils Added TEST_JDK, TEST_CLASSES properties and getMandatoryProperty method Reviewed-by: iignatyev --- .../test/testlibrary/jdk/test/lib/Utils.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/hotspot/test/testlibrary/jdk/test/lib/Utils.java b/hotspot/test/testlibrary/jdk/test/lib/Utils.java index 6776db006fe..6e9196a7c4e 100644 --- a/hotspot/test/testlibrary/jdk/test/lib/Utils.java +++ b/hotspot/test/testlibrary/jdk/test/lib/Utils.java @@ -44,6 +44,7 @@ import java.util.Iterator; import java.util.Map; import java.util.HashMap; import java.util.List; +import java.util.Objects; import java.util.Random; import java.util.function.BooleanSupplier; import java.util.concurrent.TimeUnit; @@ -82,6 +83,16 @@ public final class Utils { */ public static final String TEST_SRC = System.getProperty("test.src", ".").trim(); + /* + * Returns the value of 'test.jdk' system property + */ + public static final String TEST_JDK = System.getProperty("test.jdk"); + + /** + * Returns the value of 'test.classes' system property + */ + public static final String TEST_CLASSES = System.getProperty("test.classes", "."); + private static Unsafe unsafe = null; /** @@ -616,5 +627,18 @@ public final class Utils { NULL_VALUES.put(float.class, 0.0f); NULL_VALUES.put(double.class, 0.0d); } + + /** + * Returns mandatory property value + * @param propName is a name of property to request + * @return a String with requested property value + */ + public static String getMandatoryProperty(String propName) { + Objects.requireNonNull(propName, "Requested null property"); + String prop = System.getProperty(propName); + Objects.requireNonNull(prop, + String.format("A mandatory property '%s' isn't set", propName)); + return prop; + } } From 38339b3fe9bce21eb13494b0c35b1e38ac9b9bf6 Mon Sep 17 00:00:00 2001 From: Dmitrij Pochepko Date: Fri, 6 Nov 2015 14:54:02 +0300 Subject: [PATCH 013/260] 8138689: use package for /compiler/whitebox common classes Moved CompilerWhiteBoxTest to package, updating tests accordingly Reviewed-by: iignatyev --- .../arraycopy/TestArrayCopyNoInitDeopt.java | 3 +- .../test/compiler/floatingpoint/TestPow2.java | 3 +- .../intrinsics/IntrinsicAvailableTest.java | 3 +- .../intrinsics/bmi/verifycode/AddnTestI.java | 2 +- .../intrinsics/bmi/verifycode/AddnTestL.java | 2 +- .../intrinsics/bmi/verifycode/BlsiTestI.java | 2 +- .../intrinsics/bmi/verifycode/BlsiTestL.java | 2 +- .../bmi/verifycode/BlsmskTestI.java | 2 +- .../bmi/verifycode/BlsmskTestL.java | 2 +- .../intrinsics/bmi/verifycode/BlsrTestI.java | 2 +- .../intrinsics/bmi/verifycode/BlsrTestL.java | 2 +- .../bmi/verifycode/BmiIntrinsicBase.java | 1 + .../intrinsics/bmi/verifycode/LZcntTestI.java | 2 +- .../intrinsics/bmi/verifycode/LZcntTestL.java | 2 +- .../intrinsics/bmi/verifycode/TZcntTestI.java | 2 +- .../intrinsics/bmi/verifycode/TZcntTestL.java | 2 +- .../mathexact/sanity/AddExactIntTest.java | 3 +- .../mathexact/sanity/AddExactLongTest.java | 3 +- .../sanity/DecrementExactIntTest.java | 3 +- .../sanity/DecrementExactLongTest.java | 3 +- .../sanity/IncrementExactIntTest.java | 3 +- .../sanity/IncrementExactLongTest.java | 3 +- .../mathexact/sanity/IntrinsicBase.java | 1 + .../mathexact/sanity/MathIntrinsic.java | 1 + .../sanity/MultiplyExactIntTest.java | 3 +- .../sanity/MultiplyExactLongTest.java | 3 +- .../mathexact/sanity/NegateExactIntTest.java | 3 +- .../mathexact/sanity/NegateExactLongTest.java | 3 +- .../sanity/SubtractExactIntTest.java | 3 +- .../sanity/SubtractExactLongTest.java | 3 +- .../rangechecks/TestExplicitRangeChecks.java | 3 +- .../rangechecks/TestRangeCheckSmearing.java | 3 +- .../test/compiler/tiered/CompLevelsTest.java | 3 + .../ConstantGettersTransitionsTest.java | 3 +- .../compiler/tiered/LevelTransitionTest.java | 6 +- .../compiler/tiered/NonTieredLevelsTest.java | 5 +- .../compiler/tiered/TieredLevelsTest.java | 6 +- .../tiered/TransitionsTestExecutor.java | 1 + .../whitebox/ClearMethodStateTest.java | 5 +- .../whitebox/CompilerWhiteBoxTest.java | 273 +---------------- .../compiler/whitebox/DeoptimizeAllTest.java | 6 +- .../whitebox/DeoptimizeFramesTest.java | 4 +- .../whitebox/DeoptimizeMethodTest.java | 6 +- .../whitebox/DeoptimizeMultipleOSRTest.java | 3 +- .../EnqueueMethodForCompilationTest.java | 6 +- .../whitebox/ForceNMethodSweepTest.java | 5 +- .../compiler/whitebox/GetNMethodTest.java | 5 +- .../whitebox/IsMethodCompilableTest.java | 5 +- .../whitebox/LockCompilationTest.java | 6 +- .../whitebox/MakeMethodNotCompilableTest.java | 6 +- .../whitebox/SetDontInlineMethodTest.java | 6 +- .../whitebox/SetForceInlineMethodTest.java | 6 +- .../compiler/whitebox/SimpleTestCase.java | 284 ++++++++++++++++++ 53 files changed, 392 insertions(+), 336 deletions(-) create mode 100644 hotspot/test/compiler/whitebox/SimpleTestCase.java diff --git a/hotspot/test/compiler/arraycopy/TestArrayCopyNoInitDeopt.java b/hotspot/test/compiler/arraycopy/TestArrayCopyNoInitDeopt.java index dfa5f7e0414..c382faad67f 100644 --- a/hotspot/test/compiler/arraycopy/TestArrayCopyNoInitDeopt.java +++ b/hotspot/test/compiler/arraycopy/TestArrayCopyNoInitDeopt.java @@ -25,7 +25,7 @@ * @test * @bug 8072016 * @summary Infinite deoptimization/recompilation cycles in case of arraycopy with tightly coupled allocation - * @library /testlibrary /../../test/lib /compiler/whitebox + * @library /testlibrary /../../test/lib / * @modules java.base/sun.misc * java.management * @build TestArrayCopyNoInitDeopt @@ -42,6 +42,7 @@ import sun.hotspot.WhiteBox; import sun.hotspot.code.NMethod; import jdk.test.lib.Platform; import java.lang.reflect.*; +import compiler.whitebox.CompilerWhiteBoxTest; public class TestArrayCopyNoInitDeopt { diff --git a/hotspot/test/compiler/floatingpoint/TestPow2.java b/hotspot/test/compiler/floatingpoint/TestPow2.java index f46a9a717cc..536c956d3b7 100644 --- a/hotspot/test/compiler/floatingpoint/TestPow2.java +++ b/hotspot/test/compiler/floatingpoint/TestPow2.java @@ -25,7 +25,7 @@ * @test * @bug 8063086 * @summary X^2 special case for C2 yields different result than interpreter - * @library /testlibrary /../../test/lib /compiler/whitebox + * @library /testlibrary /../../test/lib / * @modules java.management * @build TestPow2 * @run main ClassFileInstaller sun.hotspot.WhiteBox @@ -36,6 +36,7 @@ import java.lang.reflect.*; import sun.hotspot.WhiteBox; +import compiler.whitebox.CompilerWhiteBoxTest; public class TestPow2 { diff --git a/hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java b/hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java index 1a547540382..4bd1984f858 100644 --- a/hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java +++ b/hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java @@ -23,10 +23,11 @@ import java.lang.reflect.Executable; import java.util.concurrent.Callable; import java.util.Objects; +import compiler.whitebox.CompilerWhiteBoxTest; /* * @test * @bug 8130832 - * @library /testlibrary /../../test/lib /compiler/whitebox /compiler/testlibrary + * @library /testlibrary /../../test/lib / /compiler/testlibrary * @build IntrinsicAvailableTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestI.java index 04fe2f81115..ed12ae3a4e8 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @library /testlibrary /../../test/lib /compiler/whitebox .. + * @library /testlibrary /../../test/lib / .. * @modules java.base/sun.misc * java.management * @build AddnTestI diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestL.java index b9647cfb27c..76e06a5c799 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @library /testlibrary /../../test/lib /compiler/whitebox .. + * @library /testlibrary /../../test/lib / .. * @modules java.base/sun.misc * java.management * @build AddnTestL diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestI.java index 3a583dfa463..ef6b0a9cf1c 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @library /testlibrary /../../test/lib /compiler/whitebox .. + * @library /testlibrary /../../test/lib / .. * @modules java.base/sun.misc * java.management * @build BlsiTestI diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestL.java index 55696375968..50a21472a0a 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsiTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @library /testlibrary /../../test/lib /compiler/whitebox .. + * @library /testlibrary /../../test/lib / .. * @modules java.base/sun.misc * java.management * @build BlsiTestL diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java index aba4b327829..87f10176945 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @library /testlibrary /../../test/lib /compiler/whitebox .. + * @library /testlibrary /../../test/lib / .. * @modules java.base/sun.misc * java.management * @build BlsmskTestI diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java index b58e7b382d2..5458d8374e0 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @library /testlibrary /../../test/lib /compiler/whitebox .. + * @library /testlibrary /../../test/lib / .. * @modules java.base/sun.misc * java.management * @build BlsmskTestL diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestI.java index 4b3434dc56f..912ae9daf3f 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @library /testlibrary /../../test/lib /compiler/whitebox .. + * @library /testlibrary /../../test/lib / .. * @modules java.base/sun.misc * java.management * @build BlsrTestI diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestL.java index 81b9fa81c44..20e47050c06 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BlsrTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @library /testlibrary /../../test/lib /compiler/whitebox .. + * @library /testlibrary /../../test/lib / .. * @modules java.base/sun.misc * java.management * @build BlsrTestL diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/BmiIntrinsicBase.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/BmiIntrinsicBase.java index c4c307ac3cc..8ecb518c34a 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BmiIntrinsicBase.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BmiIntrinsicBase.java @@ -32,6 +32,7 @@ import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.util.concurrent.Callable; import java.util.function.Function; +import compiler.whitebox.CompilerWhiteBoxTest; public class BmiIntrinsicBase extends CompilerWhiteBoxTest { diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java index dd45d49a3fd..b5cb34fe688 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @library /testlibrary /../../test/lib /compiler/whitebox .. + * @library /testlibrary /../../test/lib / .. * @modules java.base/sun.misc * java.management * @build LZcntTestI diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java index 4515d253aa0..9fa56d31701 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @library /testlibrary /../../test/lib /compiler/whitebox .. + * @library /testlibrary /../../test/lib / .. * @modules java.base/sun.misc * java.management * @build LZcntTestL diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java index 5d078b629f2..b122892be25 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @library /testlibrary /../../test/lib /compiler/whitebox .. + * @library /testlibrary /../../test/lib / .. * @modules java.base/sun.misc * java.management * @build TZcntTestI diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java index 0758a441a2b..a02d29e111c 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @library /testlibrary /../../test/lib /compiler/whitebox .. + * @library /testlibrary /../../test/lib / .. * @modules java.base/sun.misc * java.management * @build TZcntTestL diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java index 99948387c4d..228700ccaf1 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java @@ -23,8 +23,7 @@ /* * @test - * @library /testlibrary /../../test/lib /compiler/whitebox - * /compiler/testlibrary + * @library /testlibrary /../../test/lib / /compiler/testlibrary * @modules java.base/sun.misc * java.management * @build AddExactIntTest diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java index f13cabda852..41bf44a1505 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java @@ -23,8 +23,7 @@ /* * @test - * @library /testlibrary /../../test/lib /compiler/whitebox - * /compiler/testlibrary + * @library /testlibrary /../../test/lib / /compiler/testlibrary * @modules java.base/sun.misc * java.management * @build AddExactLongTest diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java index 1569e13308d..89e742c8fad 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java @@ -23,8 +23,7 @@ /* * @test - * @library /testlibrary /../../test/lib /compiler/whitebox - * /compiler/testlibrary + * @library /testlibrary /../../test/lib / /compiler/testlibrary * @modules java.base/sun.misc * java.management * @build DecrementExactIntTest diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java index 7dc1f329937..2681abfa930 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java @@ -23,8 +23,7 @@ /* * @test - * @library /testlibrary /../../test/lib /compiler/whitebox - * /compiler/testlibrary + * @library /testlibrary /../../test/lib / /compiler/testlibrary * @modules java.base/sun.misc * java.management * @build DecrementExactLongTest diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java index f3b9df23778..1d549816806 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java @@ -23,8 +23,7 @@ /* * @test - * @library /testlibrary /../../test/lib /compiler/whitebox - * /compiler/testlibrary + * @library /testlibrary /../../test/lib / /compiler/testlibrary * @modules java.base/sun.misc * java.management * @build IncrementExactIntTest diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java index da230bbe6f4..7c3102708b7 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java @@ -23,8 +23,7 @@ /* * @test - * @library /testlibrary /../../test/lib /compiler/whitebox - * /compiler/testlibrary + * @library /testlibrary /../../test/lib / /compiler/testlibrary * @modules java.base/sun.misc * java.management * @build IncrementExactLongTest diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java index 1fcd33a7dd1..e271f9fd49f 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java @@ -27,6 +27,7 @@ import intrinsics.Verifier; import java.io.FileOutputStream; import java.lang.reflect.Executable; import java.util.Properties; +import compiler.whitebox.CompilerWhiteBoxTest; public abstract class IntrinsicBase extends CompilerWhiteBoxTest { protected String javaVmName; diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/MathIntrinsic.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/MathIntrinsic.java index 29d5e9916e8..7148a561336 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/MathIntrinsic.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/MathIntrinsic.java @@ -23,6 +23,7 @@ import java.lang.reflect.Executable; import java.util.concurrent.Callable; +import compiler.whitebox.CompilerWhiteBoxTest; public class MathIntrinsic { diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java index f529dfe8fad..67bba360e68 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java @@ -23,8 +23,7 @@ /* * @test - * @library /testlibrary /../../test/lib /compiler/whitebox - * /compiler/testlibrary + * @library /testlibrary /../../test/lib / /compiler/testlibrary * @modules java.base/sun.misc * java.management * @build MultiplyExactIntTest diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java index 0829f1f67f0..2bf372df1bb 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java @@ -23,8 +23,7 @@ /* * @test - * @library /testlibrary /../../test/lib /compiler/whitebox - * /compiler/testlibrary + * @library /testlibrary /../../test/lib / /compiler/testlibrary * @modules java.base/sun.misc * java.management * @build MultiplyExactLongTest diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java index c0f07f51e16..a61c8e03a0a 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java @@ -23,8 +23,7 @@ /* * @test - * @library /testlibrary /../../test/lib /compiler/whitebox - * /compiler/testlibrary + * @library /testlibrary /../../test/lib / /compiler/testlibrary * @modules java.base/sun.misc * java.management * @build NegateExactIntTest diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java index 7c8da0e65cb..27a9436da4e 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java @@ -23,8 +23,7 @@ /* * @test - * @library /testlibrary /../../test/lib /compiler/whitebox - * /compiler/testlibrary + * @library /testlibrary /../../test/lib / /compiler/testlibrary * @modules java.base/sun.misc * java.management * @build NegateExactLongTest diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java index 23f10d69f19..cc3fcb8abc5 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java @@ -23,8 +23,7 @@ /* * @test - * @library /testlibrary /../../test/lib /compiler/whitebox - * /compiler/testlibrary + * @library /testlibrary /../../test/lib / /compiler/testlibrary * @modules java.base/sun.misc * java.management * @build SubtractExactIntTest diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java index cf40b140f9d..a4e218e3945 100644 --- a/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java +++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java @@ -23,8 +23,7 @@ /* * @test - * @library /testlibrary /../../test/lib /compiler/whitebox - * /compiler/testlibrary + * @library /testlibrary /../../test/lib / /compiler/testlibrary * @modules java.base/sun.misc * java.management * @build SubtractExactLongTest diff --git a/hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java b/hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java index eadd8ee7642..6ea8d615c7d 100644 --- a/hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java +++ b/hotspot/test/compiler/rangechecks/TestExplicitRangeChecks.java @@ -25,7 +25,7 @@ * @test * @bug 8073480 * @summary explicit range checks should be recognized by C2 - * @library /testlibrary /../../test/lib /compiler/whitebox + * @library /testlibrary /../../test/lib / * @build TestExplicitRangeChecks * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main ClassFileInstaller jdk.test.lib.Platform @@ -41,6 +41,7 @@ import sun.hotspot.WhiteBox; import sun.hotspot.code.NMethod; import jdk.test.lib.Platform; import sun.misc.Unsafe; +import compiler.whitebox.CompilerWhiteBoxTest; public class TestExplicitRangeChecks { diff --git a/hotspot/test/compiler/rangechecks/TestRangeCheckSmearing.java b/hotspot/test/compiler/rangechecks/TestRangeCheckSmearing.java index e1857fa12f1..dafdee6d306 100644 --- a/hotspot/test/compiler/rangechecks/TestRangeCheckSmearing.java +++ b/hotspot/test/compiler/rangechecks/TestRangeCheckSmearing.java @@ -25,7 +25,7 @@ * @test * @bug 8066103 * @summary C2's range check smearing allows out of bound array accesses - * @library /testlibrary /../../test/lib /compiler/whitebox + * @library /testlibrary /../../test/lib / * @modules java.base/sun.misc * java.management * @build TestRangeCheckSmearing @@ -42,6 +42,7 @@ import java.util.*; import sun.hotspot.WhiteBox; import sun.hotspot.code.NMethod; import jdk.test.lib.Platform; +import compiler.whitebox.CompilerWhiteBoxTest; public class TestRangeCheckSmearing { private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); diff --git a/hotspot/test/compiler/tiered/CompLevelsTest.java b/hotspot/test/compiler/tiered/CompLevelsTest.java index 5c61ba173d7..3aa5ba1d627 100644 --- a/hotspot/test/compiler/tiered/CompLevelsTest.java +++ b/hotspot/test/compiler/tiered/CompLevelsTest.java @@ -26,6 +26,9 @@ * * @author igor.ignatyev@oracle.com */ + +import compiler.whitebox.CompilerWhiteBoxTest; + public abstract class CompLevelsTest extends CompilerWhiteBoxTest { protected CompLevelsTest(TestCase testCase) { super(testCase); diff --git a/hotspot/test/compiler/tiered/ConstantGettersTransitionsTest.java b/hotspot/test/compiler/tiered/ConstantGettersTransitionsTest.java index 3b3271d2938..3cf4080e92b 100644 --- a/hotspot/test/compiler/tiered/ConstantGettersTransitionsTest.java +++ b/hotspot/test/compiler/tiered/ConstantGettersTransitionsTest.java @@ -23,10 +23,11 @@ import java.lang.reflect.Executable; import java.util.concurrent.Callable; +import compiler.whitebox.CompilerWhiteBoxTest; /** * @test ConstantGettersTransitionsTest - * @library /testlibrary /../../test/lib /compiler/whitebox + * @library /testlibrary /../../test/lib / * @modules java.base/sun.misc * java.management * @build TransitionsTestExecutor ConstantGettersTransitionsTest diff --git a/hotspot/test/compiler/tiered/LevelTransitionTest.java b/hotspot/test/compiler/tiered/LevelTransitionTest.java index 26236ea8542..f97900f3de2 100644 --- a/hotspot/test/compiler/tiered/LevelTransitionTest.java +++ b/hotspot/test/compiler/tiered/LevelTransitionTest.java @@ -25,10 +25,12 @@ import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.util.Objects; import java.util.concurrent.Callable; +import compiler.whitebox.CompilerWhiteBoxTest; +import compiler.whitebox.SimpleTestCase; /** * @test LevelTransitionTest - * @library /testlibrary /../../test/lib /compiler/whitebox + * @library /testlibrary /../../test/lib / * @modules java.base/sun.misc * java.management * @ignore 8067651 @@ -36,7 +38,7 @@ import java.util.concurrent.Callable; * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm/timeout=240 -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI -XX:+TieredCompilation - * -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* + * -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCase$Helper::* * -XX:CompileCommand=compileonly,ExtendedTestCase$CompileMethodHolder::* * TransitionsTestExecutor LevelTransitionTest * @summary Test the correctness of compilation level transitions for different methods diff --git a/hotspot/test/compiler/tiered/NonTieredLevelsTest.java b/hotspot/test/compiler/tiered/NonTieredLevelsTest.java index 510d7f6ae47..bacfd79340d 100644 --- a/hotspot/test/compiler/tiered/NonTieredLevelsTest.java +++ b/hotspot/test/compiler/tiered/NonTieredLevelsTest.java @@ -22,17 +22,18 @@ */ import java.util.function.IntPredicate; +import compiler.whitebox.CompilerWhiteBoxTest; /** * @test NonTieredLevelsTest - * @library /testlibrary /../../test/lib /compiler/whitebox + * @library /testlibrary /../../test/lib / * @modules java.management * @build NonTieredLevelsTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:-TieredCompilation * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* + * -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCase$Helper::* * NonTieredLevelsTest * @summary Verify that only one level can be used * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/compiler/tiered/TieredLevelsTest.java b/hotspot/test/compiler/tiered/TieredLevelsTest.java index 92c65c0af59..95d00d60132 100644 --- a/hotspot/test/compiler/tiered/TieredLevelsTest.java +++ b/hotspot/test/compiler/tiered/TieredLevelsTest.java @@ -21,16 +21,18 @@ * questions. */ +import compiler.whitebox.CompilerWhiteBoxTest; + /** * @test TieredLevelsTest - * @library /testlibrary /../../test/lib /compiler/whitebox + * @library /testlibrary /../../test/lib / * @modules java.management * @build TieredLevelsTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+TieredCompilation * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* + * -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCase$Helper::* * TieredLevelsTest * @summary Verify that all levels < 'TieredStopAtLevel' can be used * @author igor.ignatyev@oracle.com diff --git a/hotspot/test/compiler/tiered/TransitionsTestExecutor.java b/hotspot/test/compiler/tiered/TransitionsTestExecutor.java index 432c82a54ed..630bac2b79a 100644 --- a/hotspot/test/compiler/tiered/TransitionsTestExecutor.java +++ b/hotspot/test/compiler/tiered/TransitionsTestExecutor.java @@ -29,6 +29,7 @@ import java.lang.management.RuntimeMXBean; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import compiler.whitebox.CompilerWhiteBoxTest; /** * Executes given test in a separate VM with enabled Tiered Compilation for diff --git a/hotspot/test/compiler/whitebox/ClearMethodStateTest.java b/hotspot/test/compiler/whitebox/ClearMethodStateTest.java index be2cbdd2300..87d033b955f 100644 --- a/hotspot/test/compiler/whitebox/ClearMethodStateTest.java +++ b/hotspot/test/compiler/whitebox/ClearMethodStateTest.java @@ -22,16 +22,17 @@ */ import java.util.function.Function; +import compiler.whitebox.CompilerWhiteBoxTest; /* * @test ClearMethodStateTest * @bug 8006683 8007288 8022832 - * @library /testlibrary /../../test/lib + * @library /testlibrary /../../test/lib / * @modules java.management * @build ClearMethodStateTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* ClearMethodStateTest + * @run main/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCase$Helper::* ClearMethodStateTest * @summary testing of WB::clearMethodState() * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java index 1972b35eb1d..e4d28c7642b 100644 --- a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java +++ b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java @@ -20,10 +20,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package compiler.whitebox; import sun.hotspot.WhiteBox; import sun.hotspot.code.NMethod; - import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Method; @@ -38,19 +38,19 @@ import java.util.function.Function; */ public abstract class CompilerWhiteBoxTest { /** {@code CompLevel::CompLevel_none} -- Interpreter */ - protected static final int COMP_LEVEL_NONE = 0; + public static final int COMP_LEVEL_NONE = 0; /** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */ - protected static final int COMP_LEVEL_ANY = -1; + public static final int COMP_LEVEL_ANY = -1; /** {@code CompLevel::CompLevel_simple} -- C1 */ - protected static final int COMP_LEVEL_SIMPLE = 1; + public static final int COMP_LEVEL_SIMPLE = 1; /** {@code CompLevel::CompLevel_limited_profile} -- C1, invocation & backedge counters */ - protected static final int COMP_LEVEL_LIMITED_PROFILE = 2; + public static final int COMP_LEVEL_LIMITED_PROFILE = 2; /** {@code CompLevel::CompLevel_full_profile} -- C1, invocation & backedge counters + mdo */ - protected static final int COMP_LEVEL_FULL_PROFILE = 3; + public static final int COMP_LEVEL_FULL_PROFILE = 3; /** {@code CompLevel::CompLevel_full_optimization} -- C2 or Shark */ - protected static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; + public static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; /** Maximal value for CompLevel */ - protected static final int COMP_LEVEL_MAX = COMP_LEVEL_FULL_OPTIMIZATION; + public static final int COMP_LEVEL_MAX = COMP_LEVEL_FULL_OPTIMIZATION; /** Instance of WhiteBox */ protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); @@ -312,7 +312,7 @@ public abstract class CompilerWhiteBoxTest { * * @param executable Executable */ - protected static final void waitBackgroundCompilation(Executable executable) { + public static final void waitBackgroundCompilation(Executable executable) { if (!BACKGROUND_COMPILATION) { return; } @@ -441,7 +441,7 @@ public abstract class CompilerWhiteBoxTest { * @return {@code true} if the test should be skipped, * {@code false} otherwise */ - protected static boolean skipOnTieredCompilation(boolean value) { + public static boolean skipOnTieredCompilation(boolean value) { if (value == CompilerWhiteBoxTest.TIERED_COMPILATION) { System.err.println("Test isn't applicable w/ " + (value ? "enabled" : "disabled") @@ -452,256 +452,3 @@ public abstract class CompilerWhiteBoxTest { } } -enum SimpleTestCase implements CompilerWhiteBoxTest.TestCase { - /** constructor test case */ - CONSTRUCTOR_TEST(Helper.CONSTRUCTOR, Helper.CONSTRUCTOR_CALLABLE, false), - /** method test case */ - METHOD_TEST(Helper.METHOD, Helper.METHOD_CALLABLE, false), - /** static method test case */ - STATIC_TEST(Helper.STATIC, Helper.STATIC_CALLABLE, false), - /** OSR constructor test case */ - OSR_CONSTRUCTOR_TEST(Helper.OSR_CONSTRUCTOR, - Helper.OSR_CONSTRUCTOR_CALLABLE, true), - /** OSR method test case */ - OSR_METHOD_TEST(Helper.OSR_METHOD, Helper.OSR_METHOD_CALLABLE, true), - /** OSR static method test case */ - OSR_STATIC_TEST(Helper.OSR_STATIC, Helper.OSR_STATIC_CALLABLE, true); - - private final Executable executable; - private final Callable callable; - private final boolean isOsr; - - private SimpleTestCase(Executable executable, Callable callable, - boolean isOsr) { - this.executable = executable; - this.callable = callable; - this.isOsr = isOsr; - } - - @Override - public Executable getExecutable() { - return executable; - } - - @Override - public Callable getCallable() { - return callable; - } - - @Override - public boolean isOsr() { - return isOsr; - } - - private static class Helper { - - private static final Callable CONSTRUCTOR_CALLABLE - = new Callable() { - @Override - public Integer call() throws Exception { - return new Helper(1337).hashCode(); - } - }; - - private static final Callable METHOD_CALLABLE - = new Callable() { - private final Helper helper = new Helper(); - - @Override - public Integer call() throws Exception { - return helper.method(); - } - }; - - private static final Callable STATIC_CALLABLE - = new Callable() { - @Override - public Integer call() throws Exception { - return staticMethod(); - } - }; - - private static final Callable OSR_CONSTRUCTOR_CALLABLE - = new Callable() { - @Override - public Integer call() throws Exception { - return new Helper(null, CompilerWhiteBoxTest.BACKEDGE_THRESHOLD).hashCode(); - } - }; - - private static final Callable OSR_METHOD_CALLABLE - = new Callable() { - private final Helper helper = new Helper(); - - @Override - public Integer call() throws Exception { - return helper.osrMethod(CompilerWhiteBoxTest.BACKEDGE_THRESHOLD); - } - }; - - private static final Callable OSR_STATIC_CALLABLE - = new Callable() { - @Override - public Integer call() throws Exception { - return osrStaticMethod(CompilerWhiteBoxTest.BACKEDGE_THRESHOLD); - } - }; - - private static final Constructor CONSTRUCTOR; - private static final Constructor OSR_CONSTRUCTOR; - private static final Method METHOD; - private static final Method STATIC; - private static final Method OSR_METHOD; - private static final Method OSR_STATIC; - - static { - try { - CONSTRUCTOR = Helper.class.getDeclaredConstructor(int.class); - } catch (NoSuchMethodException | SecurityException e) { - throw new RuntimeException( - "exception on getting method Helper.(int)", e); - } - try { - OSR_CONSTRUCTOR = Helper.class.getDeclaredConstructor( - Object.class, long.class); - } catch (NoSuchMethodException | SecurityException e) { - throw new RuntimeException( - "exception on getting method Helper.(Object, long)", e); - } - METHOD = getMethod("method"); - STATIC = getMethod("staticMethod"); - OSR_METHOD = getMethod("osrMethod", long.class); - OSR_STATIC = getMethod("osrStaticMethod", long.class); - } - - private static Method getMethod(String name, Class... parameterTypes) { - try { - return Helper.class.getDeclaredMethod(name, parameterTypes); - } catch (NoSuchMethodException | SecurityException e) { - throw new RuntimeException( - "exception on getting method Helper." + name, e); - } - } - - private static int staticMethod() { - return 1138; - } - - private int method() { - return 42; - } - - /** - * Deoptimizes all non-osr versions of the given executable after - * compilation finished. - * - * @param e Executable - * @throws Exception - */ - private static void waitAndDeoptimize(Executable e) { - CompilerWhiteBoxTest.waitBackgroundCompilation(e); - if (WhiteBox.getWhiteBox().isMethodQueuedForCompilation(e)) { - throw new RuntimeException(e + " must not be in queue"); - } - // Deoptimize non-osr versions of executable - WhiteBox.getWhiteBox().deoptimizeMethod(e, false); - } - - /** - * Executes the method multiple times to make sure we have - * enough profiling information before triggering an OSR - * compilation. Otherwise the C2 compiler may add uncommon traps. - * - * @param m Method to be executed - * @return Number of times the method was executed - * @throws Exception - */ - private static int warmup(Method m) throws Exception { - waitAndDeoptimize(m); - Helper helper = new Helper(); - int result = 0; - for (long i = 0; i < CompilerWhiteBoxTest.THRESHOLD; ++i) { - result += (int)m.invoke(helper, 1); - } - // Wait to make sure OSR compilation is not blocked by - // non-OSR compilation in the compile queue - CompilerWhiteBoxTest.waitBackgroundCompilation(m); - return result; - } - - /** - * Executes the constructor multiple times to make sure we - * have enough profiling information before triggering an OSR - * compilation. Otherwise the C2 compiler may add uncommon traps. - * - * @param c Constructor to be executed - * @return Number of times the constructor was executed - * @throws Exception - */ - private static int warmup(Constructor c) throws Exception { - waitAndDeoptimize(c); - int result = 0; - for (long i = 0; i < CompilerWhiteBoxTest.THRESHOLD; ++i) { - result += c.newInstance(null, 1).hashCode(); - } - // Wait to make sure OSR compilation is not blocked by - // non-OSR compilation in the compile queue - CompilerWhiteBoxTest.waitBackgroundCompilation(c); - return result; - } - - private static int osrStaticMethod(long limit) throws Exception { - int result = 0; - if (limit != 1) { - result = warmup(OSR_STATIC); - } - // Trigger osr compilation - for (long i = 0; i < limit; ++i) { - result += staticMethod(); - } - return result; - } - - private int osrMethod(long limit) throws Exception { - int result = 0; - if (limit != 1) { - result = warmup(OSR_METHOD); - } - // Trigger osr compilation - for (long i = 0; i < limit; ++i) { - result += method(); - } - return result; - } - - private final int x; - - // for method and OSR method test case - public Helper() { - x = 0; - } - - // for OSR constructor test case - private Helper(Object o, long limit) throws Exception { - int result = 0; - if (limit != 1) { - result = warmup(OSR_CONSTRUCTOR); - } - // Trigger osr compilation - for (long i = 0; i < limit; ++i) { - result += method(); - } - x = result; - } - - // for constructor test case - private Helper(int x) { - this.x = x; - } - - @Override - public int hashCode() { - return x; - } - } -} diff --git a/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java b/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java index 90169717ab3..84195fd649e 100644 --- a/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java +++ b/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java @@ -21,15 +21,17 @@ * questions. */ +import compiler.whitebox.CompilerWhiteBoxTest; + /* * @test DeoptimizeAllTest * @bug 8006683 8007288 8022832 - * @library /testlibrary /../../test/lib + * @library /testlibrary /../../test/lib / * @modules java.management * @build DeoptimizeAllTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* DeoptimizeAllTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCase$Helper::* DeoptimizeAllTest * @summary testing of WB::deoptimizeAll() * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/compiler/whitebox/DeoptimizeFramesTest.java b/hotspot/test/compiler/whitebox/DeoptimizeFramesTest.java index c7596c797c0..6d4d9fbf3b3 100644 --- a/hotspot/test/compiler/whitebox/DeoptimizeFramesTest.java +++ b/hotspot/test/compiler/whitebox/DeoptimizeFramesTest.java @@ -21,10 +21,12 @@ * questions. */ +import compiler.whitebox.CompilerWhiteBoxTest; + /* * @test DeoptimizeFramesTest * @bug 8028595 - * @library /testlibrary /../../test/lib + * @library /testlibrary /../../test/lib / * @modules java.management * @build DeoptimizeFramesTest * @run main ClassFileInstaller sun.hotspot.WhiteBox diff --git a/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java b/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java index 3b08717b20a..1f57affac1d 100644 --- a/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java +++ b/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java @@ -21,15 +21,17 @@ * questions. */ +import compiler.whitebox.CompilerWhiteBoxTest; + /* * @test DeoptimizeMethodTest * @bug 8006683 8007288 8022832 - * @library /testlibrary /../../test/lib + * @library /testlibrary /../../test/lib / * @modules java.management * @build DeoptimizeMethodTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* DeoptimizeMethodTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCase$Helper::* DeoptimizeMethodTest * @summary testing of WB::deoptimizeMethod() * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/compiler/whitebox/DeoptimizeMultipleOSRTest.java b/hotspot/test/compiler/whitebox/DeoptimizeMultipleOSRTest.java index 54851c4d61d..c90ce730cde 100644 --- a/hotspot/test/compiler/whitebox/DeoptimizeMultipleOSRTest.java +++ b/hotspot/test/compiler/whitebox/DeoptimizeMultipleOSRTest.java @@ -24,11 +24,12 @@ import sun.hotspot.WhiteBox; import java.lang.reflect.Executable; import java.lang.reflect.Method; +import compiler.whitebox.CompilerWhiteBoxTest; /* * @test DeoptimizeMultipleOSRTest * @bug 8061817 - * @library /testlibrary /../../test/lib + * @library /testlibrary /../../test/lib / * @modules java.management * @build DeoptimizeMultipleOSRTest * @run main ClassFileInstaller sun.hotspot.WhiteBox diff --git a/hotspot/test/compiler/whitebox/EnqueueMethodForCompilationTest.java b/hotspot/test/compiler/whitebox/EnqueueMethodForCompilationTest.java index 2560d81fc30..9582922893f 100644 --- a/hotspot/test/compiler/whitebox/EnqueueMethodForCompilationTest.java +++ b/hotspot/test/compiler/whitebox/EnqueueMethodForCompilationTest.java @@ -21,15 +21,17 @@ * questions. */ +import compiler.whitebox.CompilerWhiteBoxTest; + /* * @test EnqueueMethodForCompilationTest * @bug 8006683 8007288 8022832 - * @library /testlibrary /../../test/lib + * @library /testlibrary /../../test/lib / * @modules java.management * @build EnqueueMethodForCompilationTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm/timeout=600 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* EnqueueMethodForCompilationTest + * @run main/othervm/timeout=600 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCase$Helper::* EnqueueMethodForCompilationTest * @summary testing of WB::enqueueMethodForCompilation() * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/compiler/whitebox/ForceNMethodSweepTest.java b/hotspot/test/compiler/whitebox/ForceNMethodSweepTest.java index 742805827da..d9a3c7cc1ec 100644 --- a/hotspot/test/compiler/whitebox/ForceNMethodSweepTest.java +++ b/hotspot/test/compiler/whitebox/ForceNMethodSweepTest.java @@ -30,18 +30,19 @@ import sun.hotspot.code.BlobType; import jdk.test.lib.Asserts; import jdk.test.lib.InfiniteLoop; +import compiler.whitebox.CompilerWhiteBoxTest; /* * @test * @bug 8059624 8064669 - * @library /testlibrary /../../test/lib + * @library /testlibrary /../../test/lib / * @modules java.management * @build ForceNMethodSweepTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:-TieredCompilation -XX:+WhiteBoxAPI - * -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* + * -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCase$Helper::* * -XX:-BackgroundCompilation ForceNMethodSweepTest * @summary testing of WB::forceNMethodSweep */ diff --git a/hotspot/test/compiler/whitebox/GetNMethodTest.java b/hotspot/test/compiler/whitebox/GetNMethodTest.java index 400852f6114..6690f739da3 100644 --- a/hotspot/test/compiler/whitebox/GetNMethodTest.java +++ b/hotspot/test/compiler/whitebox/GetNMethodTest.java @@ -25,16 +25,17 @@ import sun.hotspot.code.BlobType; import sun.hotspot.code.NMethod; import jdk.test.lib.Asserts; +import compiler.whitebox.CompilerWhiteBoxTest; /* * @test GetNMethodTest * @bug 8038240 - * @library /testlibrary /../../test/lib + * @library /testlibrary /../../test/lib / * @modules java.management * @build GetNMethodTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* GetNMethodTest + * @run main/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCase$Helper::* GetNMethodTest * @summary testing of WB::getNMethod() * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java index 9b22967f6fb..46625139352 100644 --- a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java +++ b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java @@ -24,7 +24,7 @@ /* * @test IsMethodCompilableTest * @bug 8007270 8006683 8007288 8022832 - * @library /testlibrary /../../test/lib + * @library /testlibrary /../../test/lib / * @modules java.base/sun.misc * java.management * @build jdk.test.lib.* sun.hotspot.WhiteBox @@ -32,12 +32,13 @@ * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ClassFileInstaller jdk.test.lib.Platform - * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -Xmixed -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:PerMethodRecompilationCutoff=3 -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest + * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -Xmixed -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:PerMethodRecompilationCutoff=3 -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCase$Helper::* IsMethodCompilableTest * @summary testing of WB::isMethodCompilable() * @author igor.ignatyev@oracle.com */ import jdk.test.lib.Platform; +import compiler.whitebox.CompilerWhiteBoxTest; public class IsMethodCompilableTest extends CompilerWhiteBoxTest { /** diff --git a/hotspot/test/compiler/whitebox/LockCompilationTest.java b/hotspot/test/compiler/whitebox/LockCompilationTest.java index 60703f04dcd..75764f42995 100644 --- a/hotspot/test/compiler/whitebox/LockCompilationTest.java +++ b/hotspot/test/compiler/whitebox/LockCompilationTest.java @@ -24,12 +24,12 @@ /* * @test LockCompilationTest * @bug 8059624 - * @library /testlibrary /../../test/lib + * @library /testlibrary /../../test/lib / * @modules java.management * @build LockCompilationTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm/timeout=600 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* LockCompilationTest + * @run main/othervm/timeout=600 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCase$Helper::* LockCompilationTest * @summary testing of WB::lock/unlockCompilation() */ @@ -37,7 +37,7 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; - +import compiler.whitebox.CompilerWhiteBoxTest; import jdk.test.lib.Asserts; public class LockCompilationTest extends CompilerWhiteBoxTest { diff --git a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java index faac33515d4..860fe0c1d82 100644 --- a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java +++ b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java @@ -21,15 +21,17 @@ * questions. */ +import compiler.whitebox.CompilerWhiteBoxTest; + /* * @test MakeMethodNotCompilableTest * @bug 8012322 8006683 8007288 8022832 - * @library /testlibrary /../../test/lib + * @library /testlibrary /../../test/lib / * @modules java.management * @build MakeMethodNotCompilableTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* MakeMethodNotCompilableTest + * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCase$Helper::* MakeMethodNotCompilableTest * @summary testing of WB::makeMethodNotCompilable() * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/compiler/whitebox/SetDontInlineMethodTest.java b/hotspot/test/compiler/whitebox/SetDontInlineMethodTest.java index 1638a5eff28..3b1068e7120 100644 --- a/hotspot/test/compiler/whitebox/SetDontInlineMethodTest.java +++ b/hotspot/test/compiler/whitebox/SetDontInlineMethodTest.java @@ -21,15 +21,17 @@ * questions. */ +import compiler.whitebox.CompilerWhiteBoxTest; + /* * @test SetDontInlineMethodTest * @bug 8006683 8007288 8022832 - * @library /testlibrary /../../test/lib + * @library /testlibrary /../../test/lib / * @modules java.management * @build SetDontInlineMethodTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* SetDontInlineMethodTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCase$Helper::* SetDontInlineMethodTest * @summary testing of WB::testSetDontInlineMethod() * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/compiler/whitebox/SetForceInlineMethodTest.java b/hotspot/test/compiler/whitebox/SetForceInlineMethodTest.java index a9e19915927..4cf991e8b57 100644 --- a/hotspot/test/compiler/whitebox/SetForceInlineMethodTest.java +++ b/hotspot/test/compiler/whitebox/SetForceInlineMethodTest.java @@ -21,15 +21,17 @@ * questions. */ +import compiler.whitebox.CompilerWhiteBoxTest; + /* * @test SetForceInlineMethodTest * @bug 8006683 8007288 8022832 - * @library /testlibrary /../../test/lib + * @library /testlibrary /../../test/lib / * @modules java.management * @build SetForceInlineMethodTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* SetForceInlineMethodTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCase$Helper::* SetForceInlineMethodTest * @summary testing of WB::testSetForceInlineMethod() * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/compiler/whitebox/SimpleTestCase.java b/hotspot/test/compiler/whitebox/SimpleTestCase.java new file mode 100644 index 00000000000..76954acf20d --- /dev/null +++ b/hotspot/test/compiler/whitebox/SimpleTestCase.java @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.whitebox; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.util.concurrent.Callable; +import sun.hotspot.WhiteBox; + +public enum SimpleTestCase implements CompilerWhiteBoxTest.TestCase { + /** constructor test case */ + CONSTRUCTOR_TEST(Helper.CONSTRUCTOR, Helper.CONSTRUCTOR_CALLABLE, false), + /** method test case */ + METHOD_TEST(Helper.METHOD, Helper.METHOD_CALLABLE, false), + /** static method test case */ + STATIC_TEST(Helper.STATIC, Helper.STATIC_CALLABLE, false), + /** OSR constructor test case */ + OSR_CONSTRUCTOR_TEST(Helper.OSR_CONSTRUCTOR, + Helper.OSR_CONSTRUCTOR_CALLABLE, true), + /** OSR method test case */ + OSR_METHOD_TEST(Helper.OSR_METHOD, Helper.OSR_METHOD_CALLABLE, true), + /** OSR static method test case */ + OSR_STATIC_TEST(Helper.OSR_STATIC, Helper.OSR_STATIC_CALLABLE, true); + + private final Executable executable; + private final Callable callable; + private final boolean isOsr; + + private SimpleTestCase(Executable executable, Callable callable, + boolean isOsr) { + this.executable = executable; + this.callable = callable; + this.isOsr = isOsr; + } + + @Override + public Executable getExecutable() { + return executable; + } + + @Override + public Callable getCallable() { + return callable; + } + + @Override + public boolean isOsr() { + return isOsr; + } + + private static class Helper { + + private static final Callable CONSTRUCTOR_CALLABLE + = new Callable() { + @Override + public Integer call() throws Exception { + return new Helper(1337).hashCode(); + } + }; + + private static final Callable METHOD_CALLABLE + = new Callable() { + private final Helper helper = new Helper(); + + @Override + public Integer call() throws Exception { + return helper.method(); + } + }; + + private static final Callable STATIC_CALLABLE + = new Callable() { + @Override + public Integer call() throws Exception { + return staticMethod(); + } + }; + + private static final Callable OSR_CONSTRUCTOR_CALLABLE + = new Callable() { + @Override + public Integer call() throws Exception { + return new Helper(null, CompilerWhiteBoxTest.BACKEDGE_THRESHOLD).hashCode(); + } + }; + + private static final Callable OSR_METHOD_CALLABLE + = new Callable() { + private final Helper helper = new Helper(); + + @Override + public Integer call() throws Exception { + return helper.osrMethod(CompilerWhiteBoxTest.BACKEDGE_THRESHOLD); + } + }; + + private static final Callable OSR_STATIC_CALLABLE + = new Callable() { + @Override + public Integer call() throws Exception { + return osrStaticMethod(CompilerWhiteBoxTest.BACKEDGE_THRESHOLD); + } + }; + + private static final Constructor CONSTRUCTOR; + private static final Constructor OSR_CONSTRUCTOR; + private static final Method METHOD; + private static final Method STATIC; + private static final Method OSR_METHOD; + private static final Method OSR_STATIC; + + static { + try { + CONSTRUCTOR = Helper.class.getDeclaredConstructor(int.class); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException( + "exception on getting method Helper.(int)", e); + } + try { + OSR_CONSTRUCTOR = Helper.class.getDeclaredConstructor( + Object.class, long.class); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException( + "exception on getting method Helper.(Object, long)", e); + } + METHOD = getMethod("method"); + STATIC = getMethod("staticMethod"); + OSR_METHOD = getMethod("osrMethod", long.class); + OSR_STATIC = getMethod("osrStaticMethod", long.class); + } + + private static Method getMethod(String name, Class... parameterTypes) { + try { + return Helper.class.getDeclaredMethod(name, parameterTypes); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException( + "exception on getting method Helper." + name, e); + } + } + + private static int staticMethod() { + return 1138; + } + + private int method() { + return 42; + } + + /** + * Deoptimizes all non-osr versions of the given executable after + * compilation finished. + * + * @param e Executable + * @throws Exception + */ + private static void waitAndDeoptimize(Executable e) { + CompilerWhiteBoxTest.waitBackgroundCompilation(e); + if (WhiteBox.getWhiteBox().isMethodQueuedForCompilation(e)) { + throw new RuntimeException(e + " must not be in queue"); + } + // Deoptimize non-osr versions of executable + WhiteBox.getWhiteBox().deoptimizeMethod(e, false); + } + + /** + * Executes the method multiple times to make sure we have + * enough profiling information before triggering an OSR + * compilation. Otherwise the C2 compiler may add uncommon traps. + * + * @param m Method to be executed + * @return Number of times the method was executed + * @throws Exception + */ + private static int warmup(Method m) throws Exception { + waitAndDeoptimize(m); + Helper helper = new Helper(); + int result = 0; + for (long i = 0; i < CompilerWhiteBoxTest.THRESHOLD; ++i) { + result += (int)m.invoke(helper, 1); + } + // Wait to make sure OSR compilation is not blocked by + // non-OSR compilation in the compile queue + CompilerWhiteBoxTest.waitBackgroundCompilation(m); + return result; + } + + /** + * Executes the constructor multiple times to make sure we + * have enough profiling information before triggering an OSR + * compilation. Otherwise the C2 compiler may add uncommon traps. + * + * @param c Constructor to be executed + * @return Number of times the constructor was executed + * @throws Exception + */ + private static int warmup(Constructor c) throws Exception { + waitAndDeoptimize(c); + int result = 0; + for (long i = 0; i < CompilerWhiteBoxTest.THRESHOLD; ++i) { + result += c.newInstance(null, 1).hashCode(); + } + // Wait to make sure OSR compilation is not blocked by + // non-OSR compilation in the compile queue + CompilerWhiteBoxTest.waitBackgroundCompilation(c); + return result; + } + + private static int osrStaticMethod(long limit) throws Exception { + int result = 0; + if (limit != 1) { + result = warmup(OSR_STATIC); + } + // Trigger osr compilation + for (long i = 0; i < limit; ++i) { + result += staticMethod(); + } + return result; + } + + private int osrMethod(long limit) throws Exception { + int result = 0; + if (limit != 1) { + result = warmup(OSR_METHOD); + } + // Trigger osr compilation + for (long i = 0; i < limit; ++i) { + result += method(); + } + return result; + } + + private final int x; + + // for method and OSR method test case + public Helper() { + x = 0; + } + + // for OSR constructor test case + private Helper(Object o, long limit) throws Exception { + int result = 0; + if (limit != 1) { + result = warmup(OSR_CONSTRUCTOR); + } + // Trigger osr compilation + for (long i = 0; i < limit; ++i) { + result += method(); + } + x = result; + } + + // for constructor test case + private Helper(int x) { + this.x = x; + } + + @Override + public int hashCode() { + return x; + } + } +} From 8d1f664989d6a731b598a6a2a2725da7d314bbe4 Mon Sep 17 00:00:00 2001 From: Dmitrij Pochepko Date: Fri, 6 Nov 2015 15:07:00 +0300 Subject: [PATCH 014/260] 8141552: [TESTBUG] compiler/jvmci/events/JvmciNotifyInstallEventTest failed after jvmci refresh Fixed test bug, which used same CompilationResult object instance in 2 installCode calls Reviewed-by: iignatyev, twisti --- .../test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java index 7ad73d87912..89a81b19990 100644 --- a/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java +++ b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java @@ -111,6 +111,8 @@ public class JvmciNotifyInstallEventTest implements HotSpotVMEventListener { Asserts.assertEQ(gotInstallNotification, 1, "Got unexpected event count after 1st install attempt"); // since "empty" compilation result is ok, a second attempt should be ok + compResult = new CompilationResult(METHOD_NAME); // create another instance with fresh state + compResult.setTotalFrameSize(0); codeCache.installCode(compRequest, compResult, /* installedCode = */ null, /* speculationLog = */ null, /* isDefault = */ false); Asserts.assertEQ(gotInstallNotification, 2, From 5d86db4b6688d4783b8d85e1b80e46706b5450c9 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 9 Nov 2015 11:35:44 +0100 Subject: [PATCH 015/260] 8067378: Add segmented code heaps info into jfr events: vm/code_cache/stats and vm/code_cache/config Added code heap specific information to code cache JFR events. Reviewed-by: twisti, mgronlun --- hotspot/src/share/vm/code/codeCache.cpp | 89 ++++++++++++++++++------ hotspot/src/share/vm/code/codeCache.hpp | 24 ++++--- hotspot/src/share/vm/code/nmethod.cpp | 2 +- hotspot/src/share/vm/memory/heap.cpp | 7 +- hotspot/src/share/vm/memory/heap.hpp | 15 +++- hotspot/src/share/vm/runtime/sweeper.cpp | 4 +- 6 files changed, 104 insertions(+), 37 deletions(-) diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index 94552fa7872..1114d24a37c 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -133,13 +133,9 @@ class CodeBlob_sizes { address CodeCache::_low_bound = 0; address CodeCache::_high_bound = 0; -int CodeCache::_number_of_blobs = 0; -int CodeCache::_number_of_adapters = 0; -int CodeCache::_number_of_nmethods = 0; int CodeCache::_number_of_nmethods_with_dependencies = 0; bool CodeCache::_needs_cache_clean = false; nmethod* CodeCache::_scavenge_root_nmethods = NULL; -int CodeCache::_codemem_full_count = 0; // Initialize array of CodeHeaps GrowableArray* CodeCache::_heaps = new(ResourceObj::C_HEAP, mtCode) GrowableArray (CodeBlobType::All, true); @@ -420,42 +416,41 @@ CodeBlob* CodeCache::allocate(int size, int code_blob_type, bool strict) { } } print_trace("allocation", cb, size); - _number_of_blobs++; return cb; } void CodeCache::free(CodeBlob* cb) { assert_locked_or_safepoint(CodeCache_lock); - + CodeHeap* heap = get_code_heap(cb); print_trace("free", cb); if (cb->is_nmethod()) { - _number_of_nmethods--; + heap->set_nmethod_count(heap->nmethod_count() - 1); if (((nmethod *)cb)->has_dependencies()) { _number_of_nmethods_with_dependencies--; } } if (cb->is_adapter_blob()) { - _number_of_adapters--; + heap->set_adapter_count(heap->adapter_count() - 1); } - _number_of_blobs--; // Get heap for given CodeBlob and deallocate get_code_heap(cb)->deallocate(cb); - assert(_number_of_blobs >= 0, "sanity check"); + assert(heap->blob_count() >= 0, "sanity check"); } void CodeCache::commit(CodeBlob* cb) { // this is called by nmethod::nmethod, which must already own CodeCache_lock assert_locked_or_safepoint(CodeCache_lock); + CodeHeap* heap = get_code_heap(cb); if (cb->is_nmethod()) { - _number_of_nmethods++; + heap->set_nmethod_count(heap->nmethod_count() + 1); if (((nmethod *)cb)->has_dependencies()) { _number_of_nmethods_with_dependencies++; } } if (cb->is_adapter_blob()) { - _number_of_adapters++; + heap->set_adapter_count(heap->adapter_count() + 1); } // flush the hardware I-cache @@ -774,6 +769,55 @@ void CodeCache::verify_oops() { } } +int CodeCache::blob_count(int code_blob_type) { + CodeHeap* heap = get_code_heap(code_blob_type); + return (heap != NULL) ? heap->blob_count() : 0; +} + +int CodeCache::blob_count() { + int count = 0; + FOR_ALL_HEAPS(heap) { + count += (*heap)->blob_count(); + } + return count; +} + +int CodeCache::nmethod_count(int code_blob_type) { + CodeHeap* heap = get_code_heap(code_blob_type); + return (heap != NULL) ? heap->nmethod_count() : 0; +} + +int CodeCache::nmethod_count() { + int count = 0; + FOR_ALL_HEAPS(heap) { + count += (*heap)->nmethod_count(); + } + return count; +} + +int CodeCache::adapter_count(int code_blob_type) { + CodeHeap* heap = get_code_heap(code_blob_type); + return (heap != NULL) ? heap->adapter_count() : 0; +} + +int CodeCache::adapter_count() { + int count = 0; + FOR_ALL_HEAPS(heap) { + count += (*heap)->adapter_count(); + } + return count; +} + +address CodeCache::low_bound(int code_blob_type) { + CodeHeap* heap = get_code_heap(code_blob_type); + return (heap != NULL) ? (address)heap->low_boundary() : NULL; +} + +address CodeCache::high_bound(int code_blob_type) { + CodeHeap* heap = get_code_heap(code_blob_type); + return (heap != NULL) ? (address)heap->high_boundary() : NULL; +} + size_t CodeCache::capacity() { size_t cap = 0; FOR_ALL_HEAPS(heap) { @@ -863,6 +907,9 @@ void CodeCache::initialize() { initialize_heaps(); } else { // Use a single code heap + FLAG_SET_ERGO(uintx, NonNMethodCodeHeapSize, 0); + FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, 0); + FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, 0); ReservedCodeSpace rs = reserve_heap_memory(ReservedCodeCacheSize); add_heap(rs, "CodeCache", CodeBlobType::All); } @@ -1104,9 +1151,8 @@ void CodeCache::report_codemem_full(int code_blob_type, bool print) { CodeHeap* heap = get_code_heap(code_blob_type); assert(heap != NULL, "heap is null"); - if (!heap->was_full() || print) { + if ((heap->full_count() == 0) || print) { // Not yet reported for this heap, report - heap->report_full(); if (SegmentedCodeCache) { warning("%s is full. Compiler has been disabled.", get_code_heap_name(code_blob_type)); warning("Try increasing the code heap size using -XX:%s=", get_code_heap_flag_name(code_blob_type)); @@ -1125,18 +1171,19 @@ void CodeCache::report_codemem_full(int code_blob_type, bool print) { tty->print("%s", s.as_string()); } - _codemem_full_count++; + heap->report_full(); + EventCodeCacheFull event; if (event.should_commit()) { event.set_codeBlobType((u1)code_blob_type); event.set_startAddress((u8)heap->low_boundary()); event.set_commitedTopAddress((u8)heap->high()); event.set_reservedTopAddress((u8)heap->high_boundary()); - event.set_entryCount(nof_blobs()); - event.set_methodCount(nof_nmethods()); - event.set_adaptorCount(nof_adapters()); + event.set_entryCount(heap->blob_count()); + event.set_methodCount(heap->nmethod_count()); + event.set_adaptorCount(heap->adapter_count()); event.set_unallocatedCapacity(heap->unallocated_capacity()/K); - event.set_fullCount(_codemem_full_count); + event.set_fullCount(heap->full_count()); event.commit(); } } @@ -1360,7 +1407,7 @@ void CodeCache::print_summary(outputStream* st, bool detailed) { if (detailed) { st->print_cr(" total_blobs=" UINT32_FORMAT " nmethods=" UINT32_FORMAT " adapters=" UINT32_FORMAT, - nof_blobs(), nof_nmethods(), nof_adapters()); + blob_count(), nmethod_count(), adapter_count()); st->print_cr(" compilation: %s", CompileBroker::should_compile_new_jobs() ? "enabled" : Arguments::mode() == Arguments::_int ? "disabled (interpreter mode)" : @@ -1392,6 +1439,6 @@ void CodeCache::print_layout(outputStream* st) { void CodeCache::log_state(outputStream* st) { st->print(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'" " adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", - nof_blobs(), nof_nmethods(), nof_adapters(), + blob_count(), nmethod_count(), adapter_count(), unallocated_capacity()); } diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp index 05a5ab12605..30900e948ea 100644 --- a/hotspot/src/share/vm/code/codeCache.hpp +++ b/hotspot/src/share/vm/code/codeCache.hpp @@ -85,13 +85,9 @@ class CodeCache : AllStatic { static address _low_bound; // Lower bound of CodeHeap addresses static address _high_bound; // Upper bound of CodeHeap addresses - static int _number_of_blobs; // Total number of CodeBlobs in the cache - static int _number_of_adapters; // Total number of Adapters in the cache - static int _number_of_nmethods; // Total number of nmethods in the cache static int _number_of_nmethods_with_dependencies; // Total number of nmethods with dependencies static bool _needs_cache_clean; // True if inline caches of the nmethods needs to be flushed static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link() - static int _codemem_full_count; // Number of times a CodeHeap in the cache was full static void mark_scavenge_root_nmethods() PRODUCT_RETURN; static void verify_perm_nmethods(CodeBlobClosure* f_or_null) PRODUCT_RETURN; @@ -104,7 +100,6 @@ class CodeCache : AllStatic { static CodeHeap* get_code_heap(int code_blob_type); // Returns the CodeHeap for the given CodeBlobType // Returns the name of the VM option to set the size of the corresponding CodeHeap static const char* get_code_heap_flag_name(int code_blob_type); - static bool heap_available(int code_blob_type); // Returns true if an own CodeHeap for the given CodeBlobType is available static size_t heap_alignment(); // Returns the alignment of the CodeHeaps in bytes static ReservedCodeSpace reserve_heap_memory(size_t size); // Reserves one continuous chunk of memory for the CodeHeaps @@ -139,9 +134,12 @@ class CodeCache : AllStatic { static CodeBlob* find_blob_unsafe(void* start); // Same as find_blob but does not fail if looking up a zombie method static nmethod* find_nmethod(void* start); // Returns the nmethod containing the given address - static int nof_blobs() { return _number_of_blobs; } // Returns the total number of CodeBlobs in the cache - static int nof_adapters() { return _number_of_adapters; } // Returns the total number of Adapters in the cache - static int nof_nmethods() { return _number_of_nmethods; } // Returns the total number of nmethods in the cache + static int blob_count(); // Returns the total number of CodeBlobs in the cache + static int blob_count(int code_blob_type); + static int adapter_count(); // Returns the total number of Adapters in the cache + static int adapter_count(int code_blob_type); + static int nmethod_count(); // Returns the total number of nmethods in the cache + static int nmethod_count(int code_blob_type); // GC support static void gc_epilogue(); @@ -177,7 +175,9 @@ class CodeCache : AllStatic { // The full limits of the codeCache static address low_bound() { return _low_bound; } + static address low_bound(int code_blob_type); static address high_bound() { return _high_bound; } + static address high_bound(int code_blob_type); // Profiling static size_t capacity(); @@ -191,6 +191,9 @@ class CodeCache : AllStatic { static void set_needs_cache_clean(bool v) { _needs_cache_clean = v; } static void clear_inline_caches(); // clear all inline caches + // Returns true if an own CodeHeap for the given CodeBlobType is available + static bool heap_available(int code_blob_type); + // Returns the CodeBlobType for the given nmethod static int get_code_blob_type(nmethod* nm) { return get_code_heap(nm)->code_blob_type(); @@ -239,7 +242,10 @@ class CodeCache : AllStatic { // tells how many nmethods have dependencies static int number_of_nmethods_with_dependencies(); - static int get_codemem_full_count() { return _codemem_full_count; } + static int get_codemem_full_count(int code_blob_type) { + CodeHeap* heap = get_code_heap(code_blob_type); + return (heap != NULL) ? heap->full_count() : 0; + } }; diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 6c9a8234b87..bdf7bd8fb19 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -1547,7 +1547,7 @@ void nmethod::flush() { if (PrintMethodFlushing) { tty->print_cr("*flushing nmethod %3d/" INTPTR_FORMAT ". Live blobs:" UINT32_FORMAT "/Free CodeCache:" SIZE_FORMAT "Kb", - _compile_id, p2i(this), CodeCache::nof_blobs(), + _compile_id, p2i(this), CodeCache::blob_count(), CodeCache::unallocated_capacity(CodeCache::get_code_blob_type(this))/1024); } diff --git a/hotspot/src/share/vm/memory/heap.cpp b/hotspot/src/share/vm/memory/heap.cpp index 2c4a661e359..1910ed49e18 100644 --- a/hotspot/src/share/vm/memory/heap.cpp +++ b/hotspot/src/share/vm/memory/heap.cpp @@ -47,7 +47,10 @@ CodeHeap::CodeHeap(const char* name, const int code_blob_type) _freelist_segments = 0; _freelist_length = 0; _max_allocated_capacity = 0; - _was_full = false; + _blob_count = 0; + _nmethod_count = 0; + _adapter_count = 0; + _full_count = 0; } @@ -185,6 +188,7 @@ void* CodeHeap::allocate(size_t instance_size) { assert(!block->free(), "must be marked free"); DEBUG_ONLY(memset((void*)block->allocated_space(), badCodeHeapNewVal, instance_size)); _max_allocated_capacity = MAX2(_max_allocated_capacity, allocated_capacity()); + _blob_count++; return block->allocated_space(); } @@ -198,6 +202,7 @@ void* CodeHeap::allocate(size_t instance_size) { _next_segment += number_of_segments; DEBUG_ONLY(memset((void *)b->allocated_space(), badCodeHeapNewVal, instance_size)); _max_allocated_capacity = MAX2(_max_allocated_capacity, allocated_capacity()); + _blob_count++; return b->allocated_space(); } else { return NULL; diff --git a/hotspot/src/share/vm/memory/heap.hpp b/hotspot/src/share/vm/memory/heap.hpp index 6f06e94f202..a34cd12ed85 100644 --- a/hotspot/src/share/vm/memory/heap.hpp +++ b/hotspot/src/share/vm/memory/heap.hpp @@ -100,7 +100,11 @@ class CodeHeap : public CHeapObj { const char* _name; // Name of the CodeHeap const int _code_blob_type; // CodeBlobType it contains - bool _was_full; // True if the code heap was full + int _blob_count; // Number of CodeBlobs + int _nmethod_count; // Number of nmethods + int _adapter_count; // Number of adapters + int _full_count; // Number of times the code heap was full + enum { free_sentinel = 0xFF }; @@ -179,8 +183,13 @@ class CodeHeap : public CHeapObj { // Debugging / Profiling const char* name() const { return _name; } - bool was_full() { return _was_full; } - void report_full() { _was_full = true; } + int blob_count() { return _blob_count; } + int nmethod_count() { return _nmethod_count; } + void set_nmethod_count(int count) { _nmethod_count = count; } + int adapter_count() { return _adapter_count; } + void set_adapter_count(int count) { _adapter_count = count; } + int full_count() { return _full_count; } + void report_full() { _full_count++; } private: size_t heap_unallocated_capacity() const; diff --git a/hotspot/src/share/vm/runtime/sweeper.cpp b/hotspot/src/share/vm/runtime/sweeper.cpp index fad5edf0f9a..5a902266205 100644 --- a/hotspot/src/share/vm/runtime/sweeper.cpp +++ b/hotspot/src/share/vm/runtime/sweeper.cpp @@ -297,7 +297,7 @@ void NMethodSweeper::force_sweep() { void NMethodSweeper::handle_safepoint_request() { if (SafepointSynchronize::is_synchronizing()) { if (PrintMethodFlushing && Verbose) { - tty->print_cr("### Sweep at %d out of %d, yielding to safepoint", _seen, CodeCache::nof_nmethods()); + tty->print_cr("### Sweep at %d out of %d, yielding to safepoint", _seen, CodeCache::nmethod_count()); } MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); @@ -401,7 +401,7 @@ void NMethodSweeper::sweep_code_cache() { int flushed_c2_count = 0; if (PrintMethodFlushing && Verbose) { - tty->print_cr("### Sweep at %d out of %d", _seen, CodeCache::nof_nmethods()); + tty->print_cr("### Sweep at %d out of %d", _seen, CodeCache::nmethod_count()); } int swept_count = 0; From e86e38619e591a9e767659af4b2b0bbd861f3275 Mon Sep 17 00:00:00 2001 From: Michael C Berg Date: Mon, 9 Nov 2015 11:26:41 -0800 Subject: [PATCH 016/260] 8140779: Code generation fixes for avx512 Assembler refactoring. Abstract away instruction attributes. Reviewed-by: kvn, roland, iveresov --- hotspot/src/cpu/aarch64/vm/aarch64.ad | 71 +- .../src/cpu/aarch64/vm/c2_globals_aarch64.hpp | 1 + hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp | 1 + hotspot/src/cpu/ppc/vm/ppc.ad | 25 +- hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp | 1 + hotspot/src/cpu/sparc/vm/sparc.ad | 21 +- hotspot/src/cpu/x86/vm/assembler_x86.cpp | 2830 ++++++++-------- hotspot/src/cpu/x86/vm/assembler_x86.hpp | 324 +- .../src/cpu/x86/vm/c1_LIRAssembler_x86.cpp | 4 +- hotspot/src/cpu/x86/vm/c2_globals_x86.hpp | 1 + hotspot/src/cpu/x86/vm/c2_init_x86.cpp | 2 - hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp | 923 ++++- hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp | 48 +- .../src/cpu/x86/vm/sharedRuntime_x86_32.cpp | 41 +- .../src/cpu/x86/vm/sharedRuntime_x86_64.cpp | 178 +- .../src/cpu/x86/vm/stubGenerator_x86_64.cpp | 4 +- hotspot/src/cpu/x86/vm/vm_version_x86.cpp | 2 +- hotspot/src/cpu/x86/vm/vm_version_x86.hpp | 16 + hotspot/src/cpu/x86/vm/x86.ad | 2991 +++++++++++++---- hotspot/src/cpu/x86/vm/x86_32.ad | 6 +- hotspot/src/cpu/x86/vm/x86_64.ad | 8 +- hotspot/src/share/vm/opto/c2_globals.hpp | 6 +- hotspot/src/share/vm/opto/matcher.hpp | 4 + hotspot/src/share/vm/opto/superword.cpp | 5 +- hotspot/src/share/vm/opto/vectornode.cpp | 2 +- 25 files changed, 4872 insertions(+), 2643 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index 0861f782775..802db1b24b0 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -1079,10 +1079,10 @@ source %{ // and for a volatile write we need // // stlr - // + // // Alternatively, we can implement them by pairing a normal // load/store with a memory barrier. For a volatile read we need - // + // // ldr // dmb ishld // @@ -1240,7 +1240,7 @@ source %{ // Alternatively, we can elide generation of the dmb instructions // and plant the alternative CompareAndSwap macro-instruction // sequence (which uses ldaxr). - // + // // Of course, the above only applies when we see these signature // configurations. We still want to plant dmb instructions in any // other cases where we may see a MemBarAcquire, MemBarRelease or @@ -1367,7 +1367,7 @@ source %{ opcode = parent->Opcode(); return opcode == Op_MemBarRelease; } - + // 2) card mark detection helper // helper predicate which can be used to detect a volatile membar @@ -1383,7 +1383,7 @@ source %{ // true // // iii) the node's Mem projection feeds a StoreCM node. - + bool is_card_mark_membar(const MemBarNode *barrier) { if (!UseG1GC && !(UseConcMarkSweepGC && UseCondCardMark)) { @@ -1402,7 +1402,7 @@ source %{ return true; } } - + return false; } @@ -1430,7 +1430,7 @@ source %{ // where // || and \\ represent Ctl and Mem feeds via Proj nodes // | \ and / indicate further routing of the Ctl and Mem feeds - // + // // this is the graph we see for non-object stores. however, for a // volatile Object store (StoreN/P) we may see other nodes below the // leading membar because of the need for a GC pre- or post-write @@ -1592,7 +1592,7 @@ source %{ // ordering but neither will a releasing store (stlr). The latter // guarantees that the object put is visible but does not guarantee // that writes by other threads have also been observed. - // + // // So, returning to the task of translating the object put and the // leading/trailing membar nodes: what do the non-normal node graph // look like for these 2 special cases? and how can we determine the @@ -1731,7 +1731,7 @@ source %{ // | | | | // C | M | M | M | // \ | | / - // . . . + // . . . // (post write subtree elided) // . . . // C \ M / @@ -1812,12 +1812,12 @@ source %{ // | | | / / // | Region . . . Phi[M] _____/ // | / | / - // | | / + // | | / // | . . . . . . | / // | / | / // Region | | Phi[M] // | | | / Bot - // \ MergeMem + // \ MergeMem // \ / // MemBarVolatile // @@ -1858,7 +1858,7 @@ source %{ // to a trailing barrier via a MergeMem. That feed is either direct // (for CMS) or via 2 or 3 Phi nodes merging the leading barrier // memory flow (for G1). - // + // // The predicates controlling generation of instructions for store // and barrier nodes employ a few simple helper functions (described // below) which identify the presence or absence of all these @@ -2112,8 +2112,8 @@ source %{ x = x->in(MemNode::Memory); } else { // the merge should get its Bottom mem feed from the leading membar - x = mm->in(Compile::AliasIdxBot); - } + x = mm->in(Compile::AliasIdxBot); + } // ensure this is a non control projection if (!x->is_Proj() || x->is_CFG()) { @@ -2190,12 +2190,12 @@ source %{ // . . . // | // MemBarVolatile (card mark) - // | | + // | | // | StoreCM // | | // | . . . - // Bot | / - // MergeMem + // Bot | / + // MergeMem // | // | // MemBarVolatile {trailing} @@ -2203,10 +2203,10 @@ source %{ // 2) // MemBarRelease/CPUOrder (leading) // | - // | + // | // |\ . . . - // | \ | - // | \ MemBarVolatile (card mark) + // | \ | + // | \ MemBarVolatile (card mark) // | \ | | // \ \ | StoreCM . . . // \ \ | @@ -2231,7 +2231,7 @@ source %{ // | \ \ | StoreCM . . . // | \ \ | // \ \ Phi - // \ \ / + // \ \ / // \ Phi // \ / // Phi . . . @@ -2506,7 +2506,7 @@ bool unnecessary_acquire(const Node *barrier) return (x->is_Load() && x->as_Load()->is_acquire()); } - + // now check for an unsafe volatile get // need to check for @@ -2644,7 +2644,7 @@ bool needs_acquiring_load(const Node *n) } membar = child_membar(membar); - + if (!membar || !membar->Opcode() == Op_MemBarCPUOrder) { return false; } @@ -2703,7 +2703,7 @@ bool unnecessary_volatile(const Node *n) // first we check if this is part of a card mark. if so then we have // to generate a StoreLoad barrier - + if (is_card_mark_membar(mbvol)) { return false; } @@ -2769,7 +2769,7 @@ bool needs_releasing_store(const Node *n) if (!is_card_mark_membar(mbvol)) { return true; } - + // we found a card mark -- just make sure we have a trailing barrier return (card_mark_to_trailing(mbvol) != NULL); @@ -2808,7 +2808,7 @@ bool needs_acquiring_load_exclusive(const Node *n) assert(barrier->Opcode() == Op_MemBarCPUOrder, "CAS not fed by cpuorder membar!"); - + MemBarNode *b = parent_membar(barrier); assert ((b != NULL && b->Opcode() == Op_MemBarRelease), "CAS not fed by cpuorder+release membar pair!"); @@ -3463,6 +3463,17 @@ const bool Matcher::match_rule_supported(int opcode) { return true; // Per default match rules are supported. } +const bool Matcher::match_rule_supported_vector(int opcode, int vlen) { + + // TODO + // identify extra cases that we might want to provide match rules for + // e.g. Op_ vector nodes and other intrinsics while guarding with vlen + bool ret_value = match_rule_supported(opcode); + // Add rules here. + + return ret_value; // Per default match rules are supported. +} + const int Matcher::float_pressure(int default_pressure_threshold) { return default_pressure_threshold; } @@ -4663,7 +4674,7 @@ encode %{ call = __ trampoline_call(Address(addr, relocInfo::static_call_type), &cbuf); } if (call == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); + ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -4671,7 +4682,7 @@ encode %{ // Emit stub for static call address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); if (stub == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); + ciEnv::current()->record_failure("CodeCache is full"); return; } } @@ -4681,7 +4692,7 @@ encode %{ MacroAssembler _masm(&cbuf); address call = __ ic_call((address)$meth$$method); if (call == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); + ciEnv::current()->record_failure("CodeCache is full"); return; } %} @@ -4706,7 +4717,7 @@ encode %{ if (cb) { address call = __ trampoline_call(Address(entry, relocInfo::runtime_call_type)); if (call == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); + ciEnv::current()->record_failure("CodeCache is full"); return; } } else { diff --git a/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp index 7ab673f2151..342f07bdb04 100644 --- a/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp @@ -73,6 +73,7 @@ define_pd_global(bool, UseCISCSpill, true); define_pd_global(bool, OptoScheduling, false); define_pd_global(bool, OptoBundling, false); define_pd_global(bool, OptoRegScheduling, false); +define_pd_global(bool, SuperWordLoopUnrollAnalysis, false); define_pd_global(intx, ReservedCodeCacheSize, 48*M); define_pd_global(intx, NonProfiledCodeHeapSize, 21*M); diff --git a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp index d41e391b4bc..20174522381 100644 --- a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp @@ -61,6 +61,7 @@ define_pd_global(bool, OptoPeephole, false); define_pd_global(bool, UseCISCSpill, false); define_pd_global(bool, OptoBundling, false); define_pd_global(bool, OptoRegScheduling, false); +define_pd_global(bool, SuperWordLoopUnrollAnalysis, false); // GL: // Detected a problem with unscaled compressed oops and // narrow_oop_use_complex_address() == false. diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index fd4a6de1869..8da21b95cff 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -2064,6 +2064,17 @@ const bool Matcher::match_rule_supported(int opcode) { return true; // Per default match rules are supported. } +const bool Matcher::match_rule_supported_vector(int opcode, int vlen) { + + // TODO + // identify extra cases that we might want to provide match rules for + // e.g. Op_ vector nodes and other intrinsics while guarding with vlen + bool ret_value = match_rule_supported(opcode); + // Add rules here. + + return ret_value; // Per default match rules are supported. +} + const int Matcher::float_pressure(int default_pressure_threshold) { return default_pressure_threshold; } @@ -3416,7 +3427,7 @@ encode %{ // The stub for call to interpreter. address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); if (stub == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); + ciEnv::current()->record_failure("CodeCache is full"); return; } } @@ -3465,7 +3476,7 @@ encode %{ // The stub for call to interpreter. address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); if (stub == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); + ciEnv::current()->record_failure("CodeCache is full"); return; } @@ -6912,7 +6923,7 @@ instruct decodeN_Disjoint_isel_Ex(iRegPdst dst, iRegNsrc src, flagsReg crx) %{ n_compare->_opnds[0] = op_crx; n_compare->_opnds[1] = op_src; n_compare->_opnds[2] = new immN_0Oper(TypeNarrowOop::NULL_PTR); - + decodeN_mergeDisjointNode *n2 = new decodeN_mergeDisjointNode(); n2->add_req(n_region, n_src, n1); n2->_opnds[0] = op_dst; @@ -10589,7 +10600,7 @@ instruct cmpP_reg_imm16(flagsReg crx, iRegPsrc src1, immL16 src2) %{ instruct cmpFUnordered_reg_reg(flagsReg crx, regF src1, regF src2) %{ // Needs matchrule, see cmpDUnordered. - match(Set crx (CmpF src1 src2)); + match(Set crx (CmpF src1 src2)); // no match-rule, false predicate predicate(false); @@ -10698,13 +10709,13 @@ instruct cmpF3_reg_reg_ExEx(iRegIdst dst, regF src1, regF src2) %{ %} instruct cmpDUnordered_reg_reg(flagsReg crx, regD src1, regD src2) %{ - // Needs matchrule so that ideal opcode is Cmp. This causes that gcm places the - // node right before the conditional move using it. + // Needs matchrule so that ideal opcode is Cmp. This causes that gcm places the + // node right before the conditional move using it. // In jck test api/java_awt/geom/QuadCurve2DFloat/index.html#SetCurveTesttestCase7, // compilation of java.awt.geom.RectangularShape::getBounds()Ljava/awt/Rectangle // crashed in register allocation where the flags Reg between cmpDUnoredered and a // conditional move was supposed to be spilled. - match(Set crx (CmpD src1 src2)); + match(Set crx (CmpD src1 src2)); // False predicate, shall not be matched. predicate(false); diff --git a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp index 39592b6e0eb..152529b9beb 100644 --- a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp @@ -65,6 +65,7 @@ define_pd_global(bool, UseCISCSpill, false); define_pd_global(bool, OptoBundling, false); define_pd_global(bool, OptoScheduling, true); define_pd_global(bool, OptoRegScheduling, false); +define_pd_global(bool, SuperWordLoopUnrollAnalysis, false); #ifdef _LP64 // We need to make sure that all generated code is within diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 5d26b664175..15526706f78 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -1860,6 +1860,17 @@ const bool Matcher::match_rule_supported(int opcode) { return true; // Per default match rules are supported. } +const bool Matcher::match_rule_supported_vector(int opcode, int vlen) { + + // TODO + // identify extra cases that we might want to provide match rules for + // e.g. Op_ vector nodes and other intrinsics while guarding with vlen + bool ret_value = match_rule_supported(opcode); + // Add rules here. + + return ret_value; // Per default match rules are supported. +} + const int Matcher::float_pressure(int default_pressure_threshold) { return default_pressure_threshold; } @@ -1905,7 +1916,7 @@ const bool Matcher::misaligned_vectors_ok() { } // Current (2013) SPARC platforms need to read original key -// to construct decryption expanded key +// to construct decryption expanded key const bool Matcher::pass_original_key_for_aes() { return true; } @@ -2612,7 +2623,7 @@ encode %{ if (stub == NULL && !(TraceJumps && Compile::current()->in_scratch_emit_size())) { ciEnv::current()->record_failure("CodeCache is full"); return; - } + } } %} @@ -3132,10 +3143,10 @@ ins_attrib ins_size(32); // Required size attribute (in bits) // AVOID_NONE - instruction can be placed anywhere // AVOID_BEFORE - instruction cannot be placed after an // instruction with MachNode::AVOID_AFTER -// AVOID_AFTER - the next instruction cannot be the one +// AVOID_AFTER - the next instruction cannot be the one // with MachNode::AVOID_BEFORE -// AVOID_BEFORE_AND_AFTER - BEFORE and AFTER attributes at -// the same time +// AVOID_BEFORE_AND_AFTER - BEFORE and AFTER attributes at +// the same time ins_attrib ins_avoid_back_to_back(MachNode::AVOID_NONE); ins_attrib ins_short_branch(0); // Required flag: is this instruction a diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index 88db2698cda..6cd7fb98c72 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -313,7 +313,7 @@ bool Assembler::query_compressed_disp_byte(int disp, bool is_evex_inst, int vect switch (cur_tuple_type) { case EVEX_FV: if ((cur_encoding & VEX_W) == VEX_W) { - mod_idx += 2 + ((cur_encoding & EVEX_Rb) == EVEX_Rb) ? 1 : 0; + mod_idx = ((cur_encoding & EVEX_Rb) == EVEX_Rb) ? 3 : 2; } else { mod_idx = ((cur_encoding & EVEX_Rb) == EVEX_Rb) ? 1 : 0; } @@ -394,25 +394,27 @@ bool Assembler::emit_compressed_disp_byte(int &disp) { int mod_idx = 0; // We will test if the displacement fits the compressed format and if so // apply the compression to the displacment iff the result is8bit. - if (VM_Version::supports_evex() && _is_evex_instruction) { - switch (_tuple_type) { + if (VM_Version::supports_evex() && (_attributes != NULL) && _attributes->is_evex_instruction()) { + int evex_encoding = _attributes->get_evex_encoding(); + int tuple_type = _attributes->get_tuple_type(); + switch (tuple_type) { case EVEX_FV: - if ((_evex_encoding & VEX_W) == VEX_W) { - mod_idx += 2 + ((_evex_encoding & EVEX_Rb) == EVEX_Rb) ? 1 : 0; + if ((evex_encoding & VEX_W) == VEX_W) { + mod_idx = ((evex_encoding & EVEX_Rb) == EVEX_Rb) ? 3 : 2; } else { - mod_idx = ((_evex_encoding & EVEX_Rb) == EVEX_Rb) ? 1 : 0; + mod_idx = ((evex_encoding & EVEX_Rb) == EVEX_Rb) ? 1 : 0; } break; case EVEX_HV: - mod_idx = ((_evex_encoding & EVEX_Rb) == EVEX_Rb) ? 1 : 0; + mod_idx = ((evex_encoding & EVEX_Rb) == EVEX_Rb) ? 1 : 0; break; case EVEX_FVM: break; case EVEX_T1S: - switch (_input_size_in_bits) { + switch (_attributes->get_input_size()) { case EVEX_8bit: break; @@ -433,7 +435,7 @@ bool Assembler::emit_compressed_disp_byte(int &disp) { case EVEX_T1F: case EVEX_T2: case EVEX_T4: - mod_idx = (_input_size_in_bits == EVEX_64bit) ? 1 : 0; + mod_idx = (_attributes->get_input_size() == EVEX_64bit) ? 1 : 0; break; case EVEX_T8: @@ -459,8 +461,9 @@ bool Assembler::emit_compressed_disp_byte(int &disp) { break; } - if (_avx_vector_len >= AVX_128bit && _avx_vector_len <= AVX_512bit) { - int disp_factor = tuple_table[_tuple_type + mod_idx][_avx_vector_len]; + int vector_len = _attributes->get_vector_len(); + if (vector_len >= AVX_128bit && vector_len <= AVX_512bit) { + int disp_factor = tuple_table[tuple_type + mod_idx][vector_len]; if ((disp % disp_factor) == 0) { int new_disp = disp / disp_factor; if (is8bit(new_disp)) { @@ -591,7 +594,6 @@ void Assembler::emit_operand(Register reg, Register base, Register index, emit_data(disp, rspec, disp32_operand); } } - _is_evex_instruction = false; } void Assembler::emit_operand(XMMRegister reg, Register base, Register index, @@ -770,7 +772,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0x55: // andnps case 0x56: // orps case 0x57: // xorps - case 0x59: //mulpd + case 0x59: // mulpd case 0x6E: // movd case 0x7E: // movd case 0xAE: // ldmxcsr, stmxcsr, fxrstor, fxsave, clflush @@ -1234,51 +1236,53 @@ void Assembler::addr_nop_8() { void Assembler::addsd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x58, dst, src, VEX_SIMD_F2); - } else { - emit_simd_arith(0x58, dst, src, VEX_SIMD_F2); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::addsd(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - emit_simd_arith_q(0x58, dst, src, VEX_SIMD_F2); - } else { - emit_simd_arith(0x58, dst, src, VEX_SIMD_F2); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_operand(dst, src); } void Assembler::addss(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - emit_simd_arith(0x58, dst, src, VEX_SIMD_F3); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::addss(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } - emit_simd_arith(0x58, dst, src, VEX_SIMD_F3); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_operand(dst, src); } void Assembler::aesdec(XMMRegister dst, Address src) { assert(VM_Version::supports_aes(), ""); InstructionMark im(this); - simd_prefix(dst, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_38, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xDE); emit_operand(dst, src); } void Assembler::aesdec(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_aes(), ""); - int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_38, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xDE); emit_int8(0xC0 | encode); } @@ -1286,16 +1290,16 @@ void Assembler::aesdec(XMMRegister dst, XMMRegister src) { void Assembler::aesdeclast(XMMRegister dst, Address src) { assert(VM_Version::supports_aes(), ""); InstructionMark im(this); - simd_prefix(dst, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_38, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xDF); emit_operand(dst, src); } void Assembler::aesdeclast(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_aes(), ""); - int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_38, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xDF); emit_int8((unsigned char)(0xC0 | encode)); } @@ -1303,16 +1307,16 @@ void Assembler::aesdeclast(XMMRegister dst, XMMRegister src) { void Assembler::aesenc(XMMRegister dst, Address src) { assert(VM_Version::supports_aes(), ""); InstructionMark im(this); - simd_prefix(dst, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_38, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xDC); emit_operand(dst, src); } void Assembler::aesenc(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_aes(), ""); - int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_38, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xDC); emit_int8(0xC0 | encode); } @@ -1320,16 +1324,16 @@ void Assembler::aesenc(XMMRegister dst, XMMRegister src) { void Assembler::aesenclast(XMMRegister dst, Address src) { assert(VM_Version::supports_aes(), ""); InstructionMark im(this); - simd_prefix(dst, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_38, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xDD); emit_operand(dst, src); } void Assembler::aesenclast(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_aes(), ""); - int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_38, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xDD); emit_int8((unsigned char)(0xC0 | encode)); } @@ -1361,15 +1365,17 @@ void Assembler::andl(Register dst, Register src) { void Assembler::andnl(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - int encode = vex_prefix_0F38_and_encode_legacy(dst, src1, src2); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF2); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::andnl(Register dst, Register src1, Address src2) { - InstructionMark im(this); assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - vex_prefix_0F38_legacy(dst, src1, src2); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF2); emit_operand(dst, src2); } @@ -1396,45 +1402,51 @@ void Assembler::bswapl(Register reg) { // bswap void Assembler::blsil(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - int encode = vex_prefix_0F38_and_encode_legacy(rbx, dst, src); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rbx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::blsil(Register dst, Address src) { - InstructionMark im(this); assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - vex_prefix_0F38_legacy(rbx, dst, src); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + vex_prefix(src, dst->encoding(), rbx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rbx, src); } void Assembler::blsmskl(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - int encode = vex_prefix_0F38_and_encode_legacy(rdx, dst, src); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rdx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::blsmskl(Register dst, Address src) { - InstructionMark im(this); assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - vex_prefix_0F38_legacy(rdx, dst, src); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + vex_prefix(src, dst->encoding(), rdx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rdx, src); } void Assembler::blsrl(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - int encode = vex_prefix_0F38_and_encode_legacy(rcx, dst, src); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rcx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::blsrl(Register dst, Address src) { - InstructionMark im(this); assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - vex_prefix_0F38_legacy(rcx, dst, src); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + vex_prefix(src, dst->encoding(), rcx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rcx, src); } @@ -1581,36 +1593,38 @@ void Assembler::comisd(XMMRegister dst, Address src) { // NOTE: dbx seems to decode this as comiss even though the // 0x66 is there. Strangly ucomisd comes out correct NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - emit_simd_arith_nonds_q(0x2F, dst, src, VEX_SIMD_66, /* no_mask_reg */ true); - } else { - emit_simd_arith_nonds(0x2F, dst, src, VEX_SIMD_66); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false);; + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x2F); + emit_operand(dst, src); } void Assembler::comisd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_nonds_q(0x2F, dst, src, VEX_SIMD_66, /* no_mask_reg */ true); - } else { - emit_simd_arith_nonds(0x2F, dst, src, VEX_SIMD_66); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x2F); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::comiss(XMMRegister dst, Address src) { - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } NOT_LP64(assert(VM_Version::supports_sse(), "")); - emit_simd_arith_nonds(0x2F, dst, src, VEX_SIMD_NONE, /* no_mask_reg */ true); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x2F); + emit_operand(dst, src); } void Assembler::comiss(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - emit_simd_arith_nonds(0x2F, dst, src, VEX_SIMD_NONE, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x2F); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::cpuid() { @@ -1699,100 +1713,113 @@ void Assembler::crc32(Register crc, Address adr, int8_t sizeInBytes) { void Assembler::cvtdq2pd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith_nonds(0xE6, dst, src, VEX_SIMD_F3, /* no_mask_reg */ false, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xE6); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::cvtdq2ps(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith_nonds(0x5B, dst, src, VEX_SIMD_NONE, /* no_mask_reg */ false, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x5B); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::cvtsd2ss(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x5A, dst, src, VEX_SIMD_F2); - } else { - emit_simd_arith(0x5A, dst, src, VEX_SIMD_F2); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x5A); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::cvtsd2ss(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1F; - _input_size_in_bits = EVEX_64bit; - emit_simd_arith_q(0x5A, dst, src, VEX_SIMD_F2); - } else { - emit_simd_arith(0x5A, dst, src, VEX_SIMD_F2); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x5A); + emit_operand(dst, src); } void Assembler::cvtsi2sdl(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2, VM_Version::supports_evex()); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x2A); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::cvtsi2sdl(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - emit_simd_arith(0x2A, dst, src, VEX_SIMD_F2, /* no_mask_reg */ true); - } else { - emit_simd_arith(0x2A, dst, src, VEX_SIMD_F2); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x2A); + emit_operand(dst, src); } void Assembler::cvtsi2ssl(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x2A); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::cvtsi2ssl(XMMRegister dst, Address src) { - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } NOT_LP64(assert(VM_Version::supports_sse(), "")); - emit_simd_arith(0x2A, dst, src, VEX_SIMD_F3, /* no_mask_reg */ true); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x2A); + emit_operand(dst, src); } void Assembler::cvtsi2ssq(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - int encode = simd_prefix_and_encode_q(dst, dst, src, VEX_SIMD_F3, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x2A); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::cvtss2sd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0x5A, dst, src, VEX_SIMD_F3); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x5A); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::cvtss2sd(XMMRegister dst, Address src) { - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0x5A, dst, src, VEX_SIMD_F3); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x5A); + emit_operand(dst, src); } void Assembler::cvttsd2sil(Register dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - int encode = simd_prefix_and_encode(dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x2C); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::cvttss2sil(Register dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - int encode = simd_prefix_and_encode(dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x2C); emit_int8((unsigned char)(0xC0 | encode)); } @@ -1807,36 +1834,38 @@ void Assembler::decl(Address dst) { void Assembler::divsd(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - emit_simd_arith_q(0x5E, dst, src, VEX_SIMD_F2); - } else { - emit_simd_arith(0x5E, dst, src, VEX_SIMD_F2); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x5E); + emit_operand(dst, src); } void Assembler::divsd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x5E, dst, src, VEX_SIMD_F2); - } else { - emit_simd_arith(0x5E, dst, src, VEX_SIMD_F2); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x5E); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::divss(XMMRegister dst, Address src) { - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } NOT_LP64(assert(VM_Version::supports_sse(), "")); - emit_simd_arith(0x5E, dst, src, VEX_SIMD_F3); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x5E); + emit_operand(dst, src); } void Assembler::divss(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - emit_simd_arith(0x5E, dst, src, VEX_SIMD_F3); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x5E); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::emms() { @@ -2082,36 +2111,26 @@ void Assembler::mov(Register dst, Register src) { void Assembler::movapd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_avx512novl()) { - int vector_len = AVX_512bit; - int dst_enc = dst->encoding(); - int src_enc = src->encoding(); - int encode = vex_prefix_and_encode(dst_enc, 0, src_enc, VEX_SIMD_66, VEX_OPCODE_0F, - /* vex_w */ true, vector_len, /* legacy_mode */ false, /* no_mask_reg */ false); - emit_int8(0x28); - emit_int8((unsigned char)(0xC0 | encode)); - } else if (VM_Version::supports_evex()) { - emit_simd_arith_nonds_q(0x28, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith_nonds(0x28, dst, src, VEX_SIMD_66); - } + int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_128bit; + InstructionAttr attributes(vector_len, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x28); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::movaps(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - if (VM_Version::supports_avx512novl()) { - int vector_len = AVX_512bit; - int encode = vex_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, vector_len); - emit_int8(0x28); - emit_int8((unsigned char)(0xC0 | encode)); - } else { - emit_simd_arith_nonds(0x28, dst, src, VEX_SIMD_NONE); - } + int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_128bit; + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x28); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::movlhps(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - int encode = simd_prefix_and_encode(dst, src, src, VEX_SIMD_NONE, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, src, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8(0x16); emit_int8((unsigned char)(0xC0 | encode)); } @@ -2125,39 +2144,36 @@ void Assembler::movb(Register dst, Address src) { } void Assembler::movddup(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse3(), "")); - int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_F2, /* no_mask_reg */ false, VEX_OPCODE_0F, - /* rex_w */ VM_Version::supports_evex(), AVX_128bit, /* legacy_mode */ false); + int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_128bit; + InstructionAttr attributes(vector_len, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x12); emit_int8(0xC0 | encode); - } void Assembler::kmovql(KRegister dst, KRegister src) { NOT_LP64(assert(VM_Version::supports_evex(), "")); - int encode = kreg_prefix_and_encode(dst, knoreg, src, VEX_SIMD_NONE, - /* no_mask_reg */ true, VEX_OPCODE_0F, /* rex_w */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = kreg_prefix_and_encode(dst, knoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x90); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::kmovql(KRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_evex(), "")); - int dst_enc = dst->encoding(); - int nds_enc = 0; - vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_NONE, - VEX_OPCODE_0F, /* vex_w */ true, AVX_128bit, /* legacy_mode */ true, /* no_reg_mask */ true); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x90); emit_operand((Register)dst, src); } void Assembler::kmovql(Address dst, KRegister src) { NOT_LP64(assert(VM_Version::supports_evex(), "")); - int src_enc = src->encoding(); - int nds_enc = 0; - vex_prefix(dst, nds_enc, src_enc, VEX_SIMD_NONE, - VEX_OPCODE_0F, /* vex_w */ true, AVX_128bit, /* legacy_mode */ true, /* no_reg_mask */ true); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + vex_prefix(dst, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x90); emit_operand((Register)src, dst); } @@ -2165,8 +2181,8 @@ void Assembler::kmovql(Address dst, KRegister src) { void Assembler::kmovql(KRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_evex(), "")); VexSimdPrefix pre = !_legacy_mode_bw ? VEX_SIMD_F2 : VEX_SIMD_NONE; - int encode = kreg_prefix_and_encode(dst, knoreg, src, pre, /* no_mask_reg */ true, - VEX_OPCODE_0F, /* legacy_mode */ !_legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ !_legacy_mode_bw, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = kreg_prefix_and_encode(dst, knoreg, src, pre, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x92); emit_int8((unsigned char)(0xC0 | encode)); } @@ -2174,14 +2190,16 @@ void Assembler::kmovql(KRegister dst, Register src) { void Assembler::kmovdl(KRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_evex(), "")); VexSimdPrefix pre = !_legacy_mode_bw ? VEX_SIMD_F2 : VEX_SIMD_NONE; - int encode = kreg_prefix_and_encode(dst, knoreg, src, pre, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = kreg_prefix_and_encode(dst, knoreg, src, pre, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x92); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::kmovwl(KRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_evex(), "")); - int encode = kreg_prefix_and_encode(dst, knoreg, src, VEX_SIMD_NONE, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = kreg_prefix_and_encode(dst, knoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x92); emit_int8((unsigned char)(0xC0 | encode)); } @@ -2205,190 +2223,174 @@ void Assembler::movb(Address dst, Register src) { void Assembler::movdl(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - int encode = simd_prefix_and_encode(dst, src, VEX_SIMD_66, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, xnoreg, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x6E); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::movdl(Register dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // swap src/dst to get correct prefix - int encode = simd_prefix_and_encode(src, dst, VEX_SIMD_66, /* no_mask_reg */ true); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x7E); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::movdl(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } InstructionMark im(this); - simd_prefix(dst, src, VEX_SIMD_66, /* no_reg_mask */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x6E); emit_operand(dst, src); } void Assembler::movdl(Address dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } InstructionMark im(this); - simd_prefix(dst, src, VEX_SIMD_66, /* no_reg_mask */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(src, xnoreg, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x7E); emit_operand(src, dst); } void Assembler::movdqa(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith_nonds(0x6F, dst, src, VEX_SIMD_66); + int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_128bit; + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x6F); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::movdqa(XMMRegister dst, Address src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } - emit_simd_arith_nonds(0x6F, dst, src, VEX_SIMD_66); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x6F); + emit_operand(dst, src); } void Assembler::movdqu(XMMRegister dst, Address src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } - emit_simd_arith_nonds(0x6F, dst, src, VEX_SIMD_F3); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + simd_prefix(dst, xnoreg, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x6F); + emit_operand(dst, src); } void Assembler::movdqu(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith_nonds(0x6F, dst, src, VEX_SIMD_F3); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x6F); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::movdqu(Address dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } InstructionMark im(this); - simd_prefix(dst, src, VEX_SIMD_F3, /* no_mask_reg */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + simd_prefix(src, xnoreg, dst, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x7F); emit_operand(src, dst); } // Move Unaligned 256bit Vector void Assembler::vmovdqu(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; assert(UseAVX > 0, ""); - int vector_len = AVX_256bit; - int encode = vex_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_F3, vector_len); + InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x6F); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vmovdqu(XMMRegister dst, Address src) { - _instruction_uses_vl = true; assert(UseAVX > 0, ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } InstructionMark im(this); - int vector_len = AVX_256bit; - vex_prefix(dst, xnoreg, src, VEX_SIMD_F3, vector_len); + InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x6F); emit_operand(dst, src); } void Assembler::vmovdqu(Address dst, XMMRegister src) { - _instruction_uses_vl = true; assert(UseAVX > 0, ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } InstructionMark im(this); - int vector_len = AVX_256bit; + InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); // swap src<->dst for encoding assert(src != xnoreg, "sanity"); - vex_prefix(src, xnoreg, dst, VEX_SIMD_F3, vector_len); + vex_prefix(dst, 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x7F); emit_operand(src, dst); } // Move Unaligned EVEX enabled Vector (programmable : 8,16,32,64) void Assembler::evmovdqul(XMMRegister dst, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 0, ""); - int src_enc = src->encoding(); - int dst_enc = dst->encoding(); - int encode = vex_prefix_and_encode(dst_enc, 0, src_enc, VEX_SIMD_F3, VEX_OPCODE_0F, - /* vex_w */ false, vector_len, /* legacy_mode */ false, /* no_mask_reg */ false); + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x6F); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::evmovdqul(XMMRegister dst, Address src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 0, ""); + assert(VM_Version::supports_evex(), ""); InstructionMark im(this); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } - vex_prefix(dst, xnoreg, src, VEX_SIMD_F3, vector_len); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x6F); emit_operand(dst, src); } void Assembler::evmovdqul(Address dst, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 0, ""); - InstructionMark im(this); + assert(VM_Version::supports_evex(), ""); assert(src != xnoreg, "sanity"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } - // swap src<->dst for encoding - vex_prefix(src, xnoreg, dst, VEX_SIMD_F3, vector_len); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(dst, 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x7F); emit_operand(src, dst); } void Assembler::evmovdquq(XMMRegister dst, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 0, ""); - int src_enc = src->encoding(); - int dst_enc = dst->encoding(); - int encode = vex_prefix_and_encode(dst_enc, 0, src_enc, VEX_SIMD_F3, VEX_OPCODE_0F, - /* vex_w */ true, vector_len, /* legacy_mode */ false, /* no_mask_reg */ false); + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x6F); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::evmovdquq(XMMRegister dst, Address src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 2, ""); + assert(VM_Version::supports_evex(), ""); InstructionMark im(this); - _tuple_type = EVEX_FVM; - vex_prefix_q(dst, xnoreg, src, VEX_SIMD_F3, vector_len); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x6F); emit_operand(dst, src); } void Assembler::evmovdquq(Address dst, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 2, ""); - InstructionMark im(this); + assert(VM_Version::supports_evex(), ""); assert(src != xnoreg, "sanity"); - _tuple_type = EVEX_FVM; - // swap src<->dst for encoding - vex_prefix_q(src, xnoreg, dst, VEX_SIMD_F3, vector_len); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(dst, 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x7F); emit_operand(src, dst); } @@ -2434,13 +2436,12 @@ void Assembler::movl(Address dst, Register src) { // The selection is done in MacroAssembler::movdbl() and movflt(). void Assembler::movlpd(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - emit_simd_arith_q(0x12, dst, src, VEX_SIMD_66, /* no_mask_reg */ true); - } else { - emit_simd_arith(0x12, dst, src, VEX_SIMD_66, /* no_mask_reg */ true); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x12); + emit_operand(dst, src); } void Assembler::movq( MMXRegister dst, Address src ) { @@ -2466,13 +2467,9 @@ void Assembler::movq( Address dst, MMXRegister src ) { void Assembler::movq(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionMark im(this); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - simd_prefix_q(dst, xnoreg, src, VEX_SIMD_F3, /* no_mask_reg */ true); - } else { - simd_prefix(dst, src, VEX_SIMD_F3, /* no_mask_reg */ true); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, xnoreg, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x7E); emit_operand(dst, src); } @@ -2480,14 +2477,9 @@ void Assembler::movq(XMMRegister dst, Address src) { void Assembler::movq(Address dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionMark im(this); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - simd_prefix(src, xnoreg, dst, VEX_SIMD_66, /* no_mask_reg */ true, - VEX_OPCODE_0F, /* rex_w */ true); - } else { - simd_prefix(dst, src, VEX_SIMD_66, /* no_mask_reg */ true); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(src, xnoreg, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD6); emit_operand(src, dst); } @@ -2510,60 +2502,56 @@ void Assembler::movsbl(Register dst, Register src) { // movsxb void Assembler::movsd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x10, dst, src, VEX_SIMD_F2, /* no_mask_reg */ true); - } else { - emit_simd_arith(0x10, dst, src, VEX_SIMD_F2); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x10); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::movsd(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - emit_simd_arith_nonds_q(0x10, dst, src, VEX_SIMD_F2, /* no_mask_reg */ true); - } else { - emit_simd_arith_nonds(0x10, dst, src, VEX_SIMD_F2); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x10); + emit_operand(dst, src); } void Assembler::movsd(Address dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionMark im(this); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - simd_prefix_q(src, xnoreg, dst, VEX_SIMD_F2); - } else { - simd_prefix(src, xnoreg, dst, VEX_SIMD_F2, /* no_mask_reg */ false); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(src, xnoreg, dst, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x11); emit_operand(src, dst); } void Assembler::movss(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - emit_simd_arith(0x10, dst, src, VEX_SIMD_F3, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x10); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::movss(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } - emit_simd_arith_nonds(0x10, dst, src, VEX_SIMD_F3, /* no_mask_reg */ true); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, xnoreg, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x10); + emit_operand(dst, src); } void Assembler::movss(Address dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } InstructionMark im(this); - simd_prefix(dst, src, VEX_SIMD_F3, /* no_mask_reg */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(src, xnoreg, dst, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x11); emit_operand(src, dst); } @@ -2655,36 +2643,38 @@ void Assembler::mull(Register src) { void Assembler::mulsd(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - emit_simd_arith_q(0x59, dst, src, VEX_SIMD_F2); - } else { - emit_simd_arith(0x59, dst, src, VEX_SIMD_F2); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_operand(dst, src); } void Assembler::mulsd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x59, dst, src, VEX_SIMD_F2); - } else { - emit_simd_arith(0x59, dst, src, VEX_SIMD_F2); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::mulss(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } - emit_simd_arith(0x59, dst, src, VEX_SIMD_F3); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_operand(dst, src); } void Assembler::mulss(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - emit_simd_arith(0x59, dst, src, VEX_SIMD_F3); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::negl(Register dst) { @@ -2985,28 +2975,35 @@ void Assembler::orl(Address dst, Register src) { void Assembler::packuswb(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_simd_arith(0x67, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x67); + emit_operand(dst, src); } void Assembler::packuswb(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0x67, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x67); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpackuswb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "some form of AVX must be enabled"); - emit_vex_arith(0x67, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x67); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpermq(XMMRegister dst, XMMRegister src, int imm8, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx2(), ""); - int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_3A, /* rex_w */ true, vector_len); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x00); emit_int8(0xC0 | encode); emit_int8(imm8); @@ -3020,8 +3017,8 @@ void Assembler::pause() { void Assembler::pcmpestri(XMMRegister dst, Address src, int imm8) { assert(VM_Version::supports_sse4_2(), ""); InstructionMark im(this); - simd_prefix(dst, xnoreg, src, VEX_SIMD_66, /* no_mask_reg */ false, VEX_OPCODE_0F_3A, - /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x61); emit_operand(dst, src); emit_int8(imm8); @@ -3029,8 +3026,8 @@ void Assembler::pcmpestri(XMMRegister dst, Address src, int imm8) { void Assembler::pcmpestri(XMMRegister dst, XMMRegister src, int imm8) { assert(VM_Version::supports_sse4_2(), ""); - int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_3A, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x61); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(imm8); @@ -3038,37 +3035,42 @@ void Assembler::pcmpestri(XMMRegister dst, XMMRegister src, int imm8) { void Assembler::pcmpeqw(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0x75, dst, src, VEX_SIMD_66, - false, (VM_Version::supports_avx512dq() == false)); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x75); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - assert(UseAVX > 0, "some form of AVX must be enabled"); - emit_vex_arith(0x75, dst, nds, src, VEX_SIMD_66, vector_len, - false, (VM_Version::supports_avx512dq() == false)); + assert(VM_Version::supports_avx(), ""); + assert(!VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x75); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::pmovmskb(Register dst, XMMRegister src) { assert(VM_Version::supports_sse2(), ""); - int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, true, VEX_OPCODE_0F, - false, AVX_128bit, (VM_Version::supports_avx512dq() == false)); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD7); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpmovmskb(Register dst, XMMRegister src) { assert(VM_Version::supports_avx2(), ""); - int vector_len = AVX_256bit; - int encode = vex_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, - vector_len, VEX_OPCODE_0F, true, false); + InstructionAttr attributes(AVX_256bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD7); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::pextrd(Register dst, XMMRegister src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); - int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, /* no_mask_reg */ true, - VEX_OPCODE_0F_3A, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_dq); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x16); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(imm8); @@ -3076,8 +3078,8 @@ void Assembler::pextrd(Register dst, XMMRegister src, int imm8) { void Assembler::pextrq(Register dst, XMMRegister src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); - int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, /* no_mask_reg */ true, - VEX_OPCODE_0F_3A, /* rex_w */ true, AVX_128bit, /* legacy_mode */ _legacy_mode_dq); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x16); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(imm8); @@ -3085,8 +3087,8 @@ void Assembler::pextrq(Register dst, XMMRegister src, int imm8) { void Assembler::pextrw(Register dst, XMMRegister src, int imm8) { assert(VM_Version::supports_sse2(), ""); - int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, /* no_mask_reg */ true, - VEX_OPCODE_0F, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xC5); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(imm8); @@ -3094,8 +3096,8 @@ void Assembler::pextrw(Register dst, XMMRegister src, int imm8) { void Assembler::pinsrd(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, /* no_mask_reg */ true, - VEX_OPCODE_0F_3A, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_dq); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x22); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(imm8); @@ -3103,8 +3105,8 @@ void Assembler::pinsrd(XMMRegister dst, Register src, int imm8) { void Assembler::pinsrq(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, /* no_mask_reg */ true, - VEX_OPCODE_0F_3A, /* rex_w */ true, AVX_128bit, /* legacy_mode */ _legacy_mode_dq); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x22); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(imm8); @@ -3112,8 +3114,8 @@ void Assembler::pinsrq(XMMRegister dst, Register src, int imm8) { void Assembler::pinsrw(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse2(), ""); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, /* no_mask_reg */ true, - VEX_OPCODE_0F, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xC4); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(imm8); @@ -3121,18 +3123,18 @@ void Assembler::pinsrw(XMMRegister dst, Register src, int imm8) { void Assembler::pmovzxbw(XMMRegister dst, Address src) { assert(VM_Version::supports_sse4_1(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_HVM; - } InstructionMark im(this); - simd_prefix(dst, src, VEX_SIMD_66, /* no_mask_reg */ false, VEX_OPCODE_0F_38); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_HVM, /* input_size_in_bits */ EVEX_NObit); + simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x30); emit_operand(dst, src); } void Assembler::pmovzxbw(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_sse4_1(), ""); - int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, /* no_mask_reg */ false, VEX_OPCODE_0F_38); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x30); emit_int8((unsigned char)(0xC0 | encode)); } @@ -3140,10 +3142,10 @@ void Assembler::pmovzxbw(XMMRegister dst, XMMRegister src) { void Assembler::vpmovzxbw(XMMRegister dst, Address src) { assert(VM_Version::supports_avx(), ""); InstructionMark im(this); - bool vector256 = true; assert(dst != xnoreg, "sanity"); - int dst_enc = dst->encoding(); - vex_prefix(src, 0, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, false, vector256); + InstructionAttr attributes(AVX_256bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_HVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x30); emit_operand(dst, src); } @@ -3246,43 +3248,41 @@ void Assembler::prefix(Prefix p) { void Assembler::pshufb(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_ssse3(), ""); - int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_38, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x00); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::pshufb(XMMRegister dst, Address src) { assert(VM_Version::supports_ssse3(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } InstructionMark im(this); - simd_prefix(dst, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_38, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x00); emit_operand(dst, src); } void Assembler::pshufd(XMMRegister dst, XMMRegister src, int mode) { - _instruction_uses_vl = true; assert(isByte(mode), "invalid value"); NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith_nonds(0x70, dst, src, VEX_SIMD_66); + int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_128bit; + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x70); + emit_int8((unsigned char)(0xC0 | encode)); emit_int8(mode & 0xFF); } void Assembler::pshufd(XMMRegister dst, Address src, int mode) { - _instruction_uses_vl = true; assert(isByte(mode), "invalid value"); NOT_LP64(assert(VM_Version::supports_sse2(), "")); assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } InstructionMark im(this); - simd_prefix(dst, src, VEX_SIMD_66, /* no_mask_reg */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x70); emit_operand(dst, src); emit_int8(mode & 0xFF); @@ -3291,7 +3291,10 @@ void Assembler::pshufd(XMMRegister dst, Address src, int mode) { void Assembler::pshuflw(XMMRegister dst, XMMRegister src, int mode) { assert(isByte(mode), "invalid value"); NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith_nonds(0x70, dst, src, VEX_SIMD_F2, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x70); + emit_int8((unsigned char)(0xC0 | encode)); emit_int8(mode & 0xFF); } @@ -3299,12 +3302,10 @@ void Assembler::pshuflw(XMMRegister dst, Address src, int mode) { assert(isByte(mode), "invalid value"); NOT_LP64(assert(VM_Version::supports_sse2(), "")); assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } InstructionMark im(this); - simd_prefix(dst, xnoreg, src, VEX_SIMD_F2, /* no_mask_reg */ false, - VEX_OPCODE_0F, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + simd_prefix(dst, xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x70); emit_operand(dst, src); emit_int8(mode & 0xFF); @@ -3313,9 +3314,9 @@ void Assembler::pshuflw(XMMRegister dst, Address src, int mode) { void Assembler::psrldq(XMMRegister dst, int shift) { // Shift left 128 bit value in dst XMMRegister by shift number of bytes. NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); // XMM3 is for /3 encoding: 66 0F 73 /3 ib - int encode = simd_prefix_and_encode(xmm3, dst, dst, VEX_SIMD_66, /* no_mask_reg */ true, - VEX_OPCODE_0F, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_bw); + int encode = simd_prefix_and_encode(xmm3, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x73); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift); @@ -3324,9 +3325,9 @@ void Assembler::psrldq(XMMRegister dst, int shift) { void Assembler::pslldq(XMMRegister dst, int shift) { // Shift left 128 bit value in dst XMMRegister by shift number of bytes. NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); // XMM7 is for /7 encoding: 66 0F 73 /7 ib - int encode = simd_prefix_and_encode(xmm7, dst, dst, VEX_SIMD_66, /* no_mask_reg */ true, - VEX_OPCODE_0F, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_bw); + int encode = simd_prefix_and_encode(xmm7, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x73); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift); @@ -3336,16 +3337,16 @@ void Assembler::ptest(XMMRegister dst, Address src) { assert(VM_Version::supports_sse4_1(), ""); assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes"); InstructionMark im(this); - simd_prefix(dst, xnoreg, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_38, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x17); emit_operand(dst, src); } void Assembler::ptest(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_sse4_1(), ""); - int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_38, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x17); emit_int8((unsigned char)(0xC0 | encode)); } @@ -3353,20 +3354,18 @@ void Assembler::ptest(XMMRegister dst, XMMRegister src) { void Assembler::vptest(XMMRegister dst, Address src) { assert(VM_Version::supports_avx(), ""); InstructionMark im(this); - int vector_len = AVX_256bit; + InstructionAttr attributes(AVX_256bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); assert(dst != xnoreg, "sanity"); - int dst_enc = dst->encoding(); // swap src<->dst for encoding - vex_prefix(src, 0, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, /* rex_w */ false, - vector_len, /* legacy_mode */ true, /* no_mask_reg */ false); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x17); emit_operand(dst, src); } void Assembler::vptest(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_avx(), ""); - int vector_len = AVX_256bit; - int encode = vex_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, vector_len, VEX_OPCODE_0F_38, /* legacy_mode */ true); + InstructionAttr attributes(AVX_256bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x17); emit_int8((unsigned char)(0xC0 | encode)); } @@ -3374,42 +3373,47 @@ void Assembler::vptest(XMMRegister dst, XMMRegister src) { void Assembler::punpcklbw(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } - emit_simd_arith(0x60, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_vlbw); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_vlbw, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x60); + emit_operand(dst, src); } void Assembler::punpcklbw(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0x60, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_vlbw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_vlbw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x60); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::punpckldq(XMMRegister dst, Address src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_simd_arith(0x62, dst, src, VEX_SIMD_66); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x62); + emit_operand(dst, src); } void Assembler::punpckldq(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0x62, dst, src, VEX_SIMD_66); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x62); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::punpcklqdq(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x6C, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith(0x6C, dst, src, VEX_SIMD_66); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x6C); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::push(int32_t imm32) { @@ -3454,16 +3458,18 @@ void Assembler::rcll(Register dst, int imm8) { void Assembler::rcpps(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, /* no_mask_reg */ false, VEX_OPCODE_0F, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8(0x53); - emit_int8(0xC0 | encode); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::rcpss(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, /* no_mask_reg */ false, VEX_OPCODE_0F, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x53); - emit_int8(0xC0 | encode); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::rdtsc() { @@ -3622,27 +3628,28 @@ void Assembler::smovl() { void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x51, dst, src, VEX_SIMD_F2); - } else { - emit_simd_arith(0x51, dst, src, VEX_SIMD_F2); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x51); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::sqrtsd(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - emit_simd_arith_q(0x51, dst, src, VEX_SIMD_F2); - } else { - emit_simd_arith(0x51, dst, src, VEX_SIMD_F2); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x51); + emit_operand(dst, src); } void Assembler::sqrtss(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - emit_simd_arith(0x51, dst, src, VEX_SIMD_F3); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x51); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::std() { @@ -3651,11 +3658,12 @@ void Assembler::std() { void Assembler::sqrtss(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } - emit_simd_arith(0x51, dst, src, VEX_SIMD_F3); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x51); + emit_operand(dst, src); } void Assembler::stmxcsr( Address dst) { @@ -3705,38 +3713,38 @@ void Assembler::subl(Register dst, Register src) { void Assembler::subsd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x5C, dst, src, VEX_SIMD_F2); - } else { - emit_simd_arith(0x5C, dst, src, VEX_SIMD_F2); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x5C); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::subsd(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - } - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x5C, dst, src, VEX_SIMD_F2); - } else { - emit_simd_arith(0x5C, dst, src, VEX_SIMD_F2); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x5C); + emit_operand(dst, src); } void Assembler::subss(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - emit_simd_arith(0x5C, dst, src, VEX_SIMD_F3); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x5C); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::subss(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } - emit_simd_arith(0x5C, dst, src, VEX_SIMD_F3); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x5C); + emit_operand(dst, src); } void Assembler::testb(Register dst, int imm8) { @@ -3765,7 +3773,7 @@ void Assembler::testl(Register dst, Register src) { emit_arith(0x85, 0xC0, dst, src); } -void Assembler::testl(Register dst, Address src) { +void Assembler::testl(Register dst, Address src) { InstructionMark im(this); prefix(src, dst); emit_int8((unsigned char)0x85); @@ -3792,36 +3800,38 @@ void Assembler::tzcntq(Register dst, Register src) { void Assembler::ucomisd(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - emit_simd_arith_nonds_q(0x2E, dst, src, VEX_SIMD_66, /* no_mask_reg */ true); - } else { - emit_simd_arith_nonds(0x2E, dst, src, VEX_SIMD_66); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x2E); + emit_operand(dst, src); } void Assembler::ucomisd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_nonds_q(0x2E, dst, src, VEX_SIMD_66, /* no_mask_reg */ true); - } else { - emit_simd_arith_nonds(0x2E, dst, src, VEX_SIMD_66); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x2E); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::ucomiss(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } - emit_simd_arith_nonds(0x2E, dst, src, VEX_SIMD_NONE, /* no_mask_reg */ true); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x2E); + emit_operand(dst, src); } void Assembler::ucomiss(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - emit_simd_arith_nonds(0x2E, dst, src, VEX_SIMD_NONE, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x2E); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::xabort(int8_t imm8) { @@ -3903,138 +3913,162 @@ void Assembler::xorl(Register dst, Register src) { void Assembler::vaddsd(XMMRegister dst, XMMRegister nds, Address src) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - emit_vex_arith_q(0x58, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } else { - emit_vex_arith(0x58, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_operand(dst, src); } void Assembler::vaddsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0x58, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } else { - emit_vex_arith(0x58, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } + InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vaddss(XMMRegister dst, XMMRegister nds, Address src) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0x58, dst, nds, src, VEX_SIMD_F3, AVX_128bit); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_operand(dst, src); } void Assembler::vaddss(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); - emit_vex_arith(0x58, dst, nds, src, VEX_SIMD_F3, AVX_128bit); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vdivsd(XMMRegister dst, XMMRegister nds, Address src) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - emit_vex_arith_q(0x5E, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } else { - emit_vex_arith(0x5E, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x5E); + emit_operand(dst, src); } void Assembler::vdivsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0x5E, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } else { - emit_vex_arith(0x5E, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } + InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x5E); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vdivss(XMMRegister dst, XMMRegister nds, Address src) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0x5E, dst, nds, src, VEX_SIMD_F3, AVX_128bit); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x5E); + emit_operand(dst, src); } void Assembler::vdivss(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); - emit_vex_arith(0x5E, dst, nds, src, VEX_SIMD_F3, AVX_128bit); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x5E); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vmulsd(XMMRegister dst, XMMRegister nds, Address src) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - emit_vex_arith_q(0x59, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } else { - emit_vex_arith(0x59, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_operand(dst, src); } void Assembler::vmulsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0x59, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } else { - emit_vex_arith(0x59, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } + InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vmulss(XMMRegister dst, XMMRegister nds, Address src) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0x59, dst, nds, src, VEX_SIMD_F3, AVX_128bit); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_operand(dst, src); } void Assembler::vmulss(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); - emit_vex_arith(0x59, dst, nds, src, VEX_SIMD_F3, AVX_128bit); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vsubsd(XMMRegister dst, XMMRegister nds, Address src) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - emit_vex_arith_q(0x5C, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } else { - emit_vex_arith(0x5C, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x5C); + emit_operand(dst, src); } void Assembler::vsubsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0x5C, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } else { - emit_vex_arith(0x5C, dst, nds, src, VEX_SIMD_F2, AVX_128bit); - } + InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x5C); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vsubss(XMMRegister dst, XMMRegister nds, Address src) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0x5C, dst, nds, src, VEX_SIMD_F3, AVX_128bit); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x5C); + emit_operand(dst, src); } void Assembler::vsubss(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); - emit_vex_arith(0x5C, dst, nds, src, VEX_SIMD_F3, AVX_128bit); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + emit_int8(0x5C); + emit_int8((unsigned char)(0xC0 | encode)); } //====================VECTOR ARITHMETIC===================================== @@ -4042,414 +4076,433 @@ void Assembler::vsubss(XMMRegister dst, XMMRegister nds, XMMRegister src) { // Float-point vector arithmetic void Assembler::addpd(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x58, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith(0x58, dst, src, VEX_SIMD_66); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::addps(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0x58, dst, src, VEX_SIMD_NONE); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vaddpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0x58, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x58, dst, nds, src, VEX_SIMD_66, vector_len); - } + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vaddps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - emit_vex_arith(0x58, dst, nds, src, VEX_SIMD_NONE, vector_len); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vaddpd(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_64bit; - emit_vex_arith_q(0x58, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x58, dst, nds, src, VEX_SIMD_66, vector_len); - } + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_operand(dst, src); } void Assembler::vaddps(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0x58, dst, nds, src, VEX_SIMD_NONE, vector_len); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x58); + emit_operand(dst, src); } void Assembler::subpd(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x5C, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith(0x5C, dst, src, VEX_SIMD_66); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x5C); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::subps(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0x5C, dst, src, VEX_SIMD_NONE); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x5C); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vsubpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0x5C, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x5C, dst, nds, src, VEX_SIMD_66, vector_len); - } + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x5C); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vsubps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - emit_vex_arith(0x5C, dst, nds, src, VEX_SIMD_NONE, vector_len); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x5C); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vsubpd(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_64bit; - emit_vex_arith_q(0x5C, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x5C, dst, nds, src, VEX_SIMD_66, vector_len); - } + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x5C); + emit_operand(dst, src); } void Assembler::vsubps(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0x5C, dst, nds, src, VEX_SIMD_NONE, vector_len); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x5C); + emit_operand(dst, src); } void Assembler::mulpd(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x59, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith(0x59, dst, src, VEX_SIMD_66); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::mulpd(XMMRegister dst, Address src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x59, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith(0x59, dst, src, VEX_SIMD_66); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_operand(dst, src); } void Assembler::mulps(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0x59, dst, src, VEX_SIMD_NONE); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vmulpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0x59, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x59, dst, nds, src, VEX_SIMD_66, vector_len); - } + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vmulps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - emit_vex_arith(0x59, dst, nds, src, VEX_SIMD_NONE, vector_len); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vmulpd(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_64bit; - emit_vex_arith_q(0x59, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x59, dst, nds, src, VEX_SIMD_66, vector_len); - } + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_operand(dst, src); } void Assembler::vmulps(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0x59, dst, nds, src, VEX_SIMD_NONE, vector_len); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x59); + emit_operand(dst, src); } void Assembler::divpd(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x5E, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith(0x5E, dst, src, VEX_SIMD_66); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x5E); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::divps(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0x5E, dst, src, VEX_SIMD_NONE); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x5E); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vdivpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0x5E, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x5E, dst, nds, src, VEX_SIMD_66, vector_len); - } + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x5E); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vdivps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - emit_vex_arith(0x5E, dst, nds, src, VEX_SIMD_NONE, vector_len); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x5E); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vdivpd(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_64bit; - emit_vex_arith_q(0x5E, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x5E, dst, nds, src, VEX_SIMD_66, vector_len); - } + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x5E); + emit_operand(dst, src); } void Assembler::vdivps(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0x5E, dst, nds, src, VEX_SIMD_NONE, vector_len); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x5E); + emit_operand(dst, src); } void Assembler::vsqrtpd(XMMRegister dst, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0x51, dst, xnoreg, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x51, dst, xnoreg, src, VEX_SIMD_66, vector_len); - } + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x51); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vsqrtpd(XMMRegister dst, Address src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_64bit; - emit_vex_arith_q(0x51, dst, xnoreg, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x51, dst, xnoreg, src, VEX_SIMD_66, vector_len); - } + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x51); + emit_operand(dst, src); } void Assembler::andpd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_avx512dq()) { - emit_simd_arith_q(0x54, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith(0x54, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ true); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x54); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::andps(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - emit_simd_arith(0x54, dst, src, VEX_SIMD_NONE, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_dq); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x54); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::andps(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_simd_arith(0x54, dst, src, VEX_SIMD_NONE, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_dq); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, dst, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x54); + emit_operand(dst, src); } void Assembler::andpd(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_avx512dq()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_64bit; - emit_simd_arith_q(0x54, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith(0x54, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ true); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x54); + emit_operand(dst, src); } void Assembler::vandpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_avx512dq()) { - emit_vex_arith_q(0x54, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x54, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ true); - } + InstructionAttr attributes(vector_len, /* vex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x54); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vandps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); - emit_vex_arith(0x54, dst, nds, src, VEX_SIMD_NONE, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_dq); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x54); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vandpd(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_avx512dq()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_64bit; - emit_vex_arith_q(0x54, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x54, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ true); - } + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x54); + emit_operand(dst, src); } void Assembler::vandps(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0x54, dst, nds, src, VEX_SIMD_NONE, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_dq); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x54); + emit_operand(dst, src); } void Assembler::unpckhpd(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x15, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith(0x15, dst, src, VEX_SIMD_66); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x15); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::unpcklpd(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0x14, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith(0x14, dst, src, VEX_SIMD_66); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x14); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::xorpd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_avx512dq()) { - emit_simd_arith_q(0x57, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith(0x57, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ true); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x57); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::xorps(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - emit_simd_arith(0x57, dst, src, VEX_SIMD_NONE, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_dq); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x57); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::xorpd(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_avx512dq()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_64bit; - emit_simd_arith_q(0x57, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith(0x57, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ true); - } + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x57); + emit_operand(dst, src); } void Assembler::xorps(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_simd_arith(0x57, dst, src, VEX_SIMD_NONE, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_dq); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + simd_prefix(dst, dst, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x57); + emit_operand(dst, src); } void Assembler::vxorpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_avx512dq()) { - emit_vex_arith_q(0x57, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x57, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ true); - } + InstructionAttr attributes(vector_len, /* vex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x57); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vxorps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); - emit_vex_arith(0x57, dst, nds, src, VEX_SIMD_NONE, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_dq); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x57); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vxorpd(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_avx512dq()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_64bit; - emit_vex_arith_q(0x57, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x57, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ true); - } + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x57); + emit_operand(dst, src); } void Assembler::vxorps(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(VM_Version::supports_avx(), ""); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0x57, dst, nds, src, VEX_SIMD_NONE, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_dq); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x57); + emit_operand(dst, src); } // Integer vector arithmetic void Assembler::vphaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx() && (vector_len == 0) || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2"); - int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector_len, VEX_OPCODE_0F_38, /* legacy_mode */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x01); emit_int8((unsigned char)(0xC0 | encode)); } @@ -4457,280 +4510,324 @@ void Assembler::vphaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, int v void Assembler::vphaddd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx() && (vector_len == 0) || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2"); - int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector_len, VEX_OPCODE_0F_38, /* legacy_mode */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x02); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::paddb(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xFC, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFC); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::paddw(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xFD, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFD); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::paddd(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xFE, dst, src, VEX_SIMD_66); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFE); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::paddq(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0xD4, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith(0xD4, dst, src, VEX_SIMD_66); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD4); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::phaddw(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse3(), "")); - int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_38, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x01); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::phaddd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse3(), "")); - int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_38, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x02); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xFC, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFC); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xFD, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFD); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpaddd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xFE, dst, nds, src, VEX_SIMD_66, vector_len); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFE); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpaddq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0xD4, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0xD4, dst, nds, src, VEX_SIMD_66, vector_len); - } + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD4); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } - emit_vex_arith(0xFC, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFC); + emit_operand(dst, src); } void Assembler::vpaddw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } - emit_vex_arith(0xFD, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFD); + emit_operand(dst, src); } void Assembler::vpaddd(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0xFE, dst, nds, src, VEX_SIMD_66, vector_len); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFE); + emit_operand(dst, src); } void Assembler::vpaddq(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_64bit; - emit_vex_arith_q(0xD4, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0xD4, dst, nds, src, VEX_SIMD_66, vector_len); - } + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD4); + emit_operand(dst, src); } void Assembler::psubb(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xF8, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xF8); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::psubw(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xF9, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xF9); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::psubd(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; - NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xFA, dst, src, VEX_SIMD_66); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFA); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::psubq(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0xFB, dst, src, VEX_SIMD_66); - } else { - emit_simd_arith(0xFB, dst, src, VEX_SIMD_66); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFB); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xF8, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xF8); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpsubw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xF9, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xF9); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpsubd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xFA, dst, nds, src, VEX_SIMD_66, vector_len); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFA); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpsubq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0xFB, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0xFB, dst, nds, src, VEX_SIMD_66, vector_len); - } + InstructionAttr attributes(vector_len, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFB); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpsubb(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } - emit_vex_arith(0xF8, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xF8); + emit_operand(dst, src); } void Assembler::vpsubw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } - emit_vex_arith(0xF9, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xF9); + emit_operand(dst, src); } void Assembler::vpsubd(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0xFA, dst, nds, src, VEX_SIMD_66, vector_len); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFA); + emit_operand(dst, src); } void Assembler::vpsubq(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_64bit; - emit_vex_arith_q(0xFB, dst, nds, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0xFB, dst, nds, src, VEX_SIMD_66, vector_len); - } + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xFB); + emit_operand(dst, src); } void Assembler::pmullw(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xD5, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD5); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::pmulld(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; assert(VM_Version::supports_sse4_1(), ""); - int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, - /* no_mask_reg */ false, VEX_OPCODE_0F_38); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x40); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpmullw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xD5, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD5); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpmulld(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector_len, VEX_OPCODE_0F_38); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x40); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpmullq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 2, "requires some form of AVX"); - int src_enc = src->encoding(); - int dst_enc = dst->encoding(); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst_enc, nds_enc, src_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, - /* vex_w */ true, vector_len, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false); + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x40); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpmullw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FVM; - } - emit_vex_arith(0xD5, dst, nds, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD5); + emit_operand(dst, src); } void Assembler::vpmulld(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } InstructionMark im(this); - int dst_enc = dst->encoding(); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_66, - VEX_OPCODE_0F_38, /* vex_w */ false, vector_len); + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x40); emit_operand(dst, src); } void Assembler::vpmullq(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_64bit; - } InstructionMark im(this); - int dst_enc = dst->encoding(); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_66, - VEX_OPCODE_0F_38, /* vex_w */ true, vector_len, /* legacy_mode */ _legacy_mode_dq); + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x40); emit_operand(dst, src); } @@ -4738,29 +4835,29 @@ void Assembler::vpmullq(XMMRegister dst, XMMRegister nds, Address src, int vecto // Shift packed integers left by specified number of bits. void Assembler::psllw(XMMRegister dst, int shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); // XMM6 is for /6 encoding: 66 0F 71 /6 ib - int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, /* no_mask_reg */ false, VEX_OPCODE_0F, - /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_bw); + int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); } void Assembler::pslld(XMMRegister dst, int shift) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); // XMM6 is for /6 encoding: 66 0F 72 /6 ib - int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, /* no_mask_reg */ false); + int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x72); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); } void Assembler::psllq(XMMRegister dst, int shift) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); // XMM6 is for /6 encoding: 66 0F 73 /6 ib - int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, /* no_mask_reg */ false, VEX_OPCODE_0F, /* rex_w */ true); + int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x73); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); @@ -4768,102 +4865,111 @@ void Assembler::psllq(XMMRegister dst, int shift) { void Assembler::psllw(XMMRegister dst, XMMRegister shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xF1, dst, shift, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xF1); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::pslld(XMMRegister dst, XMMRegister shift) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xF2, dst, shift, VEX_SIMD_66); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xF2); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::psllq(XMMRegister dst, XMMRegister shift) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0xF3, dst, shift, VEX_SIMD_66); - } else { - emit_simd_arith(0xF3, dst, shift, VEX_SIMD_66); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xF3); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpsllw(XMMRegister dst, XMMRegister src, int shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); // XMM6 is for /6 encoding: 66 0F 71 /6 ib - emit_vex_arith(0x71, xmm6, dst, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + int encode = vex_prefix_and_encode(xmm6->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x71); + emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); } void Assembler::vpslld(XMMRegister dst, XMMRegister src, int shift, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); // XMM6 is for /6 encoding: 66 0F 72 /6 ib - emit_vex_arith(0x72, xmm6, dst, src, VEX_SIMD_66, vector_len); + int encode = vex_prefix_and_encode(xmm6->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x72); + emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); } void Assembler::vpsllq(XMMRegister dst, XMMRegister src, int shift, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); // XMM6 is for /6 encoding: 66 0F 73 /6 ib - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0x73, xmm6, dst, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x73, xmm6, dst, src, VEX_SIMD_66, vector_len); - } + int encode = vex_prefix_and_encode(xmm6->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x73); + emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); } void Assembler::vpsllw(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xF1, dst, src, shift, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xF1); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpslld(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xF2, dst, src, shift, VEX_SIMD_66, vector_len); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xF2); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpsllq(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0xF3, dst, src, shift, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0xF3, dst, src, shift, VEX_SIMD_66, vector_len); - } + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xF3); + emit_int8((unsigned char)(0xC0 | encode)); } // Shift packed integers logically right by specified number of bits. void Assembler::psrlw(XMMRegister dst, int shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); // XMM2 is for /2 encoding: 66 0F 71 /2 ib - int encode = simd_prefix_and_encode(xmm2, dst, dst, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_bw); + int encode = simd_prefix_and_encode(xmm2, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); } void Assembler::psrld(XMMRegister dst, int shift) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); // XMM2 is for /2 encoding: 66 0F 72 /2 ib - int encode = simd_prefix_and_encode(xmm2, dst, dst, VEX_SIMD_66, /* no_mask_reg */ false); + int encode = simd_prefix_and_encode(xmm2, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x72); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); } void Assembler::psrlq(XMMRegister dst, int shift) { - _instruction_uses_vl = true; // Do not confuse it with psrldq SSE2 instruction which // shifts 128 bit value in xmm register by number of bytes. NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); // XMM2 is for /2 encoding: 66 0F 73 /2 ib - int encode = simd_prefix_and_encode(xmm2, dst, dst, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F, /* rex_w */ VM_Version::supports_evex()); + int encode = simd_prefix_and_encode(xmm2, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x73); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); @@ -4871,89 +4977,98 @@ void Assembler::psrlq(XMMRegister dst, int shift) { void Assembler::psrlw(XMMRegister dst, XMMRegister shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xD1, dst, shift, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD1); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::psrld(XMMRegister dst, XMMRegister shift) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xD2, dst, shift, VEX_SIMD_66); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD2); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::psrlq(XMMRegister dst, XMMRegister shift) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0xD3, dst, shift, VEX_SIMD_66); - } else { - emit_simd_arith(0xD3, dst, shift, VEX_SIMD_66); - } + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD3); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpsrlw(XMMRegister dst, XMMRegister src, int shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); // XMM2 is for /2 encoding: 66 0F 71 /2 ib - emit_vex_arith(0x71, xmm2, dst, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + int encode = vex_prefix_and_encode(xmm2->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x71); + emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); } void Assembler::vpsrld(XMMRegister dst, XMMRegister src, int shift, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); // XMM2 is for /2 encoding: 66 0F 72 /2 ib - emit_vex_arith(0x72, xmm2, dst, src, VEX_SIMD_66, vector_len); + int encode = vex_prefix_and_encode(xmm2->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x72); + emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); } void Assembler::vpsrlq(XMMRegister dst, XMMRegister src, int shift, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); // XMM2 is for /2 encoding: 66 0F 73 /2 ib - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0x73, xmm2, dst, src, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0x73, xmm2, dst, src, VEX_SIMD_66, vector_len); - } + int encode = vex_prefix_and_encode(xmm2->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x73); + emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); } void Assembler::vpsrlw(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xD1, dst, src, shift, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD1); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpsrld(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xD2, dst, src, shift, VEX_SIMD_66, vector_len); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD2); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpsrlq(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - emit_vex_arith_q(0xD3, dst, src, shift, VEX_SIMD_66, vector_len); - } else { - emit_vex_arith(0xD3, dst, src, shift, VEX_SIMD_66, vector_len); - } + InstructionAttr attributes(vector_len, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xD3); + emit_int8((unsigned char)(0xC0 | encode)); } // Shift packed integers arithmetically right by specified number of bits. void Assembler::psraw(XMMRegister dst, int shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); // XMM4 is for /4 encoding: 66 0F 71 /4 ib - int encode = simd_prefix_and_encode(xmm4, dst, dst, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_bw); + int encode = simd_prefix_and_encode(xmm4, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); } void Assembler::psrad(XMMRegister dst, int shift) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); // XMM4 is for /4 encoding: 66 0F 72 /4 ib - int encode = simd_prefix_and_encode(xmm4, dst, dst, VEX_SIMD_66, /* no_mask_reg */ false); + int encode = simd_prefix_and_encode(xmm4, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x72); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); @@ -4961,128 +5076,157 @@ void Assembler::psrad(XMMRegister dst, int shift) { void Assembler::psraw(XMMRegister dst, XMMRegister shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xE1, dst, shift, VEX_SIMD_66, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xE1); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::psrad(XMMRegister dst, XMMRegister shift) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xE2, dst, shift, VEX_SIMD_66); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xE2); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpsraw(XMMRegister dst, XMMRegister src, int shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); // XMM4 is for /4 encoding: 66 0F 71 /4 ib - emit_vex_arith(0x71, xmm4, dst, src, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + int encode = vex_prefix_and_encode(xmm4->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x71); + emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); } void Assembler::vpsrad(XMMRegister dst, XMMRegister src, int shift, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); // XMM4 is for /4 encoding: 66 0F 71 /4 ib - emit_vex_arith(0x72, xmm4, dst, src, VEX_SIMD_66, vector_len); + int encode = vex_prefix_and_encode(xmm4->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x72); + emit_int8((unsigned char)(0xC0 | encode)); emit_int8(shift & 0xFF); } void Assembler::vpsraw(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xE1, dst, src, shift, VEX_SIMD_66, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_bw); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xE1); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpsrad(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xE2, dst, src, shift, VEX_SIMD_66, vector_len); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xE2); + emit_int8((unsigned char)(0xC0 | encode)); } // logical operations packed integers void Assembler::pand(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xDB, dst, src, VEX_SIMD_66); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xDB); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpand(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xDB, dst, nds, src, VEX_SIMD_66, vector_len); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xDB); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpand(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0xDB, dst, nds, src, VEX_SIMD_66, vector_len); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xDB); + emit_operand(dst, src); } void Assembler::pandn(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - emit_simd_arith_q(0xDF, dst, src, VEX_SIMD_66); - } - else { - emit_simd_arith(0xDF, dst, src, VEX_SIMD_66); - } + InstructionAttr attributes(AVX_128bit, /* vex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xDF); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::por(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xEB, dst, src, VEX_SIMD_66); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xEB); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpor(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xEB, dst, nds, src, VEX_SIMD_66, vector_len); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xEB); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpor(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0xEB, dst, nds, src, VEX_SIMD_66, vector_len); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xEB); + emit_operand(dst, src); } void Assembler::pxor(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); - emit_simd_arith(0xEF, dst, src, VEX_SIMD_66); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xEF); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpxor(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - emit_vex_arith(0xEF, dst, nds, src, VEX_SIMD_66, vector_len); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xEF); + emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::vpxor(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - _instruction_uses_vl = true; assert(UseAVX > 0, "requires some form of AVX"); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_FV; - _input_size_in_bits = EVEX_32bit; - } - emit_vex_arith(0xEF, dst, nds, src, VEX_SIMD_66, vector_len); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xEF); + emit_operand(dst, src); } void Assembler::vinsertf128h(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); - int vector_len = AVX_256bit; - if (VM_Version::supports_evex()) { - vector_len = AVX_512bit; - } - int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector_len, VEX_OPCODE_0F_3A); + int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_256bit; + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x18); emit_int8((unsigned char)(0xC0 | encode)); // 0x00 - insert into lower 128 bits @@ -5090,45 +5234,38 @@ void Assembler::vinsertf128h(XMMRegister dst, XMMRegister nds, XMMRegister src) emit_int8(0x01); } -void Assembler::vinsertf64x4h(XMMRegister dst, XMMRegister nds, XMMRegister src) { +void Assembler::vinsertf64x4h(XMMRegister dst, XMMRegister nds, XMMRegister src, int value) { assert(VM_Version::supports_evex(), ""); - int vector_len = AVX_512bit; - int src_enc = src->encoding(); - int dst_enc = dst->encoding(); + InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst_enc, nds_enc, src_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, - /* vex_w */ true, vector_len, /* legacy_mode */ false, /* no_mask_reg */ false); + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x1A); emit_int8((unsigned char)(0xC0 | encode)); // 0x00 - insert into lower 256 bits // 0x01 - insert into upper 256 bits - emit_int8(0x01); + emit_int8(value & 0x01); } -void Assembler::vinsertf64x4h(XMMRegister dst, Address src) { +void Assembler::vinsertf64x4h(XMMRegister dst, Address src, int value) { assert(VM_Version::supports_evex(), ""); - _tuple_type = EVEX_T4; - _input_size_in_bits = EVEX_64bit; - InstructionMark im(this); - int vector_len = AVX_512bit; assert(dst != xnoreg, "sanity"); - int dst_enc = dst->encoding(); + InstructionMark im(this); + InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_64bit); // swap src<->dst for encoding - vex_prefix(src, dst_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, /* vex_w */ true, vector_len); + vex_prefix(src, dst->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x1A); emit_operand(dst, src); + // 0x00 - insert into lower 256 bits // 0x01 - insert into upper 128 bits - emit_int8(0x01); + emit_int8(value & 0x01); } void Assembler::vinsertf32x4h(XMMRegister dst, XMMRegister nds, XMMRegister src, int value) { assert(VM_Version::supports_evex(), ""); - int vector_len = AVX_512bit; - int src_enc = src->encoding(); - int dst_enc = dst->encoding(); + InstructionAttr attributes(AVX_512bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst_enc, nds_enc, src_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, - /* vex_w */ false, vector_len, /* legacy_mode */ false, /* no_mask_reg */ false); + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x18); emit_int8((unsigned char)(0xC0 | encode)); // 0x00 - insert into q0 128 bits (0..127) @@ -5139,15 +5276,14 @@ void Assembler::vinsertf32x4h(XMMRegister dst, XMMRegister nds, XMMRegister src, } void Assembler::vinsertf32x4h(XMMRegister dst, Address src, int value) { - assert(VM_Version::supports_evex(), ""); - _tuple_type = EVEX_T4; - _input_size_in_bits = EVEX_32bit; - InstructionMark im(this); - int vector_len = AVX_512bit; + assert(VM_Version::supports_avx(), ""); assert(dst != xnoreg, "sanity"); - int dst_enc = dst->encoding(); + int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_256bit; + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); // swap src<->dst for encoding - vex_prefix(src, dst_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, /* vex_w */ false, vector_len); + vex_prefix(src, dst->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x18); emit_operand(dst, src); // 0x00 - insert into q0 128 bits (0..127) @@ -5159,17 +5295,13 @@ void Assembler::vinsertf32x4h(XMMRegister dst, Address src, int value) { void Assembler::vinsertf128h(XMMRegister dst, Address src) { assert(VM_Version::supports_avx(), ""); - int vector_len = AVX_256bit; - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T4; - _input_size_in_bits = EVEX_32bit; - vector_len = AVX_512bit; - } - InstructionMark im(this); assert(dst != xnoreg, "sanity"); - int dst_enc = dst->encoding(); + int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_256bit; + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); // swap src<->dst for encoding - vex_prefix(src, dst_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, /* vex_w */ false, vector_len); + vex_prefix(src, dst->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x18); emit_operand(dst, src); // 0x01 - insert into upper 128 bits @@ -5178,11 +5310,9 @@ void Assembler::vinsertf128h(XMMRegister dst, Address src) { void Assembler::vextractf128h(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_avx(), ""); - int vector_len = AVX_256bit; - if (VM_Version::supports_evex()) { - vector_len = AVX_512bit; - } - int encode = vex_prefix_and_encode(src, xnoreg, dst, VEX_SIMD_66, vector_len, VEX_OPCODE_0F_3A); + int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_256bit; + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(src->encoding(), 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x19); emit_int8((unsigned char)(0xC0 | encode)); // 0x00 - insert into lower 128 bits @@ -5192,16 +5322,12 @@ void Assembler::vextractf128h(XMMRegister dst, XMMRegister src) { void Assembler::vextractf128h(Address dst, XMMRegister src) { assert(VM_Version::supports_avx(), ""); - int vector_len = AVX_256bit; - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T4; - _input_size_in_bits = EVEX_32bit; - vector_len = AVX_512bit; - } - InstructionMark im(this); assert(src != xnoreg, "sanity"); - int src_enc = src->encoding(); - vex_prefix(dst, 0, src_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, /* vex_w */ false, vector_len); + int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_256bit; + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); + vex_prefix(dst, 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x19); emit_operand(src, dst); // 0x01 - extract from upper 128 bits @@ -5210,11 +5336,10 @@ void Assembler::vextractf128h(Address dst, XMMRegister src) { void Assembler::vinserti128h(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx2(), ""); - int vector_len = AVX_256bit; - if (VM_Version::supports_evex()) { - vector_len = AVX_512bit; - } - int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector_len, VEX_OPCODE_0F_3A); + int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_256bit; + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x38); emit_int8((unsigned char)(0xC0 | encode)); // 0x00 - insert into lower 128 bits @@ -5222,34 +5347,27 @@ void Assembler::vinserti128h(XMMRegister dst, XMMRegister nds, XMMRegister src) emit_int8(0x01); } -void Assembler::vinserti64x4h(XMMRegister dst, XMMRegister nds, XMMRegister src) { +void Assembler::vinserti64x4h(XMMRegister dst, XMMRegister nds, XMMRegister src, int value) { assert(VM_Version::supports_evex(), ""); - int vector_len = AVX_512bit; - int src_enc = src->encoding(); - int dst_enc = dst->encoding(); + InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst_enc, nds_enc, src_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, - /* vex_w */ true, vector_len, /* legacy_mode */ false, /* no_reg_mask */ false); + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x38); emit_int8((unsigned char)(0xC0 | encode)); // 0x00 - insert into lower 256 bits // 0x01 - insert into upper 256 bits - emit_int8(0x01); + emit_int8(value & 0x01); } void Assembler::vinserti128h(XMMRegister dst, Address src) { assert(VM_Version::supports_avx2(), ""); - int vector_len = AVX_256bit; - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T4; - _input_size_in_bits = EVEX_32bit; - vector_len = AVX_512bit; - } - InstructionMark im(this); assert(dst != xnoreg, "sanity"); - int dst_enc = dst->encoding(); + int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_256bit; + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); // swap src<->dst for encoding - vex_prefix(src, dst_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, /* vex_w */ false, vector_len); + vex_prefix(src, dst->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x38); emit_operand(dst, src); // 0x01 - insert into upper 128 bits @@ -5258,11 +5376,9 @@ void Assembler::vinserti128h(XMMRegister dst, Address src) { void Assembler::vextracti128h(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_avx(), ""); - int vector_len = AVX_256bit; - if (VM_Version::supports_evex()) { - vector_len = AVX_512bit; - } - int encode = vex_prefix_and_encode(src, xnoreg, dst, VEX_SIMD_66, vector_len, VEX_OPCODE_0F_3A); + int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_256bit; + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(src->encoding(), 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x39); emit_int8((unsigned char)(0xC0 | encode)); // 0x00 - insert into lower 128 bits @@ -5272,48 +5388,33 @@ void Assembler::vextracti128h(XMMRegister dst, XMMRegister src) { void Assembler::vextracti128h(Address dst, XMMRegister src) { assert(VM_Version::supports_avx2(), ""); - int vector_len = AVX_256bit; - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T4; - _input_size_in_bits = EVEX_32bit; - vector_len = AVX_512bit; - } - InstructionMark im(this); assert(src != xnoreg, "sanity"); - int src_enc = src->encoding(); - vex_prefix(dst, 0, src_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, /* vex_w */ false, vector_len); + int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_256bit; + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); + vex_prefix(dst, 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x39); emit_operand(src, dst); // 0x01 - extract from upper 128 bits emit_int8(0x01); } -void Assembler::vextracti64x4h(XMMRegister dst, XMMRegister src) { +void Assembler::vextracti64x4h(XMMRegister dst, XMMRegister src, int value) { assert(VM_Version::supports_evex(), ""); - int vector_len = AVX_512bit; - int src_enc = src->encoding(); - int dst_enc = dst->encoding(); - int encode = vex_prefix_and_encode(src_enc, 0, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, - /* vex_w */ true, vector_len, /* legacy_mode */ false, /* no_mask_reg */ false); + InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(src->encoding(), 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x3B); emit_int8((unsigned char)(0xC0 | encode)); + // 0x00 - extract from lower 256 bits // 0x01 - extract from upper 256 bits - emit_int8(0x01); + emit_int8(value & 0x01); } void Assembler::vextracti64x2h(XMMRegister dst, XMMRegister src, int value) { assert(VM_Version::supports_evex(), ""); - int vector_len = AVX_512bit; - int src_enc = src->encoding(); - int dst_enc = dst->encoding(); - int encode; - if (VM_Version::supports_avx512dq()) { - encode = vex_prefix_and_encode(src_enc, 0, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, - /* vex_w */ true, vector_len, /* legacy_mode */ false, /* no_mask_reg */ false); - } else { - encode = vex_prefix_and_encode(src_enc, 0, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, - /* vex_w */ false, vector_len, /* legacy_mode */ true, /* no_mask_reg */ false); - } + InstructionAttr attributes(AVX_512bit, /* vex_w */ !_legacy_mode_dq, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(src->encoding(), 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x39); emit_int8((unsigned char)(0xC0 | encode)); // 0x01 - extract from bits 255:128 @@ -5322,42 +5423,36 @@ void Assembler::vextracti64x2h(XMMRegister dst, XMMRegister src, int value) { emit_int8(value & 0x3); } -void Assembler::vextractf64x4h(XMMRegister dst, XMMRegister src) { +void Assembler::vextractf64x4h(XMMRegister dst, XMMRegister src, int value) { assert(VM_Version::supports_evex(), ""); - int vector_len = AVX_512bit; - int src_enc = src->encoding(); - int dst_enc = dst->encoding(); - int encode = vex_prefix_and_encode(src_enc, 0, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, - /* vex_w */ true, vector_len, /* legacy_mode */ false, /* no_mask_reg */ false); + InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(src->encoding(), 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x1B); emit_int8((unsigned char)(0xC0 | encode)); + // 0x00 - extract from lower 256 bits // 0x01 - extract from upper 256 bits - emit_int8(0x01); + emit_int8(value & 0x1); } -void Assembler::vextractf64x4h(Address dst, XMMRegister src) { +void Assembler::vextractf64x4h(Address dst, XMMRegister src, int value) { assert(VM_Version::supports_evex(), ""); - _tuple_type = EVEX_T4; - _input_size_in_bits = EVEX_64bit; - InstructionMark im(this); - int vector_len = AVX_512bit; assert(src != xnoreg, "sanity"); - int src_enc = src->encoding(); - vex_prefix(dst, 0, src_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, - /* vex_w */ true, vector_len); + InstructionMark im(this); + InstructionAttr attributes(AVX_512bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4,/* input_size_in_bits */ EVEX_64bit); + vex_prefix(dst, 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x1B); emit_operand(src, dst); + // 0x00 - extract from lower 256 bits // 0x01 - extract from upper 256 bits - emit_int8(0x01); + emit_int8(value & 0x01); } void Assembler::vextractf32x4h(XMMRegister dst, XMMRegister src, int value) { - assert(VM_Version::supports_evex(), ""); - int vector_len = AVX_512bit; - int src_enc = src->encoding(); - int dst_enc = dst->encoding(); - int encode = vex_prefix_and_encode(src_enc, 0, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, - /* vex_w */ false, vector_len, /* legacy_mode */ false, /* no_mask_reg */ false); + assert(VM_Version::supports_avx(), ""); + int vector_len = VM_Version::supports_evex() ? AVX_512bit : AVX_256bit; + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(src->encoding(), 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x19); emit_int8((unsigned char)(0xC0 | encode)); // 0x00 - extract from bits 127:0 @@ -5369,13 +5464,11 @@ void Assembler::vextractf32x4h(XMMRegister dst, XMMRegister src, int value) { void Assembler::vextractf32x4h(Address dst, XMMRegister src, int value) { assert(VM_Version::supports_evex(), ""); - _tuple_type = EVEX_T4; - _input_size_in_bits = EVEX_32bit; - InstructionMark im(this); - int vector_len = AVX_512bit; assert(src != xnoreg, "sanity"); - int src_enc = src->encoding(); - vex_prefix(dst, 0, src_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, /* vex_w */ false, vector_len); + InstructionMark im(this); + InstructionAttr attributes(AVX_512bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T4, /* input_size_in_bits */ EVEX_32bit); + vex_prefix(dst, 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x19); emit_operand(src, dst); // 0x00 - extract from bits 127:0 @@ -5387,11 +5480,8 @@ void Assembler::vextractf32x4h(Address dst, XMMRegister src, int value) { void Assembler::vextractf64x2h(XMMRegister dst, XMMRegister src, int value) { assert(VM_Version::supports_evex(), ""); - int vector_len = AVX_512bit; - int src_enc = src->encoding(); - int dst_enc = dst->encoding(); - int encode = vex_prefix_and_encode(src_enc, 0, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, - /* vex_w */ !_legacy_mode_dq, vector_len, /* legacy_mode */ false, /* no_mask_reg */ false); + InstructionAttr attributes(AVX_512bit, /* vex_w */ !_legacy_mode_dq, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(src->encoding(), 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x19); emit_int8((unsigned char)(0xC0 | encode)); // 0x01 - extract from bits 255:128 @@ -5402,10 +5492,9 @@ void Assembler::vextractf64x2h(XMMRegister dst, XMMRegister src, int value) { // duplicate 4-bytes integer data from src into 8 locations in dest void Assembler::vpbroadcastd(XMMRegister dst, XMMRegister src) { - _instruction_uses_vl = true; - assert(UseAVX > 1, ""); - int vector_len = AVX_256bit; - int encode = vex_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, vector_len, VEX_OPCODE_0F_38); + assert(VM_Version::supports_avx2(), ""); + InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x58); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5413,189 +5502,170 @@ void Assembler::vpbroadcastd(XMMRegister dst, XMMRegister src) { // duplicate 2-bytes integer data from src into 16 locations in dest void Assembler::vpbroadcastw(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_avx2(), ""); - bool vector_len = AVX_256bit; - int encode = vex_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, - vector_len, VEX_OPCODE_0F_38, false); + InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x79); emit_int8((unsigned char)(0xC0 | encode)); } // duplicate 1-byte integer data from src into 16||32|64 locations in dest : requires AVX512BW and AVX512VL void Assembler::evpbroadcastb(XMMRegister dst, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 1, ""); - int encode = vex_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, vector_len, VEX_OPCODE_0F_38); + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x78); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::evpbroadcastb(XMMRegister dst, Address src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 1, ""); - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_8bit; - InstructionMark im(this); + assert(VM_Version::supports_evex(), ""); assert(dst != xnoreg, "sanity"); - int dst_enc = dst->encoding(); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_8bit); // swap src<->dst for encoding - vex_prefix(src, dst_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, /* vex_w */ false, vector_len); + vex_prefix(src, dst->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x78); emit_operand(dst, src); } // duplicate 2-byte integer data from src into 8|16||32 locations in dest : requires AVX512BW and AVX512VL void Assembler::evpbroadcastw(XMMRegister dst, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 1, ""); - int encode = vex_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, vector_len, VEX_OPCODE_0F_38); + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x79); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::evpbroadcastw(XMMRegister dst, Address src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 1, ""); - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_16bit; - InstructionMark im(this); + assert(VM_Version::supports_evex(), ""); assert(dst != xnoreg, "sanity"); - int dst_enc = dst->encoding(); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_16bit); // swap src<->dst for encoding - vex_prefix(src, dst_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, /* vex_w */ false, vector_len); + vex_prefix(src, dst->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x79); emit_operand(dst, src); } // duplicate 4-byte integer data from src into 4|8|16 locations in dest : requires AVX512VL void Assembler::evpbroadcastd(XMMRegister dst, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 1, ""); - int encode = vex_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, vector_len, VEX_OPCODE_0F_38); + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x58); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::evpbroadcastd(XMMRegister dst, Address src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 1, ""); - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - InstructionMark im(this); + assert(VM_Version::supports_evex(), ""); assert(dst != xnoreg, "sanity"); - int dst_enc = dst->encoding(); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); // swap src<->dst for encoding - vex_prefix(src, dst_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, /* vex_w */ false, vector_len); + vex_prefix(src, dst->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x58); emit_operand(dst, src); } // duplicate 8-byte integer data from src into 4|8|16 locations in dest : requires AVX512VL void Assembler::evpbroadcastq(XMMRegister dst, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 1, ""); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, - /* vex_w */ true, vector_len, /* legacy_mode */ false, /* no_mask_reg */ false); + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x59); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::evpbroadcastq(XMMRegister dst, Address src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 1, ""); - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - InstructionMark im(this); + assert(VM_Version::supports_evex(), ""); assert(dst != xnoreg, "sanity"); - int dst_enc = dst->encoding(); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); // swap src<->dst for encoding - vex_prefix(src, dst_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, /* vex_w */ true, vector_len); + vex_prefix(src, dst->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x59); emit_operand(dst, src); } // duplicate single precision fp from src into 4|8|16 locations in dest : requires AVX512VL void Assembler::evpbroadcastss(XMMRegister dst, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 1, ""); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, - /* vex_w */ false, vector_len, /* legacy_mode */ false, /*no_mask_reg */ false); + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x18); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::evpbroadcastss(XMMRegister dst, Address src, int vector_len) { - assert(UseAVX > 1, ""); - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - InstructionMark im(this); + assert(VM_Version::supports_evex(), ""); assert(dst != xnoreg, "sanity"); - int dst_enc = dst->encoding(); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); // swap src<->dst for encoding - vex_prefix(src, 0, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, /* vex_w */ false, vector_len); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x18); emit_operand(dst, src); } // duplicate double precision fp from src into 2|4|8 locations in dest : requires AVX512VL void Assembler::evpbroadcastsd(XMMRegister dst, XMMRegister src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 1, ""); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, - /*vex_w */ true, vector_len, /* legacy_mode */ false, /*no_mask_reg */ false); + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x19); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::evpbroadcastsd(XMMRegister dst, Address src, int vector_len) { - _instruction_uses_vl = true; - assert(UseAVX > 1, ""); - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_64bit; - InstructionMark im(this); + assert(VM_Version::supports_evex(), ""); assert(dst != xnoreg, "sanity"); - int dst_enc = dst->encoding(); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); // swap src<->dst for encoding - vex_prefix(src, 0, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, /* vex_w */ true, vector_len); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x19); emit_operand(dst, src); } // duplicate 1-byte integer data from src into 16||32|64 locations in dest : requires AVX512BW and AVX512VL void Assembler::evpbroadcastb(XMMRegister dst, Register src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_evex(), ""); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, - /*vex_w */ false, vector_len, /* legacy_mode */ false, /*no_mask_reg */ false); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x7A); emit_int8((unsigned char)(0xC0 | encode)); } // duplicate 2-byte integer data from src into 8|16||32 locations in dest : requires AVX512BW and AVX512VL void Assembler::evpbroadcastw(XMMRegister dst, Register src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_evex(), ""); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, - /* vex_w */ false, vector_len, /* legacy_mode */ false, /*no_mask_reg */ false); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x7B); emit_int8((unsigned char)(0xC0 | encode)); } // duplicate 4-byte integer data from src into 4|8|16 locations in dest : requires AVX512VL void Assembler::evpbroadcastd(XMMRegister dst, Register src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_evex(), ""); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, - /* vex_w */ false, vector_len, /* legacy_mode */ false, /*no_mask_reg */ false); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x7C); emit_int8((unsigned char)(0xC0 | encode)); } // duplicate 8-byte integer data from src into 4|8|16 locations in dest : requires AVX512VL void Assembler::evpbroadcastq(XMMRegister dst, Register src, int vector_len) { - _instruction_uses_vl = true; assert(VM_Version::supports_evex(), ""); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, - /* vex_w */ true, vector_len, /* legacy_mode */ false, /*no_mask_reg */ false); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x7C); emit_int8((unsigned char)(0xC0 | encode)); } @@ -5603,8 +5673,8 @@ void Assembler::evpbroadcastq(XMMRegister dst, Register src, int vector_len) { // Carry-Less Multiplication Quadword void Assembler::pclmulqdq(XMMRegister dst, XMMRegister src, int mask) { assert(VM_Version::supports_clmul(), ""); - int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, /* no_mask_reg */ false, - VEX_OPCODE_0F_3A, /* rex_w */ false, AVX_128bit, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x44); emit_int8((unsigned char)(0xC0 | encode)); emit_int8((unsigned char)mask); @@ -5613,8 +5683,9 @@ void Assembler::pclmulqdq(XMMRegister dst, XMMRegister src, int mask) { // Carry-Less Multiplication Quadword void Assembler::vpclmulqdq(XMMRegister dst, XMMRegister nds, XMMRegister src, int mask) { assert(VM_Version::supports_avx() && VM_Version::supports_clmul(), ""); - int vector_len = AVX_128bit; - int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector_len, VEX_OPCODE_0F_3A, /* legacy_mode */ true); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8(0x44); emit_int8((unsigned char)(0xC0 | encode)); emit_int8((unsigned char)mask); @@ -5622,11 +5693,9 @@ void Assembler::vpclmulqdq(XMMRegister dst, XMMRegister nds, XMMRegister src, in void Assembler::vzeroupper() { assert(VM_Version::supports_avx(), ""); - if (UseAVX < 3) - { - (void)vex_prefix_and_encode(xmm0, xmm0, xmm0, VEX_SIMD_NONE); - emit_int8(0x77); - } + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + (void)vex_prefix_and_encode(0, 0, 0, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8(0x77); } @@ -6130,8 +6199,7 @@ int Assembler::rex_prefix_and_encode(int dst_enc, int src_enc, VexSimdPrefix pre if (pre > 0) { emit_int8(simd_pre[pre]); } - int encode = (rex_w) ? prefixq_and_encode(dst_enc, src_enc) : - prefix_and_encode(dst_enc, src_enc); + int encode = (rex_w) ? prefixq_and_encode(dst_enc, src_enc) : prefix_and_encode(dst_enc, src_enc); if (opc > 0) { emit_int8(0x0F); int opc2 = simd_opc[opc]; @@ -6143,7 +6211,9 @@ int Assembler::rex_prefix_and_encode(int dst_enc, int src_enc, VexSimdPrefix pre } -void Assembler::vex_prefix(bool vex_r, bool vex_b, bool vex_x, bool vex_w, int nds_enc, VexSimdPrefix pre, VexOpcode opc, int vector_len) { +void Assembler::vex_prefix(bool vex_r, bool vex_b, bool vex_x, int nds_enc, VexSimdPrefix pre, VexOpcode opc) { + int vector_len = _attributes->get_vector_len(); + bool vex_w = _attributes->is_rex_vex_w(); if (vex_b || vex_x || vex_w || (opc == VEX_OPCODE_0F_38) || (opc == VEX_OPCODE_0F_3A)) { prefix(VEX_3bytes); @@ -6167,13 +6237,13 @@ void Assembler::vex_prefix(bool vex_r, bool vex_b, bool vex_x, bool vex_w, int n } // This is a 4 byte encoding -void Assembler::evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool vex_w, bool evex_r, bool evex_v, - int nds_enc, VexSimdPrefix pre, VexOpcode opc, - bool is_extended_context, bool is_merge_context, - int vector_len, bool no_mask_reg ){ +void Assembler::evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, bool evex_v, int nds_enc, VexSimdPrefix pre, VexOpcode opc){ // EVEX 0x62 prefix prefix(EVEX_4bytes); - _evex_encoding = (vex_w ? VEX_W : 0) | (evex_r ? EVEX_Rb : 0); + bool vex_w = _attributes->is_rex_vex_w(); + int evex_encoding = (vex_w ? VEX_W : 0); + // EVEX.b is not currently used for broadcast of single element or data rounding modes + _attributes->set_evex_encoding(evex_encoding); // P0: byte 2, initialized to RXBR`00mm // instead of not'd @@ -6195,214 +6265,127 @@ void Assembler::evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool vex_w, bool emit_int8(byte3); // P2: byte 4 as zL'Lbv'aaa - int byte4 = (no_mask_reg) ? 0 : 1; // kregs are implemented in the low 3 bits as aaa (hard code k1, it will be initialized for now) + int byte4 = (_attributes->is_no_reg_mask()) ? 0 : 1; // kregs are implemented in the low 3 bits as aaa (hard code k1, it will be initialized for now) // EVEX.v` for extending EVEX.vvvv or VIDX byte4 |= (evex_v ? 0: EVEX_V); // third EXEC.b for broadcast actions - byte4 |= (is_extended_context ? EVEX_Rb : 0); + byte4 |= (_attributes->is_extended_context() ? EVEX_Rb : 0); // fourth EVEX.L'L for vector length : 0 is 128, 1 is 256, 2 is 512, currently we do not support 1024 - byte4 |= ((vector_len) & 0x3) << 5; + byte4 |= ((_attributes->get_vector_len())& 0x3) << 5; // last is EVEX.z for zero/merge actions - byte4 |= (is_merge_context ? EVEX_Z : 0); + byte4 |= (_attributes->is_clear_context() ? EVEX_Z : 0); emit_int8(byte4); } -void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix pre, - VexOpcode opc, bool vex_w, int vector_len, bool legacy_mode, bool no_mask_reg) { +void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes) { bool vex_r = ((xreg_enc & 8) == 8) ? 1 : 0; bool vex_b = adr.base_needs_rex(); bool vex_x = adr.index_needs_rex(); - _avx_vector_len = vector_len; + set_attributes(attributes); + attributes->set_current_assembler(this); // if vector length is turned off, revert to AVX for vectors smaller than 512-bit - if (_legacy_mode_vl && _instruction_uses_vl) { - switch (vector_len) { + if ((UseAVX > 2) && _legacy_mode_vl && attributes->uses_vl()) { + switch (attributes->get_vector_len()) { case AVX_128bit: case AVX_256bit: - legacy_mode = true; + attributes->set_is_legacy_mode(); break; } } - if ((UseAVX > 2) && (legacy_mode == false)) + if ((UseAVX > 2) && !attributes->is_legacy_mode()) { bool evex_r = (xreg_enc >= 16); bool evex_v = (nds_enc >= 16); - _is_evex_instruction = true; - evex_prefix(vex_r, vex_b, vex_x, vex_w, evex_r, evex_v, nds_enc, pre, opc, false, false, vector_len, no_mask_reg); + attributes->set_is_evex_instruction(); + evex_prefix(vex_r, vex_b, vex_x, evex_r, evex_v, nds_enc, pre, opc); } else { - vex_prefix(vex_r, vex_b, vex_x, vex_w, nds_enc, pre, opc, vector_len); + vex_prefix(vex_r, vex_b, vex_x, nds_enc, pre, opc); } - _instruction_uses_vl = false; } -int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, - bool vex_w, int vector_len, bool legacy_mode, bool no_mask_reg ) { +int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes) { bool vex_r = ((dst_enc & 8) == 8) ? 1 : 0; bool vex_b = ((src_enc & 8) == 8) ? 1 : 0; bool vex_x = false; - _avx_vector_len = vector_len; + set_attributes(attributes); + attributes->set_current_assembler(this); // if vector length is turned off, revert to AVX for vectors smaller than 512-bit - if (_legacy_mode_vl && _instruction_uses_vl) { - switch (vector_len) { + if ((UseAVX > 2) && _legacy_mode_vl && attributes->uses_vl()) { + switch (attributes->get_vector_len()) { case AVX_128bit: case AVX_256bit: - legacy_mode = true; + if ((dst_enc >= 16) | (nds_enc >= 16) | (src_enc >= 16)) { + // up propagate arithmetic instructions to meet RA requirements + attributes->set_vector_len(AVX_512bit); + } else { + attributes->set_is_legacy_mode(); + } break; } } - if ((UseAVX > 2) && (legacy_mode == false)) + if ((UseAVX > 2) && !attributes->is_legacy_mode()) { bool evex_r = (dst_enc >= 16); bool evex_v = (nds_enc >= 16); // can use vex_x as bank extender on rm encoding vex_x = (src_enc >= 16); - evex_prefix(vex_r, vex_b, vex_x, vex_w, evex_r, evex_v, nds_enc, pre, opc, false, false, vector_len, no_mask_reg); + attributes->set_is_evex_instruction(); + evex_prefix(vex_r, vex_b, vex_x, evex_r, evex_v, nds_enc, pre, opc); } else { - vex_prefix(vex_r, vex_b, vex_x, vex_w, nds_enc, pre, opc, vector_len); + vex_prefix(vex_r, vex_b, vex_x, nds_enc, pre, opc); } - _instruction_uses_vl = false; - // return modrm byte components for operands return (((dst_enc & 7) << 3) | (src_enc & 7)); } void Assembler::simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr, VexSimdPrefix pre, - bool no_mask_reg, VexOpcode opc, bool rex_w, int vector_len, bool legacy_mode) { + VexOpcode opc, InstructionAttr *attributes) { if (UseAVX > 0) { int xreg_enc = xreg->encoding(); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(adr, nds_enc, xreg_enc, pre, opc, rex_w, vector_len, legacy_mode, no_mask_reg); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + vex_prefix(adr, nds_enc, xreg_enc, pre, opc, attributes); } else { assert((nds == xreg) || (nds == xnoreg), "wrong sse encoding"); - rex_prefix(adr, xreg, pre, opc, rex_w); + rex_prefix(adr, xreg, pre, opc, attributes->is_rex_vex_w()); } } int Assembler::simd_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src, VexSimdPrefix pre, - bool no_mask_reg, VexOpcode opc, bool rex_w, int vector_len, bool legacy_mode) { + VexOpcode opc, InstructionAttr *attributes) { int dst_enc = dst->encoding(); int src_enc = src->encoding(); if (UseAVX > 0) { int nds_enc = nds->is_valid() ? nds->encoding() : 0; - return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, rex_w, vector_len, legacy_mode, no_mask_reg); + return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, attributes); } else { assert((nds == dst) || (nds == src) || (nds == xnoreg), "wrong sse encoding"); - return rex_prefix_and_encode(dst_enc, src_enc, pre, opc, rex_w); + return rex_prefix_and_encode(dst_enc, src_enc, pre, opc, attributes->is_rex_vex_w()); } } int Assembler::kreg_prefix_and_encode(KRegister dst, KRegister nds, KRegister src, VexSimdPrefix pre, - bool no_mask_reg, VexOpcode opc, bool rex_w, int vector_len) { - int dst_enc = dst->encoding(); - int src_enc = src->encoding(); + VexOpcode opc, InstructionAttr *attributes) { int nds_enc = nds->is_valid() ? nds->encoding() : 0; - return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, rex_w, vector_len, true, no_mask_reg); + return vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), pre, opc, attributes); } int Assembler::kreg_prefix_and_encode(KRegister dst, KRegister nds, Register src, VexSimdPrefix pre, - bool no_mask_reg, VexOpcode opc, bool rex_w, int vector_len) { - int dst_enc = dst->encoding(); - int src_enc = src->encoding(); + VexOpcode opc, InstructionAttr *attributes) { int nds_enc = nds->is_valid() ? nds->encoding() : 0; - return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, rex_w, vector_len, true, no_mask_reg); -} - -void Assembler::emit_simd_arith(int opcode, XMMRegister dst, Address src, VexSimdPrefix pre, bool no_mask_reg, bool legacy_mode) { - InstructionMark im(this); - simd_prefix(dst, dst, src, pre, no_mask_reg, VEX_OPCODE_0F, false, AVX_128bit, legacy_mode); - emit_int8(opcode); - emit_operand(dst, src); -} - -void Assembler::emit_simd_arith_q(int opcode, XMMRegister dst, Address src, VexSimdPrefix pre, bool no_mask_reg) { - InstructionMark im(this); - simd_prefix_q(dst, dst, src, pre, no_mask_reg); - emit_int8(opcode); - emit_operand(dst, src); -} - -void Assembler::emit_simd_arith(int opcode, XMMRegister dst, XMMRegister src, VexSimdPrefix pre, bool no_mask_reg, bool legacy_mode) { - int encode = simd_prefix_and_encode(dst, dst, src, pre, no_mask_reg, VEX_OPCODE_0F, false, AVX_128bit, legacy_mode); - emit_int8(opcode); - emit_int8((unsigned char)(0xC0 | encode)); -} - -void Assembler::emit_simd_arith_q(int opcode, XMMRegister dst, XMMRegister src, VexSimdPrefix pre, bool no_mask_reg) { - int encode = simd_prefix_and_encode(dst, dst, src, pre, no_mask_reg, VEX_OPCODE_0F, true, AVX_128bit); - emit_int8(opcode); - emit_int8((unsigned char)(0xC0 | encode)); -} - -// Versions with no second source register (non-destructive source). -void Assembler::emit_simd_arith_nonds(int opcode, XMMRegister dst, Address src, VexSimdPrefix pre, bool opNoRegMask) { - InstructionMark im(this); - simd_prefix(dst, xnoreg, src, pre, opNoRegMask); - emit_int8(opcode); - emit_operand(dst, src); -} - -void Assembler::emit_simd_arith_nonds_q(int opcode, XMMRegister dst, Address src, VexSimdPrefix pre, bool opNoRegMask) { - InstructionMark im(this); - simd_prefix_q(dst, xnoreg, src, pre, opNoRegMask); - emit_int8(opcode); - emit_operand(dst, src); -} - -void Assembler::emit_simd_arith_nonds(int opcode, XMMRegister dst, XMMRegister src, VexSimdPrefix pre, bool no_mask_reg, bool legacy_mode) { - int encode = simd_prefix_and_encode(dst, xnoreg, src, pre, no_mask_reg, VEX_OPCODE_0F, false, AVX_128bit, legacy_mode); - emit_int8(opcode); - emit_int8((unsigned char)(0xC0 | encode)); -} - -void Assembler::emit_simd_arith_nonds_q(int opcode, XMMRegister dst, XMMRegister src, VexSimdPrefix pre, bool no_mask_reg) { - int encode = simd_prefix_and_encode(dst, xnoreg, src, pre, no_mask_reg, VEX_OPCODE_0F, true); - emit_int8(opcode); - emit_int8((unsigned char)(0xC0 | encode)); -} - -// 3-operands AVX instructions -void Assembler::emit_vex_arith(int opcode, XMMRegister dst, XMMRegister nds, Address src, - VexSimdPrefix pre, int vector_len, bool no_mask_reg, bool legacy_mode) { - InstructionMark im(this); - vex_prefix(dst, nds, src, pre, vector_len, no_mask_reg, legacy_mode); - emit_int8(opcode); - emit_operand(dst, src); -} - -void Assembler::emit_vex_arith_q(int opcode, XMMRegister dst, XMMRegister nds, - Address src, VexSimdPrefix pre, int vector_len, bool no_mask_reg) { - InstructionMark im(this); - vex_prefix_q(dst, nds, src, pre, vector_len, no_mask_reg); - emit_int8(opcode); - emit_operand(dst, src); -} - -void Assembler::emit_vex_arith(int opcode, XMMRegister dst, XMMRegister nds, XMMRegister src, - VexSimdPrefix pre, int vector_len, bool no_mask_reg, bool legacy_mode) { - int encode = vex_prefix_and_encode(dst, nds, src, pre, vector_len, VEX_OPCODE_0F, legacy_mode, no_mask_reg); - emit_int8(opcode); - emit_int8((unsigned char)(0xC0 | encode)); -} - -void Assembler::emit_vex_arith_q(int opcode, XMMRegister dst, XMMRegister nds, XMMRegister src, - VexSimdPrefix pre, int vector_len, bool no_mask_reg) { - int src_enc = src->encoding(); - int dst_enc = dst->encoding(); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - int encode = vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, VEX_OPCODE_0F, true, vector_len, false, no_mask_reg); - emit_int8(opcode); - emit_int8((unsigned char)(0xC0 | encode)); + return vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), pre, opc, attributes); } void Assembler::cmppd(XMMRegister dst, XMMRegister nds, XMMRegister src, int cop, int vector_len) { assert(VM_Version::supports_avx(), ""); assert(!VM_Version::supports_evex(), ""); - int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector_len, VEX_OPCODE_0F, /* no_mask_reg */ false); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, nds, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xC2); emit_int8((unsigned char)(0xC0 | encode)); emit_int8((unsigned char)(0xF & cop)); @@ -6411,7 +6394,9 @@ void Assembler::cmppd(XMMRegister dst, XMMRegister nds, XMMRegister src, int cop void Assembler::vpblendd(XMMRegister dst, XMMRegister nds, XMMRegister src1, XMMRegister src2, int vector_len) { assert(VM_Version::supports_avx(), ""); assert(!VM_Version::supports_evex(), ""); - int encode = vex_prefix_and_encode(dst, nds, src1, VEX_SIMD_66, vector_len, VEX_OPCODE_0F_3A, /* no_mask_reg */ false); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); emit_int8((unsigned char)0x4B); emit_int8((unsigned char)(0xC0 | encode)); int src2_enc = src2->encoding(); @@ -6430,7 +6415,7 @@ void Assembler::lea(Register dst, Address src) { leal(dst, src); } -void Assembler::mov_literal32(Address dst, int32_t imm32, RelocationHolder const& rspec) { +void Assembler::mov_literal32(Address dst, int32_t imm32, RelocationHolder const& rspec) { InstructionMark im(this); emit_int8((unsigned char)0xC7); emit_operand(rax, dst); @@ -6948,15 +6933,17 @@ void Assembler::andq(Register dst, Register src) { void Assembler::andnq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - int encode = vex_prefix_0F38_and_encode_q_legacy(dst, src1, src2); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF2); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::andnq(Register dst, Register src1, Address src2) { - InstructionMark im(this); assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - vex_prefix_0F38_q_legacy(dst, src1, src2); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF2); emit_operand(dst, src2); } @@ -6983,45 +6970,51 @@ void Assembler::bswapq(Register reg) { void Assembler::blsiq(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - int encode = vex_prefix_0F38_and_encode_q_legacy(rbx, dst, src); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rbx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::blsiq(Register dst, Address src) { - InstructionMark im(this); assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - vex_prefix_0F38_q_legacy(rbx, dst, src); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + vex_prefix(src, dst->encoding(), rbx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rbx, src); } void Assembler::blsmskq(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - int encode = vex_prefix_0F38_and_encode_q_legacy(rdx, dst, src); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rdx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::blsmskq(Register dst, Address src) { - InstructionMark im(this); assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - vex_prefix_0F38_q_legacy(rdx, dst, src); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + vex_prefix(src, dst->encoding(), rdx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rdx, src); } void Assembler::blsrq(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - int encode = vex_prefix_0F38_and_encode_q_legacy(rcx, dst, src); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rcx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::blsrq(Register dst, Address src) { - InstructionMark im(this); assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - vex_prefix_0F38_q_legacy(rcx, dst, src); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + vex_prefix(src, dst->encoding(), rcx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rcx, src); } @@ -7095,45 +7088,44 @@ void Assembler::cmpxchgq(Register reg, Address adr) { void Assembler::cvtsi2sdq(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - int encode = simd_prefix_and_encode_q(dst, dst, src, VEX_SIMD_F2, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x2A); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::cvtsi2sdq(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } InstructionMark im(this); - simd_prefix_q(dst, dst, src, VEX_SIMD_F2, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x2A); emit_operand(dst, src); } void Assembler::cvtsi2ssq(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - if (VM_Version::supports_evex()) { - _tuple_type = EVEX_T1S; - _input_size_in_bits = EVEX_32bit; - } InstructionMark im(this); - simd_prefix_q(dst, dst, src, VEX_SIMD_F3, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + simd_prefix(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x2A); emit_operand(dst, src); } void Assembler::cvttsd2siq(Register dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - int encode = simd_prefix_and_encode_q(dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x2C); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::cvttss2siq(Register dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); - int encode = simd_prefix_and_encode_q(dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x2C); emit_int8((unsigned char)(0xC0 | encode)); } @@ -7316,7 +7308,8 @@ void Assembler::lzcntq(Register dst, Register src) { void Assembler::movdq(XMMRegister dst, Register src) { // table D-1 says MMX/SSE2 NOT_LP64(assert(VM_Version::supports_sse2(), "")); - int encode = simd_prefix_and_encode_q(dst, src, VEX_SIMD_66, /* no_mask_reg */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, xnoreg, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x6E); emit_int8((unsigned char)(0xC0 | encode)); } @@ -7324,8 +7317,9 @@ void Assembler::movdq(XMMRegister dst, Register src) { void Assembler::movdq(Register dst, XMMRegister src) { // table D-1 says MMX/SSE2 NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // swap src/dst to get correct prefix - int encode = simd_prefix_and_encode_q(src, dst, VEX_SIMD_66, /* no_mask_reg */ true); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x7E); emit_int8((unsigned char)(0xC0 | encode)); } @@ -7458,8 +7452,8 @@ void Assembler::mulq(Register src) { void Assembler::mulxq(Register dst1, Register dst2, Register src) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - int encode = vex_prefix_and_encode(dst1->encoding(), dst2->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, - /* vex_w */ true, AVX_128bit, /* legacy_mode */ true, /* no_mask_reg */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst1->encoding(), dst2->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF6); emit_int8((unsigned char)(0xC0 | encode)); } @@ -7621,8 +7615,8 @@ void Assembler::rorq(Register dst, int imm8) { void Assembler::rorxq(Register dst, Register src, int imm8) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, - /* vex_w */ true, AVX_128bit, /* legacy_mode */ true, /* no_mask_reg */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, &attributes); emit_int8((unsigned char)0xF0); emit_int8((unsigned char)(0xC0 | encode)); emit_int8(imm8); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 28210a7af47..8e9c00bbf2c 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -438,6 +438,8 @@ class ArrayAddress VALUE_OBJ_CLASS_SPEC { }; +class InstructionAttr; + // 64-bit refect the fxsave size which is 512 bytes and the new xsave area on EVEX which is another 2176 bytes // See fxsave and xsave(EVEX enabled) documentation for layout const int FPUStateSizeInWords = NOT_LP64(27) LP64_ONLY(2688 / wordSize); @@ -568,7 +570,8 @@ class Assembler : public AbstractAssembler { EVEX_8bit = 0, EVEX_16bit = 1, EVEX_32bit = 2, - EVEX_64bit = 3 + EVEX_64bit = 3, + EVEX_NObit = 4 }; enum WhichOperand { @@ -598,16 +601,12 @@ class Assembler : public AbstractAssembler { private: - int _evex_encoding; - int _input_size_in_bits; - int _avx_vector_len; - int _tuple_type; - bool _is_evex_instruction; bool _legacy_mode_bw; bool _legacy_mode_dq; bool _legacy_mode_vl; bool _legacy_mode_vlbw; - bool _instruction_uses_vl; + + class InstructionAttr *_attributes; // 64bit prefixes int prefix_and_encode(int reg_enc, bool byteinst = false); @@ -637,181 +636,30 @@ private: int rex_prefix_and_encode(int dst_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, bool rex_w); - void vex_prefix(bool vex_r, bool vex_b, bool vex_x, bool vex_w, - int nds_enc, VexSimdPrefix pre, VexOpcode opc, - int vector_len); + void vex_prefix(bool vex_r, bool vex_b, bool vex_x, int nds_enc, VexSimdPrefix pre, VexOpcode opc); - void evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool vex_w, bool evex_r, bool evex_v, - int nds_enc, VexSimdPrefix pre, VexOpcode opc, - bool is_extended_context, bool is_merge_context, - int vector_len, bool no_mask_reg ); + void evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, bool evex_v, + int nds_enc, VexSimdPrefix pre, VexOpcode opc); void vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, - bool vex_w, int vector_len, - bool legacy_mode = false, bool no_mask_reg = false); - - void vex_prefix(XMMRegister dst, XMMRegister nds, Address src, - VexSimdPrefix pre, int vector_len = AVX_128bit, - bool no_mask_reg = false, bool legacy_mode = false) { - int dst_enc = dst->encoding(); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst_enc, pre, VEX_OPCODE_0F, false, vector_len, legacy_mode, no_mask_reg); - } - - void vex_prefix_q(XMMRegister dst, XMMRegister nds, Address src, - VexSimdPrefix pre, int vector_len = AVX_128bit, - bool no_mask_reg = false) { - int dst_enc = dst->encoding(); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - vex_prefix(src, nds_enc, dst_enc, pre, VEX_OPCODE_0F, true, vector_len, false, no_mask_reg); - } - - void vex_prefix_0F38(Register dst, Register nds, Address src, bool no_mask_reg = false) { - bool vex_w = false; - int vector_len = AVX_128bit; - vex_prefix(src, nds->encoding(), dst->encoding(), - VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, - vector_len, no_mask_reg); - } - - void vex_prefix_0F38_legacy(Register dst, Register nds, Address src, bool no_mask_reg = false) { - bool vex_w = false; - int vector_len = AVX_128bit; - vex_prefix(src, nds->encoding(), dst->encoding(), - VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, - vector_len, true, no_mask_reg); - } - - void vex_prefix_0F38_q(Register dst, Register nds, Address src, bool no_mask_reg = false) { - bool vex_w = true; - int vector_len = AVX_128bit; - vex_prefix(src, nds->encoding(), dst->encoding(), - VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, - vector_len, no_mask_reg); - } - - void vex_prefix_0F38_q_legacy(Register dst, Register nds, Address src, bool no_mask_reg = false) { - bool vex_w = true; - int vector_len = AVX_128bit; - vex_prefix(src, nds->encoding(), dst->encoding(), - VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, - vector_len, true, no_mask_reg); - } + InstructionAttr *attributes); int vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, - bool vex_w, int vector_len, - bool legacy_mode, bool no_mask_reg); + InstructionAttr *attributes); - int vex_prefix_0F38_and_encode(Register dst, Register nds, Register src, bool no_mask_reg = false) { - bool vex_w = false; - int vector_len = AVX_128bit; - return vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), - VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, vector_len, - false, no_mask_reg); - } + void simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr, VexSimdPrefix pre, + VexOpcode opc, InstructionAttr *attributes); - int vex_prefix_0F38_and_encode_legacy(Register dst, Register nds, Register src, bool no_mask_reg = false) { - bool vex_w = false; - int vector_len = AVX_128bit; - return vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), - VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, vector_len, - true, no_mask_reg); - } + int simd_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src, VexSimdPrefix pre, + VexOpcode opc, InstructionAttr *attributes); - int vex_prefix_0F38_and_encode_q(Register dst, Register nds, Register src, bool no_mask_reg = false) { - bool vex_w = true; - int vector_len = AVX_128bit; - return vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), - VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, vector_len, - false, no_mask_reg); - } + int kreg_prefix_and_encode(KRegister dst, KRegister nds, KRegister src, VexSimdPrefix pre, + VexOpcode opc, InstructionAttr *attributes); - int vex_prefix_0F38_and_encode_q_legacy(Register dst, Register nds, Register src, bool no_mask_reg = false) { - bool vex_w = true; - int vector_len = AVX_128bit; - return vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), - VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, vector_len, - true, no_mask_reg); - } - - int vex_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src, - VexSimdPrefix pre, int vector_len = AVX_128bit, - VexOpcode opc = VEX_OPCODE_0F, bool legacy_mode = false, - bool no_mask_reg = false) { - int src_enc = src->encoding(); - int dst_enc = dst->encoding(); - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, false, vector_len, legacy_mode, no_mask_reg); - } - - void simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr, - VexSimdPrefix pre, bool no_mask_reg, VexOpcode opc = VEX_OPCODE_0F, - bool rex_w = false, int vector_len = AVX_128bit, bool legacy_mode = false); - - void simd_prefix(XMMRegister dst, Address src, VexSimdPrefix pre, - bool no_mask_reg, VexOpcode opc = VEX_OPCODE_0F) { - simd_prefix(dst, xnoreg, src, pre, no_mask_reg, opc); - } - - void simd_prefix(Address dst, XMMRegister src, VexSimdPrefix pre, bool no_mask_reg) { - simd_prefix(src, dst, pre, no_mask_reg); - } - void simd_prefix_q(XMMRegister dst, XMMRegister nds, Address src, - VexSimdPrefix pre, bool no_mask_reg = false) { - bool rex_w = true; - simd_prefix(dst, nds, src, pre, no_mask_reg, VEX_OPCODE_0F, rex_w); - } - - int simd_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src, - VexSimdPrefix pre, bool no_mask_reg, - VexOpcode opc = VEX_OPCODE_0F, - bool rex_w = false, int vector_len = AVX_128bit, - bool legacy_mode = false); - - int kreg_prefix_and_encode(KRegister dst, KRegister nds, KRegister src, - VexSimdPrefix pre, bool no_mask_reg, - VexOpcode opc = VEX_OPCODE_0F, - bool rex_w = false, int vector_len = AVX_128bit); - - int kreg_prefix_and_encode(KRegister dst, KRegister nds, Register src, - VexSimdPrefix pre, bool no_mask_reg, - VexOpcode opc = VEX_OPCODE_0F, - bool rex_w = false, int vector_len = AVX_128bit); - - // Move/convert 32-bit integer value. - int simd_prefix_and_encode(XMMRegister dst, XMMRegister nds, Register src, - VexSimdPrefix pre, bool no_mask_reg) { - // It is OK to cast from Register to XMMRegister to pass argument here - // since only encoding is used in simd_prefix_and_encode() and number of - // Gen and Xmm registers are the same. - return simd_prefix_and_encode(dst, nds, as_XMMRegister(src->encoding()), pre, no_mask_reg, VEX_OPCODE_0F); - } - int simd_prefix_and_encode(XMMRegister dst, Register src, VexSimdPrefix pre, bool no_mask_reg) { - return simd_prefix_and_encode(dst, xnoreg, src, pre, no_mask_reg); - } - int simd_prefix_and_encode(Register dst, XMMRegister src, - VexSimdPrefix pre, VexOpcode opc = VEX_OPCODE_0F, - bool no_mask_reg = false) { - return simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, pre, no_mask_reg, opc); - } - - // Move/convert 64-bit integer value. - int simd_prefix_and_encode_q(XMMRegister dst, XMMRegister nds, Register src, - VexSimdPrefix pre, bool no_mask_reg = false) { - bool rex_w = true; - return simd_prefix_and_encode(dst, nds, as_XMMRegister(src->encoding()), pre, no_mask_reg, VEX_OPCODE_0F, rex_w); - } - int simd_prefix_and_encode_q(XMMRegister dst, Register src, VexSimdPrefix pre, bool no_mask_reg) { - return simd_prefix_and_encode_q(dst, xnoreg, src, pre, no_mask_reg); - } - int simd_prefix_and_encode_q(Register dst, XMMRegister src, - VexSimdPrefix pre, VexOpcode opc = VEX_OPCODE_0F, - bool no_mask_reg = false) { - bool rex_w = true; - return simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, pre, no_mask_reg, opc, rex_w); - } + int kreg_prefix_and_encode(KRegister dst, KRegister nds, Register src, VexSimdPrefix pre, + VexOpcode opc, InstructionAttr *attributes); // Helper functions for groups of instructions void emit_arith_b(int op1, int op2, Register dst, int imm8); @@ -821,27 +669,6 @@ private: void emit_arith_imm32(int op1, int op2, Register dst, int32_t imm32); void emit_arith(int op1, int op2, Register dst, Register src); - void emit_simd_arith(int opcode, XMMRegister dst, Address src, VexSimdPrefix pre, bool no_mask_reg = false, bool legacy_mode = false); - void emit_simd_arith_q(int opcode, XMMRegister dst, Address src, VexSimdPrefix pre, bool no_mask_reg = false); - void emit_simd_arith(int opcode, XMMRegister dst, XMMRegister src, VexSimdPrefix pre, bool no_mask_reg = false, bool legacy_mode = false); - void emit_simd_arith_q(int opcode, XMMRegister dst, XMMRegister src, VexSimdPrefix pre, bool no_mask_reg = false); - void emit_simd_arith_nonds(int opcode, XMMRegister dst, Address src, VexSimdPrefix pre, bool no_mask_reg = false); - void emit_simd_arith_nonds_q(int opcode, XMMRegister dst, Address src, VexSimdPrefix pre, bool no_mask_reg = false); - void emit_simd_arith_nonds(int opcode, XMMRegister dst, XMMRegister src, VexSimdPrefix pre, bool no_mask_reg = false, bool legacy_mode = false); - void emit_simd_arith_nonds_q(int opcode, XMMRegister dst, XMMRegister src, VexSimdPrefix pre, bool no_mask_reg = false); - void emit_vex_arith(int opcode, XMMRegister dst, XMMRegister nds, - Address src, VexSimdPrefix pre, int vector_len, - bool no_mask_reg = false, bool legacy_mode = false); - void emit_vex_arith_q(int opcode, XMMRegister dst, XMMRegister nds, - Address src, VexSimdPrefix pre, int vector_len, - bool no_mask_reg = false); - void emit_vex_arith(int opcode, XMMRegister dst, XMMRegister nds, - XMMRegister src, VexSimdPrefix pre, int vector_len, - bool no_mask_reg = false, bool legacy_mode = false); - void emit_vex_arith_q(int opcode, XMMRegister dst, XMMRegister nds, - XMMRegister src, VexSimdPrefix pre, int vector_len, - bool no_mask_reg = false); - bool emit_compressed_disp_byte(int &disp); void emit_operand(Register reg, @@ -986,18 +813,16 @@ private: // belong in macro assembler but there is no need for both varieties to exist void init_attributes(void) { - _evex_encoding = 0; - _input_size_in_bits = 0; - _avx_vector_len = AVX_NoVec; - _tuple_type = EVEX_ETUP; - _is_evex_instruction = false; _legacy_mode_bw = (VM_Version::supports_avx512bw() == false); _legacy_mode_dq = (VM_Version::supports_avx512dq() == false); _legacy_mode_vl = (VM_Version::supports_avx512vl() == false); _legacy_mode_vlbw = (VM_Version::supports_avx512vlbw() == false); - _instruction_uses_vl = false; + _attributes = NULL; } + void set_attributes(InstructionAttr *attributes) { _attributes = attributes; } + void clear_attributes(void) { _attributes = NULL; } + void lea(Register dst, Address src); void mov(Register dst, Register src); @@ -2106,12 +1931,12 @@ private: void vextracti128h(Address dst, XMMRegister src); // Copy low 256bit into high 256bit of ZMM registers. - void vinserti64x4h(XMMRegister dst, XMMRegister nds, XMMRegister src); - void vinsertf64x4h(XMMRegister dst, XMMRegister nds, XMMRegister src); - void vextracti64x4h(XMMRegister dst, XMMRegister src); - void vextractf64x4h(XMMRegister dst, XMMRegister src); - void vextractf64x4h(Address dst, XMMRegister src); - void vinsertf64x4h(XMMRegister dst, Address src); + void vinserti64x4h(XMMRegister dst, XMMRegister nds, XMMRegister src, int value); + void vinsertf64x4h(XMMRegister dst, XMMRegister nds, XMMRegister src, int value); + void vextracti64x4h(XMMRegister dst, XMMRegister src, int value); + void vextractf64x4h(XMMRegister dst, XMMRegister src, int value); + void vextractf64x4h(Address dst, XMMRegister src, int value); + void vinsertf64x4h(XMMRegister dst, Address src, int value); // Copy targeted 128bit segments of the ZMM registers void vextracti64x2h(XMMRegister dst, XMMRegister src, int value); @@ -2173,4 +1998,95 @@ private: }; +// The Intel x86/Amd64 Assembler attributes: All fields enclosed here are to guide encoding level decisions. +// Specific set functions are for specialized use, else defaults or whatever was supplied to object construction +// are applied. +class InstructionAttr { +public: + InstructionAttr( + int vector_len, + bool rex_vex_w, + bool legacy_mode, + bool no_reg_mask, + bool uses_vl) + : + _avx_vector_len(vector_len), + _rex_vex_w(rex_vex_w), + _legacy_mode(legacy_mode), + _no_reg_mask(no_reg_mask), + _uses_vl(uses_vl), + _tuple_type(Assembler::EVEX_ETUP), + _input_size_in_bits(Assembler::EVEX_NObit), + _is_evex_instruction(false), + _evex_encoding(0), + _is_clear_context(false), + _is_extended_context(false), + _current_assembler(NULL) { + if (UseAVX < 3) _legacy_mode = true; + } + + ~InstructionAttr() { + if (_current_assembler != NULL) { + _current_assembler->clear_attributes(); + } + _current_assembler = NULL; + } + +private: + int _avx_vector_len; + bool _rex_vex_w; + bool _legacy_mode; + bool _no_reg_mask; + bool _uses_vl; + int _tuple_type; + int _input_size_in_bits; + bool _is_evex_instruction; + int _evex_encoding; + bool _is_clear_context; + bool _is_extended_context; + + Assembler *_current_assembler; + +public: + // query functions for field accessors + int get_vector_len(void) const { return _avx_vector_len; } + bool is_rex_vex_w(void) const { return _rex_vex_w; } + bool is_legacy_mode(void) const { return _legacy_mode; } + bool is_no_reg_mask(void) const { return _no_reg_mask; } + bool uses_vl(void) const { return _uses_vl; } + int get_tuple_type(void) const { return _tuple_type; } + int get_input_size(void) const { return _input_size_in_bits; } + int is_evex_instruction(void) const { return _is_evex_instruction; } + int get_evex_encoding(void) const { return _evex_encoding; } + bool is_clear_context(void) const { return _is_clear_context; } + bool is_extended_context(void) const { return _is_extended_context; } + + // Set the vector len manually + void set_vector_len(int vector_len) { _avx_vector_len = vector_len; } + + // Set the instruction to be encoded in AVX mode + void set_is_legacy_mode(void) { _legacy_mode = true; } + + // Set the current instuction to be encoded as an EVEX instuction + void set_is_evex_instruction(void) { _is_evex_instruction = true; } + + // Internal encoding data used in compressed immediate offset programming + void set_evex_encoding(int value) { _evex_encoding = value; } + + // Set the Evex.Z field to be used to clear all non directed XMM/YMM/ZMM components + void set_is_clear_context(void) { _is_clear_context = true; } + + // Map back to current asembler so that we can manage object level assocation + void set_current_assembler(Assembler *current_assembler) { _current_assembler = current_assembler; } + + // Address modifiers used for compressed displacement calculation + void set_address_attributes(int tuple_type, int input_size_in_bits) { + if (VM_Version::supports_evex()) { + _tuple_type = tuple_type; + _input_size_in_bits = input_size_in_bits; + } + } + +}; + #endif // CPU_X86_VM_ASSEMBLER_X86_HPP diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index 82e6c3d7931..cc93bd9ab4d 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -3714,7 +3714,7 @@ void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest) { if (left->as_xmm_float_reg() != dest->as_xmm_float_reg()) { __ movflt(dest->as_xmm_float_reg(), left->as_xmm_float_reg()); } - if (UseAVX > 1) { + if (UseAVX > 0) { __ vnegatess(dest->as_xmm_float_reg(), dest->as_xmm_float_reg(), ExternalAddress((address)float_signflip_pool)); } else { @@ -3725,7 +3725,7 @@ void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest) { if (left->as_xmm_double_reg() != dest->as_xmm_double_reg()) { __ movdbl(dest->as_xmm_double_reg(), left->as_xmm_double_reg()); } - if (UseAVX > 1) { + if (UseAVX > 0) { __ vnegatesd(dest->as_xmm_double_reg(), dest->as_xmm_double_reg(), ExternalAddress((address)double_signflip_pool)); } else { diff --git a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp index db3692f8ccc..ec0b81cc541 100644 --- a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp @@ -84,6 +84,7 @@ define_pd_global(bool, UseCISCSpill, true); define_pd_global(bool, OptoScheduling, false); define_pd_global(bool, OptoBundling, false); define_pd_global(bool, OptoRegScheduling, true); +define_pd_global(bool, SuperWordLoopUnrollAnalysis, true); define_pd_global(intx, ReservedCodeCacheSize, 48*M); define_pd_global(intx, NonProfiledCodeHeapSize, 21*M); diff --git a/hotspot/src/cpu/x86/vm/c2_init_x86.cpp b/hotspot/src/cpu/x86/vm/c2_init_x86.cpp index 32afe488f35..522af0038ae 100644 --- a/hotspot/src/cpu/x86/vm/c2_init_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c2_init_x86.cpp @@ -58,6 +58,4 @@ void Compile::pd_compiler2_init() { OptoReg::invalidate(i); } } - - SuperWordLoopUnrollAnalysis = true; } diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 0b1f94bc01b..bafa9ff0f6c 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -3651,12 +3651,71 @@ void MacroAssembler::movptr(Address dst, Register src) { LP64_ONLY(movq(dst, src)) NOT_LP64(movl(dst, src)); } +void MacroAssembler::movdqu(Address dst, XMMRegister src) { + if (UseAVX > 2 && !VM_Version::supports_avx512vl() && (src->encoding() > 15)) { + Assembler::vextractf32x4h(dst, src, 0); + } else { + Assembler::movdqu(dst, src); + } +} + +void MacroAssembler::movdqu(XMMRegister dst, Address src) { + if (UseAVX > 2 && !VM_Version::supports_avx512vl() && (dst->encoding() > 15)) { + Assembler::vinsertf32x4h(dst, src, 0); + } else { + Assembler::movdqu(dst, src); + } +} + +void MacroAssembler::movdqu(XMMRegister dst, XMMRegister src) { + if (UseAVX > 2 && !VM_Version::supports_avx512vl()) { + Assembler::evmovdqul(dst, src, Assembler::AVX_512bit); + } else { + Assembler::movdqu(dst, src); + } +} + void MacroAssembler::movdqu(XMMRegister dst, AddressLiteral src) { if (reachable(src)) { - Assembler::movdqu(dst, as_Address(src)); + movdqu(dst, as_Address(src)); } else { lea(rscratch1, src); - Assembler::movdqu(dst, Address(rscratch1, 0)); + movdqu(dst, Address(rscratch1, 0)); + } +} + +void MacroAssembler::vmovdqu(Address dst, XMMRegister src) { + if (UseAVX > 2 && !VM_Version::supports_avx512vl() && (src->encoding() > 15)) { + Assembler::vextractf64x4h(dst, src, 0); + } else { + Assembler::vmovdqu(dst, src); + } +} + +void MacroAssembler::vmovdqu(XMMRegister dst, Address src) { + if (UseAVX > 2 && !VM_Version::supports_avx512vl() && (dst->encoding() > 15)) { + Assembler::vinsertf64x4h(dst, src, 0); + } else { + Assembler::vmovdqu(dst, src); + } +} + +void MacroAssembler::vmovdqu(XMMRegister dst, XMMRegister src) { + if (UseAVX > 2 && !VM_Version::supports_avx512vl()) { + Assembler::evmovdqul(dst, src, Assembler::AVX_512bit); + } + else { + Assembler::vmovdqu(dst, src); + } +} + +void MacroAssembler::vmovdqu(XMMRegister dst, AddressLiteral src) { + if (reachable(src)) { + vmovdqu(dst, as_Address(src)); + } + else { + lea(rscratch1, src); + vmovdqu(dst, Address(rscratch1, 0)); } } @@ -3726,6 +3785,10 @@ void MacroAssembler::os_breakpoint() { call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint))); } +#ifdef _LP64 +#define XSTATE_BV 0x200 +#endif + void MacroAssembler::pop_CPU_state() { pop_FPU_state(); pop_IU_state(); @@ -3735,27 +3798,7 @@ void MacroAssembler::pop_FPU_state() { #ifndef _LP64 frstor(Address(rsp, 0)); #else - // AVX will continue to use the fxsave area. - // EVEX needs to utilize the xsave area, which is under different - // management. - if(VM_Version::supports_evex()) { - // EDX:EAX describe the XSAVE header and - // are obtained while fetching info for XCR0 via cpuid. - // These two registers make up 64-bits in the header for which bits - // 62:10 are currently reserved for future implementations and unused. Bit 63 - // is unused for our implementation as we do not utilize - // compressed XSAVE areas. Bits 9..8 are currently ignored as we do not use - // the functionality for PKRU state and MSR tracing. - // Ergo we are primarily concerned with bits 7..0, which define - // which ISA extensions and features are enabled for a given machine and are - // defined in XemXcr0Eax and is used to map the XSAVE area - // for restoring registers as described via XCR0. - movl(rdx,VM_Version::get_xsave_header_upper_segment()); - movl(rax,VM_Version::get_xsave_header_lower_segment()); - xrstor(Address(rsp, 0)); - } else { - fxrstor(Address(rsp, 0)); - } + fxrstor(Address(rsp, 0)); #endif addptr(rsp, FPUStateSizeInWords * wordSize); } @@ -3773,49 +3816,13 @@ void MacroAssembler::push_CPU_state() { push_FPU_state(); } -#ifdef _LP64 -#define XSTATE_BV 0x200 -#endif - void MacroAssembler::push_FPU_state() { subptr(rsp, FPUStateSizeInWords * wordSize); #ifndef _LP64 fnsave(Address(rsp, 0)); fwait(); #else - // AVX will continue to use the fxsave area. - // EVEX needs to utilize the xsave area, which is under different - // management. - if(VM_Version::supports_evex()) { - // Save a copy of EAX and EDX - push(rax); - push(rdx); - // EDX:EAX describe the XSAVE header and - // are obtained while fetching info for XCR0 via cpuid. - // These two registers make up 64-bits in the header for which bits - // 62:10 are currently reserved for future implementations and unused. Bit 63 - // is unused for our implementation as we do not utilize - // compressed XSAVE areas. Bits 9..8 are currently ignored as we do not use - // the functionality for PKRU state and MSR tracing. - // Ergo we are primarily concerned with bits 7..0, which define - // which ISA extensions and features are enabled for a given machine and are - // defined in XemXcr0Eax and is used to program XSAVE area - // for saving the required registers as defined in XCR0. - int xcr0_edx = VM_Version::get_xsave_header_upper_segment(); - int xcr0_eax = VM_Version::get_xsave_header_lower_segment(); - movl(rdx,xcr0_edx); - movl(rax,xcr0_eax); - xsave(Address(rsp, wordSize*2)); - // now Apply control bits and clear bytes 8..23 in the header - pop(rdx); - pop(rax); - movl(Address(rsp, XSTATE_BV), xcr0_eax); - movl(Address(rsp, XSTATE_BV+4), xcr0_edx); - andq(Address(rsp, XSTATE_BV+8), 0); - andq(Address(rsp, XSTATE_BV+16), 0); - } else { - fxsave(Address(rsp, 0)); - } + fxsave(Address(rsp, 0)); #endif // LP64 } @@ -4007,6 +4014,23 @@ void MacroAssembler::xorpd(XMMRegister dst, AddressLiteral src) { } } +void MacroAssembler::xorpd(XMMRegister dst, XMMRegister src) { + if (UseAVX > 2 && !VM_Version::supports_avx512dq() && (dst->encoding() == src->encoding())) { + Assembler::vpxor(dst, dst, src, Assembler::AVX_512bit); + } + else { + Assembler::xorpd(dst, src); + } +} + +void MacroAssembler::xorps(XMMRegister dst, XMMRegister src) { + if (UseAVX > 2 && !VM_Version::supports_avx512dq() && (dst->encoding() == src->encoding())) { + Assembler::vpxor(dst, dst, src, Assembler::AVX_512bit); + } else { + Assembler::xorps(dst, src); + } +} + void MacroAssembler::xorps(XMMRegister dst, AddressLiteral src) { // Used in sign-bit flipping with aligned address. assert((UseAVX > 0) || (((intptr_t)src.target() & 15) == 0), "SSE mode requires address alignment 16 bytes"); @@ -4050,6 +4074,682 @@ void MacroAssembler::vaddss(XMMRegister dst, XMMRegister nds, AddressLiteral src } } +void MacroAssembler::vabsss(XMMRegister dst, XMMRegister nds, XMMRegister src, AddressLiteral negate_field, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + int src_enc = src->encoding(); + if ((dst_enc < 16) && (nds_enc < 16)) { + vandps(dst, nds, negate_field, vector_len); + } else if ((src_enc < 16) && (dst_enc < 16)) { + movss(src, nds); + vandps(dst, src, negate_field, vector_len); + } else if (src_enc < 16) { + movss(src, nds); + vandps(src, src, negate_field, vector_len); + movss(dst, src); + } else if (dst_enc < 16) { + movdqu(src, xmm0); + movss(xmm0, nds); + vandps(dst, xmm0, negate_field, vector_len); + movdqu(xmm0, src); + } else if (nds_enc < 16) { + movdqu(src, xmm0); + vandps(xmm0, nds, negate_field, vector_len); + movss(dst, xmm0); + movdqu(xmm0, src); + } else { + movdqu(src, xmm0); + movss(xmm0, nds); + vandps(xmm0, xmm0, negate_field, vector_len); + movss(dst, xmm0); + movdqu(xmm0, src); + } +} + +void MacroAssembler::vabssd(XMMRegister dst, XMMRegister nds, XMMRegister src, AddressLiteral negate_field, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + int src_enc = src->encoding(); + if ((dst_enc < 16) && (nds_enc < 16)) { + vandpd(dst, nds, negate_field, vector_len); + } else if ((src_enc < 16) && (dst_enc < 16)) { + movsd(src, nds); + vandpd(dst, src, negate_field, vector_len); + } else if (src_enc < 16) { + movsd(src, nds); + vandpd(src, src, negate_field, vector_len); + movsd(dst, src); + } else if (dst_enc < 16) { + movdqu(src, xmm0); + movsd(xmm0, nds); + vandpd(dst, xmm0, negate_field, vector_len); + movdqu(xmm0, src); + } else if (nds_enc < 16) { + movdqu(src, xmm0); + vandpd(xmm0, nds, negate_field, vector_len); + movsd(dst, xmm0); + movdqu(xmm0, src); + } else { + movdqu(src, xmm0); + movsd(xmm0, nds); + vandpd(xmm0, xmm0, negate_field, vector_len); + movsd(dst, xmm0); + movdqu(xmm0, src); + } +} + +void MacroAssembler::vpaddb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + int src_enc = src->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpaddb(dst, nds, src, vector_len); + } else if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::vpaddb(dst, dst, src, vector_len); + } else if ((dst_enc < 16) && (nds_enc < 16)) { + // use nds as scratch for src + evmovdqul(nds, src, Assembler::AVX_512bit); + Assembler::vpaddb(dst, dst, nds, vector_len); + } else if ((src_enc < 16) && (nds_enc < 16)) { + // use nds as scratch for dst + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpaddb(nds, nds, src, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else if (dst_enc < 16) { + // use nds as scatch for xmm0 to hold src + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::vpaddb(dst, dst, xmm0, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs are in the upper bank + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm1, src, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpaddb(xmm0, xmm0, xmm1, vector_len); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::vpaddb(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpaddb(dst, nds, src, vector_len); + } else if (dst_enc < 16) { + Assembler::vpaddb(dst, dst, src, vector_len); + } else if (nds_enc < 16) { + // implies dst_enc in upper bank with src as scratch + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpaddb(nds, nds, src, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs in upper bank + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpaddb(xmm0, xmm0, src, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } +} + +void MacroAssembler::vpaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + int src_enc = src->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpaddw(dst, nds, src, vector_len); + } else if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::vpaddw(dst, dst, src, vector_len); + } else if ((dst_enc < 16) && (nds_enc < 16)) { + // use nds as scratch for src + evmovdqul(nds, src, Assembler::AVX_512bit); + Assembler::vpaddw(dst, dst, nds, vector_len); + } else if ((src_enc < 16) && (nds_enc < 16)) { + // use nds as scratch for dst + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpaddw(nds, nds, src, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else if (dst_enc < 16) { + // use nds as scatch for xmm0 to hold src + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::vpaddw(dst, dst, xmm0, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs are in the upper bank + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm1, src, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpaddw(xmm0, xmm0, xmm1, vector_len); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::vpaddw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpaddw(dst, nds, src, vector_len); + } else if (dst_enc < 16) { + Assembler::vpaddw(dst, dst, src, vector_len); + } else if (nds_enc < 16) { + // implies dst_enc in upper bank with src as scratch + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpaddw(nds, nds, src, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs in upper bank + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpaddw(xmm0, xmm0, src, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } +} + +void MacroAssembler::vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + int src_enc = src->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpsubb(dst, nds, src, vector_len); + } else if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::vpsubb(dst, dst, src, vector_len); + } else if ((dst_enc < 16) && (nds_enc < 16)) { + // use nds as scratch for src + evmovdqul(nds, src, Assembler::AVX_512bit); + Assembler::vpsubb(dst, dst, nds, vector_len); + } else if ((src_enc < 16) && (nds_enc < 16)) { + // use nds as scratch for dst + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpsubb(nds, nds, src, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else if (dst_enc < 16) { + // use nds as scatch for xmm0 to hold src + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::vpsubb(dst, dst, xmm0, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs are in the upper bank + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm1, src, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpsubb(xmm0, xmm0, xmm1, vector_len); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::vpsubb(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpsubb(dst, nds, src, vector_len); + } else if (dst_enc < 16) { + Assembler::vpsubb(dst, dst, src, vector_len); + } else if (nds_enc < 16) { + // implies dst_enc in upper bank with src as scratch + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpsubb(nds, nds, src, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs in upper bank + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpsubw(xmm0, xmm0, src, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } +} + +void MacroAssembler::vpsubw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + int src_enc = src->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpsubw(dst, nds, src, vector_len); + } else if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::vpsubw(dst, dst, src, vector_len); + } else if ((dst_enc < 16) && (nds_enc < 16)) { + // use nds as scratch for src + evmovdqul(nds, src, Assembler::AVX_512bit); + Assembler::vpsubw(dst, dst, nds, vector_len); + } else if ((src_enc < 16) && (nds_enc < 16)) { + // use nds as scratch for dst + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpsubw(nds, nds, src, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else if (dst_enc < 16) { + // use nds as scatch for xmm0 to hold src + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::vpsubw(dst, dst, xmm0, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs are in the upper bank + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm1, src, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpsubw(xmm0, xmm0, xmm1, vector_len); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::vpsubw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpsubw(dst, nds, src, vector_len); + } else if (dst_enc < 16) { + Assembler::vpsubw(dst, dst, src, vector_len); + } else if (nds_enc < 16) { + // implies dst_enc in upper bank with src as scratch + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpsubw(nds, nds, src, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs in upper bank + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpsubw(xmm0, xmm0, src, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } +} + + +void MacroAssembler::vpmullw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + int src_enc = src->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpmullw(dst, nds, src, vector_len); + } else if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::vpmullw(dst, dst, src, vector_len); + } else if ((dst_enc < 16) && (nds_enc < 16)) { + // use nds as scratch for src + evmovdqul(nds, src, Assembler::AVX_512bit); + Assembler::vpmullw(dst, dst, nds, vector_len); + } else if ((src_enc < 16) && (nds_enc < 16)) { + // use nds as scratch for dst + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpmullw(nds, nds, src, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else if (dst_enc < 16) { + // use nds as scatch for xmm0 to hold src + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::vpmullw(dst, dst, xmm0, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs are in the upper bank + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm1, src, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpmullw(xmm0, xmm0, xmm1, vector_len); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::vpmullw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpmullw(dst, nds, src, vector_len); + } else if (dst_enc < 16) { + Assembler::vpmullw(dst, dst, src, vector_len); + } else if (nds_enc < 16) { + // implies dst_enc in upper bank with src as scratch + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpmullw(nds, nds, src, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs in upper bank + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpmullw(xmm0, xmm0, src, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } +} + +void MacroAssembler::vpsraw(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + int shift_enc = shift->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpsraw(dst, nds, shift, vector_len); + } else if ((dst_enc < 16) && (shift_enc < 16)) { + Assembler::vpsraw(dst, dst, shift, vector_len); + } else if ((dst_enc < 16) && (nds_enc < 16)) { + // use nds_enc as scratch with shift + evmovdqul(nds, shift, Assembler::AVX_512bit); + Assembler::vpsraw(dst, dst, nds, vector_len); + } else if ((shift_enc < 16) && (nds_enc < 16)) { + // use nds as scratch with dst + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpsraw(nds, nds, shift, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else if (dst_enc < 16) { + // use nds to save a copy of xmm0 and hold shift + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, shift, Assembler::AVX_512bit); + Assembler::vpsraw(dst, dst, xmm0, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } else if (nds_enc < 16) { + // use nds as dest as temps + evmovdqul(nds, dst, Assembler::AVX_512bit); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, shift, Assembler::AVX_512bit); + Assembler::vpsraw(nds, nds, xmm0, vector_len); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs are in the upper bank + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm1, shift, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpsllw(xmm0, xmm0, xmm1, vector_len); + evmovdqul(xmm1, dst, Assembler::AVX_512bit); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::vpsraw(XMMRegister dst, XMMRegister nds, int shift, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpsraw(dst, nds, shift, vector_len); + } else if (dst_enc < 16) { + Assembler::vpsraw(dst, dst, shift, vector_len); + } else if (nds_enc < 16) { + // use nds as scratch + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpsraw(nds, nds, shift, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else { + // use nds as scratch for xmm0 + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpsraw(xmm0, xmm0, shift, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } +} + +void MacroAssembler::vpsrlw(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + int shift_enc = shift->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpsrlw(dst, nds, shift, vector_len); + } else if ((dst_enc < 16) && (shift_enc < 16)) { + Assembler::vpsrlw(dst, dst, shift, vector_len); + } else if ((dst_enc < 16) && (nds_enc < 16)) { + // use nds_enc as scratch with shift + evmovdqul(nds, shift, Assembler::AVX_512bit); + Assembler::vpsrlw(dst, dst, nds, vector_len); + } else if ((shift_enc < 16) && (nds_enc < 16)) { + // use nds as scratch with dst + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpsrlw(nds, nds, shift, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else if (dst_enc < 16) { + // use nds to save a copy of xmm0 and hold shift + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, shift, Assembler::AVX_512bit); + Assembler::vpsrlw(dst, dst, xmm0, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } else if (nds_enc < 16) { + // use nds as dest as temps + evmovdqul(nds, dst, Assembler::AVX_512bit); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, shift, Assembler::AVX_512bit); + Assembler::vpsrlw(nds, nds, xmm0, vector_len); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs are in the upper bank + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm1, shift, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpsllw(xmm0, xmm0, xmm1, vector_len); + evmovdqul(xmm1, dst, Assembler::AVX_512bit); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::vpsrlw(XMMRegister dst, XMMRegister nds, int shift, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpsrlw(dst, nds, shift, vector_len); + } else if (dst_enc < 16) { + Assembler::vpsrlw(dst, dst, shift, vector_len); + } else if (nds_enc < 16) { + // use nds as scratch + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpsrlw(nds, nds, shift, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else { + // use nds as scratch for xmm0 + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpsrlw(xmm0, xmm0, shift, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } +} + +void MacroAssembler::vpsllw(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + int shift_enc = shift->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpsllw(dst, nds, shift, vector_len); + } else if ((dst_enc < 16) && (shift_enc < 16)) { + Assembler::vpsllw(dst, dst, shift, vector_len); + } else if ((dst_enc < 16) && (nds_enc < 16)) { + // use nds_enc as scratch with shift + evmovdqul(nds, shift, Assembler::AVX_512bit); + Assembler::vpsllw(dst, dst, nds, vector_len); + } else if ((shift_enc < 16) && (nds_enc < 16)) { + // use nds as scratch with dst + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpsllw(nds, nds, shift, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else if (dst_enc < 16) { + // use nds to save a copy of xmm0 and hold shift + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, shift, Assembler::AVX_512bit); + Assembler::vpsllw(dst, dst, xmm0, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } else if (nds_enc < 16) { + // use nds as dest as temps + evmovdqul(nds, dst, Assembler::AVX_512bit); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, shift, Assembler::AVX_512bit); + Assembler::vpsllw(nds, nds, xmm0, vector_len); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs are in the upper bank + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm1, shift, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpsllw(xmm0, xmm0, xmm1, vector_len); + evmovdqul(xmm1, dst, Assembler::AVX_512bit); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::vpsllw(XMMRegister dst, XMMRegister nds, int shift, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpsllw(dst, nds, shift, vector_len); + } else if (dst_enc < 16) { + Assembler::vpsllw(dst, dst, shift, vector_len); + } else if (nds_enc < 16) { + // use nds as scratch + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpsllw(nds, nds, shift, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else { + // use nds as scratch for xmm0 + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpsllw(xmm0, xmm0, shift, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } +} + +// This instruction exists within macros, ergo we cannot control its input +// when emitted through those patterns. +void MacroAssembler::punpcklbw(XMMRegister dst, XMMRegister src) { + if (VM_Version::supports_avx512nobw()) { + int dst_enc = dst->encoding(); + int src_enc = src->encoding(); + if (dst_enc == src_enc) { + if (dst_enc < 16) { + Assembler::punpcklbw(dst, src); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::punpcklbw(xmm0, xmm0); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } + } else { + if ((src_enc < 16) && (dst_enc < 16)) { + Assembler::punpcklbw(dst, src); + } else if (src_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::punpcklbw(xmm0, src); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else if (dst_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::punpcklbw(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + evmovdqul(xmm1, src, Assembler::AVX_512bit); + Assembler::punpcklbw(xmm0, xmm1); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } + } + } else { + Assembler::punpcklbw(dst, src); + } +} + +// This instruction exists within macros, ergo we cannot control its input +// when emitted through those patterns. +void MacroAssembler::pshuflw(XMMRegister dst, XMMRegister src, int mode) { + if (VM_Version::supports_avx512nobw()) { + int dst_enc = dst->encoding(); + int src_enc = src->encoding(); + if (dst_enc == src_enc) { + if (dst_enc < 16) { + Assembler::pshuflw(dst, src, mode); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::pshuflw(xmm0, xmm0, mode); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } + } else { + if ((src_enc < 16) && (dst_enc < 16)) { + Assembler::pshuflw(dst, src, mode); + } else if (src_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::pshuflw(xmm0, src, mode); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else if (dst_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::pshuflw(dst, xmm0, mode); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + evmovdqul(xmm1, src, Assembler::AVX_512bit); + Assembler::pshuflw(xmm0, xmm1, mode); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } + } + } else { + Assembler::pshuflw(dst, src, mode); + } +} + void MacroAssembler::vandpd(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len) { if (reachable(src)) { vandpd(dst, nds, as_Address(src), vector_len); @@ -4133,31 +4833,16 @@ void MacroAssembler::vnegatess(XMMRegister dst, XMMRegister nds, AddressLiteral subptr(rsp, 64); evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); movflt(xmm0, nds); - if (reachable(src)) { - vxorps(xmm0, xmm0, as_Address(src), Assembler::AVX_128bit); - } else { - lea(rscratch1, src); - vxorps(xmm0, xmm0, Address(rscratch1, 0), Assembler::AVX_128bit); - } + vxorps(xmm0, xmm0, src, Assembler::AVX_128bit); movflt(dst, xmm0); evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); addptr(rsp, 64); } else { movflt(dst, nds); - if (reachable(src)) { - vxorps(dst, dst, as_Address(src), Assembler::AVX_128bit); - } else { - lea(rscratch1, src); - vxorps(dst, dst, Address(rscratch1, 0), Assembler::AVX_128bit); - } + vxorps(dst, dst, src, Assembler::AVX_128bit); } } else { - if (reachable(src)) { - vxorps(dst, nds, as_Address(src), Assembler::AVX_128bit); - } else { - lea(rscratch1, src); - vxorps(dst, nds, Address(rscratch1, 0), Assembler::AVX_128bit); - } + vxorps(dst, nds, src, Assembler::AVX_128bit); } } @@ -4172,31 +4857,16 @@ void MacroAssembler::vnegatesd(XMMRegister dst, XMMRegister nds, AddressLiteral subptr(rsp, 64); evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); movdbl(xmm0, nds); - if (reachable(src)) { - vxorps(xmm0, xmm0, as_Address(src), Assembler::AVX_128bit); - } else { - lea(rscratch1, src); - vxorps(xmm0, xmm0, Address(rscratch1, 0), Assembler::AVX_128bit); - } + vxorpd(xmm0, xmm0, src, Assembler::AVX_128bit); movdbl(dst, xmm0); evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); addptr(rsp, 64); } else { movdbl(dst, nds); - if (reachable(src)) { - vxorps(dst, dst, as_Address(src), Assembler::AVX_128bit); - } else { - lea(rscratch1, src); - vxorps(dst, dst, Address(rscratch1, 0), Assembler::AVX_128bit); - } + vxorpd(dst, dst, src, Assembler::AVX_128bit); } } else { - if (reachable(src)) { - vxorpd(dst, nds, as_Address(src), Assembler::AVX_128bit); - } else { - lea(rscratch1, src); - vxorpd(dst, nds, Address(rscratch1, 0), Assembler::AVX_128bit); - } + vxorpd(dst, nds, src, Assembler::AVX_128bit); } } @@ -4688,7 +5358,6 @@ void MacroAssembler::fp_runtime_fallback(address runtime_entry, int nb_args, int pusha(); // if we are coming from c1, xmm registers may be live - int off = 0; int num_xmm_regs = LP64_ONLY(16) NOT_LP64(8); if (UseAVX > 2) { num_xmm_regs = LP64_ONLY(32) NOT_LP64(8); @@ -4697,7 +5366,7 @@ void MacroAssembler::fp_runtime_fallback(address runtime_entry, int nb_args, int if (UseSSE == 1) { subptr(rsp, sizeof(jdouble)*8); for (int n = 0; n < 8; n++) { - movflt(Address(rsp, off++*sizeof(jdouble)), as_XMMRegister(n)); + movflt(Address(rsp, n*sizeof(jdouble)), as_XMMRegister(n)); } } else if (UseSSE >= 2) { if (UseAVX > 2) { @@ -4709,37 +5378,35 @@ void MacroAssembler::fp_runtime_fallback(address runtime_entry, int nb_args, int #ifdef COMPILER2 if (MaxVectorSize > 16) { if(UseAVX > 2) { - // Save upper half of ZMM registes + // Save upper half of ZMM registers subptr(rsp, 32*num_xmm_regs); for (int n = 0; n < num_xmm_regs; n++) { - vextractf64x4h(Address(rsp, off++*32), as_XMMRegister(n)); + vextractf64x4h(Address(rsp, n*32), as_XMMRegister(n), 1); } - off = 0; } assert(UseAVX > 0, "256 bit vectors are supported only with AVX"); - // Save upper half of YMM registes + // Save upper half of YMM registers subptr(rsp, 16*num_xmm_regs); for (int n = 0; n < num_xmm_regs; n++) { - vextractf128h(Address(rsp, off++*16), as_XMMRegister(n)); + vextractf128h(Address(rsp, n*16), as_XMMRegister(n)); } } #endif // Save whole 128bit (16 bytes) XMM registers subptr(rsp, 16*num_xmm_regs); - off = 0; #ifdef _LP64 - if (VM_Version::supports_avx512novl()) { + if (VM_Version::supports_evex()) { for (int n = 0; n < num_xmm_regs; n++) { - vextractf32x4h(Address(rsp, off++*16), as_XMMRegister(n), 0); + vextractf32x4h(Address(rsp, n*16), as_XMMRegister(n), 0); } } else { for (int n = 0; n < num_xmm_regs; n++) { - movdqu(Address(rsp, off++*16), as_XMMRegister(n)); + movdqu(Address(rsp, n*16), as_XMMRegister(n)); } } #else for (int n = 0; n < num_xmm_regs; n++) { - movdqu(Address(rsp, off++*16), as_XMMRegister(n)); + movdqu(Address(rsp, n*16), as_XMMRegister(n)); } #endif } @@ -4808,44 +5475,40 @@ void MacroAssembler::fp_runtime_fallback(address runtime_entry, int nb_args, int addptr(rsp, sizeof(jdouble)*nb_args); } - off = 0; if (UseSSE == 1) { for (int n = 0; n < 8; n++) { - movflt(as_XMMRegister(n), Address(rsp, off++*sizeof(jdouble))); + movflt(as_XMMRegister(n), Address(rsp, n*sizeof(jdouble))); } addptr(rsp, sizeof(jdouble)*8); } else if (UseSSE >= 2) { - // Restore whole 128bit (16 bytes) XMM regiters + // Restore whole 128bit (16 bytes) XMM registers #ifdef _LP64 - if (VM_Version::supports_avx512novl()) { - for (int n = 0; n < num_xmm_regs; n++) { - vinsertf32x4h(as_XMMRegister(n), Address(rsp, off++*16), 0); - } - } - else { - for (int n = 0; n < num_xmm_regs; n++) { - movdqu(as_XMMRegister(n), Address(rsp, off++*16)); - } - } -#else + if (VM_Version::supports_evex()) { for (int n = 0; n < num_xmm_regs; n++) { - movdqu(as_XMMRegister(n), Address(rsp, off++ * 16)); + vinsertf32x4h(as_XMMRegister(n), Address(rsp, n*16), 0); } + } else { + for (int n = 0; n < num_xmm_regs; n++) { + movdqu(as_XMMRegister(n), Address(rsp, n*16)); + } + } +#else + for (int n = 0; n < num_xmm_regs; n++) { + movdqu(as_XMMRegister(n), Address(rsp, n*16)); + } #endif addptr(rsp, 16*num_xmm_regs); #ifdef COMPILER2 if (MaxVectorSize > 16) { - // Restore upper half of YMM registes. - off = 0; + // Restore upper half of YMM registers. for (int n = 0; n < num_xmm_regs; n++) { - vinsertf128h(as_XMMRegister(n), Address(rsp, off++*16)); + vinsertf128h(as_XMMRegister(n), Address(rsp, n*16)); } addptr(rsp, 16*num_xmm_regs); if(UseAVX > 2) { - off = 0; for (int n = 0; n < num_xmm_regs; n++) { - vinsertf64x4h(as_XMMRegister(n), Address(rsp, off++*32)); + vinsertf64x4h(as_XMMRegister(n), Address(rsp, n*32), 1); } addptr(rsp, 32*num_xmm_regs); } @@ -6831,7 +7494,7 @@ void MacroAssembler::string_indexof_char(Register str1, Register cnt1, Register bind(SCAN_TO_16_CHAR_LOOP); vmovdqu(vec3, Address(result, 0)); - vpcmpeqw(vec3, vec3, vec1, true); + vpcmpeqw(vec3, vec3, vec1, 1); vptest(vec2, vec3); jcc(Assembler::carryClear, FOUND_CHAR); addptr(result, 32); @@ -7671,7 +8334,7 @@ void MacroAssembler::generate_fill(BasicType t, bool aligned, BIND(L_check_fill_32_bytes); addl(count, 8 << shift); jccb(Assembler::less, L_check_fill_8_bytes); - evmovdqul(Address(to, 0), xtmp, Assembler::AVX_256bit); + vmovdqu(Address(to, 0), xtmp); addptr(to, 32); subl(count, 8 << shift); diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index 1b0185110d7..076600efa34 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -962,10 +962,15 @@ public: void divss(XMMRegister dst, AddressLiteral src); // Move Unaligned Double Quadword - void movdqu(Address dst, XMMRegister src) { Assembler::movdqu(dst, src); } - void movdqu(XMMRegister dst, Address src) { Assembler::movdqu(dst, src); } - void movdqu(XMMRegister dst, XMMRegister src) { Assembler::movdqu(dst, src); } + void movdqu(Address dst, XMMRegister src); + void movdqu(XMMRegister dst, Address src); + void movdqu(XMMRegister dst, XMMRegister src); void movdqu(XMMRegister dst, AddressLiteral src); + // AVX Unaligned forms + void vmovdqu(Address dst, XMMRegister src); + void vmovdqu(XMMRegister dst, Address src); + void vmovdqu(XMMRegister dst, XMMRegister src); + void vmovdqu(XMMRegister dst, AddressLiteral src); // Move Aligned Double Quadword void movdqa(XMMRegister dst, Address src) { Assembler::movdqa(dst, src); } @@ -1024,12 +1029,12 @@ public: void ucomisd(XMMRegister dst, AddressLiteral src); // Bitwise Logical XOR of Packed Double-Precision Floating-Point Values - void xorpd(XMMRegister dst, XMMRegister src) { Assembler::xorpd(dst, src); } + void xorpd(XMMRegister dst, XMMRegister src); void xorpd(XMMRegister dst, Address src) { Assembler::xorpd(dst, src); } void xorpd(XMMRegister dst, AddressLiteral src); // Bitwise Logical XOR of Packed Single-Precision Floating-Point Values - void xorps(XMMRegister dst, XMMRegister src) { Assembler::xorps(dst, src); } + void xorps(XMMRegister dst, XMMRegister src); void xorps(XMMRegister dst, Address src) { Assembler::xorps(dst, src); } void xorps(XMMRegister dst, AddressLiteral src); @@ -1047,6 +1052,39 @@ public: void vaddss(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vaddss(dst, nds, src); } void vaddss(XMMRegister dst, XMMRegister nds, AddressLiteral src); + void vabsss(XMMRegister dst, XMMRegister nds, XMMRegister src, AddressLiteral negate_field, int vector_len); + void vabssd(XMMRegister dst, XMMRegister nds, XMMRegister src, AddressLiteral negate_field, int vector_len); + + void vpaddb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpaddb(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + + void vpaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpaddw(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + + void vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpsubb(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + + void vpsubw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpsubw(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + + void vpmullw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpmullw(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + + void vpsraw(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len); + void vpsraw(XMMRegister dst, XMMRegister nds, int shift, int vector_len); + + void vpsrlw(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len); + void vpsrlw(XMMRegister dst, XMMRegister nds, int shift, int vector_len); + + void vpsllw(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len); + void vpsllw(XMMRegister dst, XMMRegister nds, int shift, int vector_len); + + void punpcklbw(XMMRegister dst, XMMRegister src); + void punpcklbw(XMMRegister dst, Address src) { Assembler::punpcklbw(dst, src); } + + void pshuflw(XMMRegister dst, XMMRegister src, int mode); + void pshuflw(XMMRegister dst, Address src, int mode) { Assembler::pshuflw(dst, src, mode); } + void vandpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { Assembler::vandpd(dst, nds, src, vector_len); } void vandpd(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { Assembler::vandpd(dst, nds, src, vector_len); } void vandpd(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len); diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index e2047549877..708b8b9d441 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp @@ -192,31 +192,22 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ } } else if(UseSSE >= 2) { // Save whole 128bit (16 bytes) XMM regiters - if (VM_Version::supports_avx512novl()) { - for (int n = 0; n < num_xmm_regs; n++) { - __ vextractf32x4h(Address(rsp, off*wordSize), as_XMMRegister(n), 0); - off += delta; - } - } else { - for (int n = 0; n < num_xmm_regs; n++) { - __ movdqu(Address(rsp, off*wordSize), as_XMMRegister(n)); - off += delta; - } + for (int n = 0; n < num_xmm_regs; n++) { + __ movdqu(Address(rsp, off*wordSize), as_XMMRegister(n)); + off += delta; } } if (vect_words > 0) { assert(vect_words*wordSize == 128, ""); __ subptr(rsp, 128); // Save upper half of YMM registes - off = 0; for (int n = 0; n < num_xmm_regs; n++) { - __ vextractf128h(Address(rsp, off++*16), as_XMMRegister(n)); + __ vextractf128h(Address(rsp, n*16), as_XMMRegister(n)); } if (UseAVX > 2) { __ subptr(rsp, 256); // Save upper half of ZMM registes - off = 0; for (int n = 0; n < num_xmm_regs; n++) { - __ vextractf64x4h(Address(rsp, off++*32), as_XMMRegister(n)); + __ vextractf64x4h(Address(rsp, n*32), as_XMMRegister(n), 1); } } } @@ -285,31 +276,23 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_ve off += delta; } } else if (UseSSE >= 2) { - if (VM_Version::supports_avx512novl()) { - for (int n = 0; n < num_xmm_regs; n++) { - __ vinsertf32x4h(as_XMMRegister(n), Address(rsp, off*wordSize+additional_frame_bytes), 0); - off += delta; - } - } else { - for (int n = 0; n < num_xmm_regs; n++) { - __ movdqu(as_XMMRegister(n), Address(rsp, off*wordSize+additional_frame_bytes)); - off += delta; - } + for (int n = 0; n < num_xmm_regs; n++) { + __ movdqu(as_XMMRegister(n), Address(rsp, off*wordSize+additional_frame_bytes)); + off += delta; } } if (restore_vectors) { + assert(additional_frame_bytes == 128, ""); if (UseAVX > 2) { - off = 0; + // Restore upper half of ZMM registers. for (int n = 0; n < num_xmm_regs; n++) { - __ vinsertf64x4h(as_XMMRegister(n), Address(rsp, off++*32)); + __ vinsertf64x4h(as_XMMRegister(n), Address(rsp, n*32), 1); } __ addptr(rsp, additional_frame_bytes*2); // Save upper half of ZMM registes } // Restore upper half of YMM registes. - assert(additional_frame_bytes == 128, ""); - off = 0; for (int n = 0; n < num_xmm_regs; n++) { - __ vinsertf128h(as_XMMRegister(n), Address(rsp, off++*16)); + __ vinsertf128h(as_XMMRegister(n), Address(rsp, n*16)); } __ addptr(rsp, additional_frame_bytes); // Save upper half of YMM registes } diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index 0b17c56095c..68094878b09 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -72,45 +72,28 @@ class SimpleRuntimeFrame { class RegisterSaver { // Capture info about frame layout. Layout offsets are in jint // units because compiler frame slots are jints. -#define HALF_ZMM_BANK_WORDS 128 +#define XSAVE_AREA_BEGIN 160 +#define XSAVE_AREA_YMM_BEGIN 576 +#define XSAVE_AREA_ZMM_BEGIN 1152 +#define XSAVE_AREA_UPPERBANK 1664 #define DEF_XMM_OFFS(regnum) xmm ## regnum ## _off = xmm_off + (regnum)*16/BytesPerInt, xmm ## regnum ## H_off +#define DEF_YMM_OFFS(regnum) ymm ## regnum ## _off = ymm_off + (regnum)*16/BytesPerInt, ymm ## regnum ## H_off #define DEF_ZMM_OFFS(regnum) zmm ## regnum ## _off = zmm_off + (regnum-16)*64/BytesPerInt, zmm ## regnum ## H_off enum layout { fpu_state_off = frame::arg_reg_save_area_bytes/BytesPerInt, // fxsave save area - xmm_off = fpu_state_off + 160/BytesPerInt, // offset in fxsave save area + xmm_off = fpu_state_off + XSAVE_AREA_BEGIN/BytesPerInt, // offset in fxsave save area DEF_XMM_OFFS(0), DEF_XMM_OFFS(1), - DEF_XMM_OFFS(2), - DEF_XMM_OFFS(3), - DEF_XMM_OFFS(4), - DEF_XMM_OFFS(5), - DEF_XMM_OFFS(6), - DEF_XMM_OFFS(7), - DEF_XMM_OFFS(8), - DEF_XMM_OFFS(9), - DEF_XMM_OFFS(10), - DEF_XMM_OFFS(11), - DEF_XMM_OFFS(12), - DEF_XMM_OFFS(13), - DEF_XMM_OFFS(14), - DEF_XMM_OFFS(15), - zmm_off = fpu_state_off + ((FPUStateSizeInWords - (HALF_ZMM_BANK_WORDS + 1))*wordSize / BytesPerInt), + // 2..15 are implied in range usage + ymm_off = xmm_off + (XSAVE_AREA_YMM_BEGIN - XSAVE_AREA_BEGIN)/BytesPerInt, + DEF_YMM_OFFS(0), + DEF_YMM_OFFS(1), + // 2..15 are implied in range usage + zmm_high = xmm_off + (XSAVE_AREA_ZMM_BEGIN - XSAVE_AREA_BEGIN)/BytesPerInt, + zmm_off = xmm_off + (XSAVE_AREA_UPPERBANK - XSAVE_AREA_BEGIN)/BytesPerInt, DEF_ZMM_OFFS(16), DEF_ZMM_OFFS(17), - DEF_ZMM_OFFS(18), - DEF_ZMM_OFFS(19), - DEF_ZMM_OFFS(20), - DEF_ZMM_OFFS(21), - DEF_ZMM_OFFS(22), - DEF_ZMM_OFFS(23), - DEF_ZMM_OFFS(24), - DEF_ZMM_OFFS(25), - DEF_ZMM_OFFS(26), - DEF_ZMM_OFFS(27), - DEF_ZMM_OFFS(28), - DEF_ZMM_OFFS(29), - DEF_ZMM_OFFS(30), - DEF_ZMM_OFFS(31), + // 18..31 are implied in range usage fpu_state_end = fpu_state_off + ((FPUStateSizeInWords-1)*wordSize / BytesPerInt), fpu_stateH_end, r15_off, r15H_off, @@ -160,8 +143,6 @@ class RegisterSaver { }; OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors) { - int vect_words = 0; - int ymmhi_offset = -1; int off = 0; int num_xmm_regs = XMMRegisterImpl::number_of_registers; if (UseAVX < 3) { @@ -171,24 +152,15 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ if (save_vectors) { assert(UseAVX > 0, "512bit vectors are supported only with EVEX"); assert(MaxVectorSize == 64, "only 512bit vectors are supported now"); - // Save upper half of YMM registers - vect_words = 16 * num_xmm_regs / wordSize; - if (UseAVX < 3) { - ymmhi_offset = additional_frame_words; - additional_frame_words += vect_words; - } } #else assert(!save_vectors, "vectors are generated only by C2 and JVMCI"); #endif - // Always make the frame size 16-byte aligned - int frame_size_in_bytes = round_to(additional_frame_words*wordSize + - reg_save_size*BytesPerInt, num_xmm_regs); + // Always make the frame size 16-byte aligned, both vector and non vector stacks are always allocated + int frame_size_in_bytes = round_to(reg_save_size*BytesPerInt, num_xmm_regs); // OopMap frame size is in compiler stack slots (jint's) not bytes or words int frame_size_in_slots = frame_size_in_bytes / BytesPerInt; - // The caller will allocate additional_frame_words - int additional_frame_slots = additional_frame_words*wordSize / BytesPerInt; // CodeBlob frame size is in words. int frame_size_in_words = frame_size_in_bytes / wordSize; *total_frame_words = frame_size_in_words; @@ -203,12 +175,34 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ __ push_CPU_state(); // Push a multiple of 16 bytes // push cpu state handles this on EVEX enabled targets - if ((vect_words > 0) && (UseAVX < 3)) { - assert(vect_words*wordSize >= 256, ""); - // Save upper half of YMM registes(0..num_xmm_regs) - __ subptr(rsp, num_xmm_regs*16); - for (int n = 0; n < num_xmm_regs; n++) { - __ vextractf128h(Address(rsp, off++*16), as_XMMRegister(n)); + if (save_vectors) { + // Save upper half of YMM registes(0..15) + int base_addr = XSAVE_AREA_YMM_BEGIN; + for (int n = 0; n < 16; n++) { + __ vextractf128h(Address(rsp, base_addr+n*16), as_XMMRegister(n)); + } + if (VM_Version::supports_evex()) { + // Save upper half of ZMM registes(0..15) + base_addr = XSAVE_AREA_ZMM_BEGIN; + for (int n = 0; n < 16; n++) { + __ vextractf64x4h(Address(rsp, base_addr+n*32), as_XMMRegister(n), 1); + } + // Save full ZMM registes(16..num_xmm_regs) + base_addr = XSAVE_AREA_UPPERBANK; + int off = 0; + int vector_len = Assembler::AVX_512bit; + for (int n = 16; n < num_xmm_regs; n++) { + __ evmovdqul(Address(rsp, base_addr+(off++*64)), as_XMMRegister(n), vector_len); + } + } + } else { + if (VM_Version::supports_evex()) { + // Save upper bank of ZMM registers(16..31) for double/float usage + int base_addr = XSAVE_AREA_UPPERBANK; + int off = 0; + for (int n = 16; n < num_xmm_regs; n++) { + __ movsd(Address(rsp, base_addr+(off++*64)), as_XMMRegister(n)); + } } } if (frame::arg_reg_save_area_bytes != 0) { @@ -224,8 +218,7 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ OopMapSet *oop_maps = new OopMapSet(); OopMap* map = new OopMap(frame_size_in_slots, 0); -#define STACK_OFFSET(x) VMRegImpl::stack2reg((x) + additional_frame_slots) -#define YMMHI_STACK_OFFSET(x) VMRegImpl::stack2reg((x / VMRegImpl::stack_slot_size) + ymmhi_offset) +#define STACK_OFFSET(x) VMRegImpl::stack2reg((x)) map->set_callee_saved(STACK_OFFSET( rax_off ), rax->as_VMReg()); map->set_callee_saved(STACK_OFFSET( rcx_off ), rcx->as_VMReg()); @@ -257,31 +250,21 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ off = zmm16_off; delta = zmm17_off - off; for (int n = 16; n < num_xmm_regs; n++) { - XMMRegister xmm_name = as_XMMRegister(n); - map->set_callee_saved(STACK_OFFSET(off), xmm_name->as_VMReg()); + XMMRegister zmm_name = as_XMMRegister(n); + map->set_callee_saved(STACK_OFFSET(off), zmm_name->as_VMReg()); off += delta; } } #if defined(COMPILER2) || INCLUDE_JVMCI if (save_vectors) { - assert(ymmhi_offset != -1, "save area must exist"); - map->set_callee_saved(YMMHI_STACK_OFFSET( 0), xmm0->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET( 16), xmm1->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET( 32), xmm2->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET( 48), xmm3->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET( 64), xmm4->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET( 80), xmm5->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET( 96), xmm6->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET(112), xmm7->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET(128), xmm8->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET(144), xmm9->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET(160), xmm10->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET(176), xmm11->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET(192), xmm12->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET(208), xmm13->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET(224), xmm14->as_VMReg()->next(4)); - map->set_callee_saved(YMMHI_STACK_OFFSET(240), xmm15->as_VMReg()->next(4)); + off = ymm0_off; + int delta = ymm1_off - off; + for (int n = 0; n < 16; n++) { + XMMRegister ymm_name = as_XMMRegister(n); + map->set_callee_saved(STACK_OFFSET(off), ymm_name->as_VMReg()->next(4)); + off += delta; + } } #endif // COMPILER2 || INCLUDE_JVMCI @@ -316,8 +299,8 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ off = zmm16H_off; delta = zmm17H_off - off; for (int n = 16; n < num_xmm_regs; n++) { - XMMRegister xmm_name = as_XMMRegister(n); - map->set_callee_saved(STACK_OFFSET(off), xmm_name->as_VMReg()->next()); + XMMRegister zmm_name = as_XMMRegister(n); + map->set_callee_saved(STACK_OFFSET(off), zmm_name->as_VMReg()->next()); off += delta; } } @@ -335,21 +318,48 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_ve // Pop arg register save area __ addptr(rsp, frame::arg_reg_save_area_bytes); } + #if defined(COMPILER2) || INCLUDE_JVMCI - // On EVEX enabled targets everything is handled in pop fpu state - if ((restore_vectors) && (UseAVX < 3)) { - assert(UseAVX > 0, "256/512-bit vectors are supported only with AVX"); - assert(MaxVectorSize == 64, "up to 512bit vectors are supported now"); - int off = 0; - // Restore upper half of YMM registes (0..num_xmm_regs) - for (int n = 0; n < num_xmm_regs; n++) { - __ vinsertf128h(as_XMMRegister(n), Address(rsp, off++*16)); - } - __ addptr(rsp, num_xmm_regs*16); + if (restore_vectors) { + assert(UseAVX > 0, "512bit vectors are supported only with EVEX"); + assert(MaxVectorSize == 64, "only 512bit vectors are supported now"); } #else - assert(!restore_vectors, "vectors are generated only by C2 and JVMCI"); + assert(!save_vectors, "vectors are generated only by C2"); #endif + + // On EVEX enabled targets everything is handled in pop fpu state + if (restore_vectors) { + // Restore upper half of YMM registes (0..15) + int base_addr = XSAVE_AREA_YMM_BEGIN; + for (int n = 0; n < 16; n++) { + __ vinsertf128h(as_XMMRegister(n), Address(rsp, base_addr+n*16)); + } + if (VM_Version::supports_evex()) { + // Restore upper half of ZMM registes (0..15) + base_addr = XSAVE_AREA_ZMM_BEGIN; + for (int n = 0; n < 16; n++) { + __ vinsertf64x4h(as_XMMRegister(n), Address(rsp, base_addr+n*32), 1); + } + // Restore full ZMM registes(16..num_xmm_regs) + base_addr = XSAVE_AREA_UPPERBANK; + int vector_len = Assembler::AVX_512bit; + int off = 0; + for (int n = 16; n < num_xmm_regs; n++) { + __ evmovdqul(as_XMMRegister(n), Address(rsp, base_addr+(off++*64)), vector_len); + } + } + } else { + if (VM_Version::supports_evex()) { + // Restore upper bank of ZMM registes(16..31) for double/float usage + int base_addr = XSAVE_AREA_UPPERBANK; + int off = 0; + for (int n = 16; n < num_xmm_regs; n++) { + __ movsd(as_XMMRegister(n), Address(rsp, base_addr+(off++*64))); + } + } + } + // Recover CPU state __ pop_CPU_state(); // Get the rbp described implicitly by the calling convention (no oopMap) diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index 49b78565677..8ebcd28044a 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -273,7 +273,7 @@ class StubGenerator: public StubCodeGenerator { if (UseAVX > 2) { last_reg = 31; } - if (VM_Version::supports_avx512novl()) { + if (VM_Version::supports_evex()) { for (int i = xmm_save_first; i <= last_reg; i++) { __ vextractf32x4h(xmm_save(i), as_XMMRegister(i), 0); } @@ -391,7 +391,7 @@ class StubGenerator: public StubCodeGenerator { // restore regs belonging to calling function #ifdef _WIN64 // emit the restores for xmm regs - if (VM_Version::supports_avx512novl()) { + if (VM_Version::supports_evex()) { for (int i = xmm_save_first; i <= last_reg; i++) { __ vinsertf32x4h(as_XMMRegister(i), xmm_save(i), 0); } diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index 4e2e1942cef..e66fcc51153 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -891,7 +891,7 @@ void VM_Version::get_processor_features() { UseNewLongLShift = true; } if( FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper) ) { - if( supports_sse4a() ) { + if (supports_sse4a()) { UseXmmLoadAndClearUpper = true; // use movsd only on '10h' Opteron } else { UseXmmLoadAndClearUpper = false; diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp index d97c681cfc0..29b4a80b1dd 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp @@ -552,6 +552,19 @@ protected: break; } } + // zmm_save will be set on a EVEX enabled machine even if we choose AVX code gen + if (retVal == false) { + // Verify that OS save/restore all bits of EVEX registers + // during signal processing. + int nreg = 2 LP64_ONLY(+2); + retVal = true; + for (int i = 0; i < 16 * nreg; i++) { // 64 bytes per zmm register + if (_cpuid_info.zmm_save[i] != ymm_test_value()) { + retVal = false; + break; + } + } + } } return retVal; } @@ -706,6 +719,9 @@ public: static bool supports_avx512vl() { return (_cpuFeatures & CPU_AVX512VL) != 0; } static bool supports_avx512vlbw() { return (supports_avx512bw() && supports_avx512vl()); } static bool supports_avx512novl() { return (supports_evex() && !supports_avx512vl()); } + static bool supports_avx512nobw() { return (supports_evex() && !supports_avx512bw()); } + static bool supports_avx256only() { return (supports_avx2() && !supports_evex()); } + static bool supports_avxonly() { return ((supports_avx2() || supports_avx()) && !supports_evex()); } // Intel features static bool is_intel_family_core() { return is_intel() && extended_cpu_family() == CPU_FAMILY_INTEL_CORE; } diff --git a/hotspot/src/cpu/x86/vm/x86.ad b/hotspot/src/cpu/x86/vm/x86.ad index b637b9bddac..28d25cca76b 100644 --- a/hotspot/src/cpu/x86/vm/x86.ad +++ b/hotspot/src/cpu/x86/vm/x86.ad @@ -1716,6 +1716,36 @@ const bool Matcher::match_rule_supported(int opcode) { return ret_value; // Per default match rules are supported. } +const bool Matcher::match_rule_supported_vector(int opcode, int vlen) { + // identify extra cases that we might want to provide match rules for + // e.g. Op_ vector nodes and other intrinsics while guarding with vlen + bool ret_value = match_rule_supported(opcode); + if (ret_value) { + switch (opcode) { + case Op_AddVB: + case Op_SubVB: + if ((vlen == 64) && (VM_Version::supports_avx512bw() == false)) + ret_value = false; + break; + case Op_URShiftVS: + case Op_RShiftVS: + case Op_LShiftVS: + case Op_MulVS: + case Op_AddVS: + case Op_SubVS: + if ((vlen == 32) && (VM_Version::supports_avx512bw() == false)) + ret_value = false; + break; + case Op_CMoveVD: + if (vlen != 4) + ret_value = false; + break; + } + } + + return ret_value; // Per default match rules are supported. +} + const int Matcher::float_pressure(int default_pressure_threshold) { int float_pressure_threshold = default_pressure_threshold; #ifdef _LP64 @@ -1759,11 +1789,9 @@ const int Matcher::vector_width_in_bytes(BasicType bt) { break; case T_BYTE: if (size < 4) return 0; - if ((size > 32) && !VM_Version::supports_avx512bw()) return 0; break; case T_SHORT: if (size < 4) return 0; - if ((size > 16) && !VM_Version::supports_avx512bw()) return 0; break; default: ShouldNotReachHere(); @@ -1967,27 +1995,34 @@ static int vec_spill_helper(CodeBuffer *cbuf, bool do_size, bool is_load, bool is_single_byte = false; int vec_len = 0; if ((UseAVX > 2) && (stack_offset != 0)) { + int tuple_type = Assembler::EVEX_FVM; + int input_size = Assembler::EVEX_32bit; switch (ireg) { - case Op_VecS: + case Op_VecS: + tuple_type = Assembler::EVEX_T1S; + break; case Op_VecD: + tuple_type = Assembler::EVEX_T1S; + input_size = Assembler::EVEX_64bit; + break; case Op_VecX: - break; - case Op_VecY: - vec_len = 1; - break; + break; + case Op_VecY: + vec_len = 1; + break; case Op_VecZ: - vec_len = 2; - break; + vec_len = 2; + break; } - is_single_byte = Assembler::query_compressed_disp_byte(stack_offset, true, vec_len, Assembler::EVEX_FVM, Assembler::EVEX_32bit, 0); + is_single_byte = Assembler::query_compressed_disp_byte(stack_offset, true, vec_len, tuple_type, input_size, 0); } int offset_size = 0; int size = 5; if (UseAVX > 2 ) { - if ((VM_Version::supports_avx512vl() == false) && (vec_len == 2)) { + if (VM_Version::supports_avx512novl() && (vec_len == 2)) { offset_size = (stack_offset == 0) ? 0 : ((is_single_byte) ? 1 : 4); size += 2; // Need an additional two bytes for EVEX encoding - } else if ((VM_Version::supports_avx512vl() == false) && (vec_len < 2)) { + } else if (VM_Version::supports_avx512novl() && (vec_len < 2)) { offset_size = (stack_offset == 0) ? 0 : ((stack_offset <= 127) ? 1 : 4); } else { offset_size = (stack_offset == 0) ? 0 : ((is_single_byte) ? 1 : 4); @@ -2711,7 +2746,7 @@ instruct absF_reg(regF dst) %{ %} instruct absF_reg_reg(regF dst, regF src) %{ - predicate(UseAVX > 0); + predicate(VM_Version::supports_avxonly()); match(Set dst (AbsF src)); ins_cost(150); format %{ "vandps $dst, $src, [0x7fffffff]\t# abs float by sign masking" %} @@ -2723,6 +2758,48 @@ instruct absF_reg_reg(regF dst, regF src) %{ ins_pipe(pipe_slow); %} +#ifdef _LP64 +instruct absF_reg_reg_evex(regF dst, regF src) %{ + predicate(UseAVX > 2 && VM_Version::supports_avx512vl()); + match(Set dst (AbsF src)); + ins_cost(150); + format %{ "vandps $dst, $src, [0x7fffffff]\t# abs float by sign masking" %} + ins_encode %{ + int vector_len = 0; + __ vandps($dst$$XMMRegister, $src$$XMMRegister, + ExternalAddress(float_signmask()), vector_len); + %} + ins_pipe(pipe_slow); +%} + +instruct absF_reg_reg_evex_special(regF dst, regF src1, regF src2) %{ + predicate(VM_Version::supports_avx512novl()); + match(Set dst (AbsF src1)); + effect(TEMP src2); + ins_cost(150); + format %{ "vabsss $dst, $src1, $src2, [0x7fffffff]\t# abs float by sign masking" %} + ins_encode %{ + int vector_len = 0; + __ vabsss($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, + ExternalAddress(float_signmask()), vector_len); + %} + ins_pipe(pipe_slow); +%} +#else // _LP64 +instruct absF_reg_reg_evex(regF dst, regF src) %{ + predicate(UseAVX > 2); + match(Set dst (AbsF src)); + ins_cost(150); + format %{ "vandps $dst, $src, [0x7fffffff]\t# abs float by sign masking" %} + ins_encode %{ + int vector_len = 0; + __ vandps($dst$$XMMRegister, $src$$XMMRegister, + ExternalAddress(float_signmask()), vector_len); + %} + ins_pipe(pipe_slow); +%} +#endif + instruct absD_reg(regD dst) %{ predicate((UseSSE>=2) && (UseAVX == 0)); match(Set dst (AbsD dst)); @@ -2736,7 +2813,7 @@ instruct absD_reg(regD dst) %{ %} instruct absD_reg_reg(regD dst, regD src) %{ - predicate(UseAVX > 0); + predicate(VM_Version::supports_avxonly()); match(Set dst (AbsD src)); ins_cost(150); format %{ "vandpd $dst, $src, [0x7fffffffffffffff]\t" @@ -2749,6 +2826,50 @@ instruct absD_reg_reg(regD dst, regD src) %{ ins_pipe(pipe_slow); %} +#ifdef _LP64 +instruct absD_reg_reg_evex(regD dst, regD src) %{ + predicate(UseAVX > 2 && VM_Version::supports_avx512vl()); + match(Set dst (AbsD src)); + ins_cost(150); + format %{ "vandpd $dst, $src, [0x7fffffffffffffff]\t" + "# abs double by sign masking" %} + ins_encode %{ + int vector_len = 0; + __ vandpd($dst$$XMMRegister, $src$$XMMRegister, + ExternalAddress(double_signmask()), vector_len); + %} + ins_pipe(pipe_slow); +%} + +instruct absD_reg_reg_evex_special(regD dst, regD src1, regD src2) %{ + predicate(VM_Version::supports_avx512novl()); + match(Set dst (AbsD src1)); + effect(TEMP src2); + ins_cost(150); + format %{ "vabssd $dst, $src1, $src2, [0x7fffffffffffffff]\t# abs float by sign masking" %} + ins_encode %{ + int vector_len = 0; + __ vabssd($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, + ExternalAddress(double_signmask()), vector_len); + %} + ins_pipe(pipe_slow); +%} +#else // _LP64 +instruct absD_reg_reg_evex(regD dst, regD src) %{ + predicate(UseAVX > 2); + match(Set dst (AbsD src)); + ins_cost(150); + format %{ "vandpd $dst, $src, [0x7fffffffffffffff]\t" + "# abs double by sign masking" %} + ins_encode %{ + int vector_len = 0; + __ vandpd($dst$$XMMRegister, $src$$XMMRegister, + ExternalAddress(double_signmask()), vector_len); + %} + ins_pipe(pipe_slow); +%} +#endif + instruct negF_reg(regF dst) %{ predicate((UseSSE>=1) && (UseAVX == 0)); match(Set dst (NegF dst)); @@ -4554,7 +4675,7 @@ instruct rsadd2I_reduction_reg(rRegI dst, rRegI src1, vecD src2, regF tmp, regF %} instruct rvadd2I_reduction_reg(rRegI dst, rRegI src1, vecD src2, regF tmp, regF tmp2) %{ - predicate(UseAVX > 0 && UseAVX < 3); + predicate(VM_Version::supports_avxonly()); match(Set dst (AddReductionVI src1 src2)); effect(TEMP tmp, TEMP tmp2); format %{ "vphaddd $tmp,$src2,$src2\n\t" @@ -4594,37 +4715,37 @@ instruct rvadd2I_reduction_reg_evex(rRegI dst, rRegI src1, vecD src2, regF tmp, instruct rsadd4I_reduction_reg(rRegI dst, rRegI src1, vecX src2, regF tmp, regF tmp2) %{ predicate(UseSSE > 2 && UseAVX == 0); match(Set dst (AddReductionVI src1 src2)); - effect(TEMP tmp2, TEMP tmp); - format %{ "movdqu $tmp2,$src2\n\t" - "phaddd $tmp2,$tmp2\n\t" - "phaddd $tmp2,$tmp2\n\t" - "movd $tmp,$src1\n\t" - "paddd $tmp,$tmp2\n\t" - "movd $dst,$tmp\t! add reduction4I" %} + effect(TEMP tmp, TEMP tmp2); + format %{ "movdqu $tmp,$src2\n\t" + "phaddd $tmp,$tmp\n\t" + "phaddd $tmp,$tmp\n\t" + "movd $tmp2,$src1\n\t" + "paddd $tmp2,$tmp\n\t" + "movd $dst,$tmp2\t! add reduction4I" %} ins_encode %{ - __ movdqu($tmp2$$XMMRegister, $src2$$XMMRegister); - __ phaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister); - __ phaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister); - __ movdl($tmp$$XMMRegister, $src1$$Register); - __ paddd($tmp$$XMMRegister, $tmp2$$XMMRegister); - __ movdl($dst$$Register, $tmp$$XMMRegister); + __ movdqu($tmp$$XMMRegister, $src2$$XMMRegister); + __ phaddd($tmp$$XMMRegister, $tmp$$XMMRegister); + __ phaddd($tmp$$XMMRegister, $tmp$$XMMRegister); + __ movdl($tmp2$$XMMRegister, $src1$$Register); + __ paddd($tmp2$$XMMRegister, $tmp$$XMMRegister); + __ movdl($dst$$Register, $tmp2$$XMMRegister); %} ins_pipe( pipe_slow ); %} instruct rvadd4I_reduction_reg(rRegI dst, rRegI src1, vecX src2, regF tmp, regF tmp2) %{ - predicate(UseAVX > 0 && UseAVX < 3); + predicate(VM_Version::supports_avxonly()); match(Set dst (AddReductionVI src1 src2)); effect(TEMP tmp, TEMP tmp2); format %{ "vphaddd $tmp,$src2,$src2\n\t" - "vphaddd $tmp,$tmp,$tmp2\n\t" + "vphaddd $tmp,$tmp,$tmp\n\t" "movd $tmp2,$src1\n\t" "vpaddd $tmp2,$tmp2,$tmp\n\t" "movd $dst,$tmp2\t! add reduction4I" %} ins_encode %{ int vector_len = 0; __ vphaddd($tmp$$XMMRegister, $src2$$XMMRegister, $src2$$XMMRegister, vector_len); - __ vphaddd($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp2$$XMMRegister, vector_len); + __ vphaddd($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp$$XMMRegister, vector_len); __ movdl($tmp2$$XMMRegister, $src1$$Register); __ vpaddd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister, vector_len); __ movdl($dst$$Register, $tmp2$$XMMRegister); @@ -4657,7 +4778,7 @@ instruct rvadd4I_reduction_reg_evex(rRegI dst, rRegI src1, vecX src2, regF tmp, %} instruct rvadd8I_reduction_reg(rRegI dst, rRegI src1, vecY src2, regF tmp, regF tmp2) %{ - predicate(UseAVX > 0 && UseAVX < 3); + predicate(VM_Version::supports_avxonly()); match(Set dst (AddReductionVI src1 src2)); effect(TEMP tmp, TEMP tmp2); format %{ "vphaddd $tmp,$src2,$src2\n\t" @@ -4712,7 +4833,7 @@ instruct rvadd16I_reduction_reg_evex(rRegI dst, rRegI src1, vecZ src2, regF tmp, predicate(UseAVX > 2); match(Set dst (AddReductionVI src1 src2)); effect(TEMP tmp, TEMP tmp2, TEMP tmp3); - format %{ "vextracti64x4 $tmp3,$src2\n\t" + format %{ "vextracti64x4 $tmp3,$src2,0x1\n\t" "vpaddd $tmp3,$tmp3,$src2\n\t" "vextracti128 $tmp,$tmp3\n\t" "vpaddd $tmp,$tmp,$tmp3\n\t" @@ -4724,7 +4845,7 @@ instruct rvadd16I_reduction_reg_evex(rRegI dst, rRegI src1, vecZ src2, regF tmp, "vpaddd $tmp2,$tmp,$tmp2\n\t" "movd $dst,$tmp2\t! mul reduction16I" %} ins_encode %{ - __ vextracti64x4h($tmp3$$XMMRegister, $src2$$XMMRegister); + __ vextracti64x4h($tmp3$$XMMRegister, $src2$$XMMRegister, 1); __ vpaddd($tmp3$$XMMRegister, $tmp3$$XMMRegister, $src2$$XMMRegister, 1); __ vextracti128h($tmp$$XMMRegister, $tmp3$$XMMRegister); __ vpaddd($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp3$$XMMRegister, 0); @@ -4763,7 +4884,7 @@ instruct rvadd4L_reduction_reg(rRegL dst, rRegL src1, vecY src2, regF tmp, regF predicate(UseAVX > 2); match(Set dst (AddReductionVL src1 src2)); effect(TEMP tmp, TEMP tmp2); - format %{ "vextracti64x2 $tmp,$src2, 0x1\n\t" + format %{ "vextracti128 $tmp,$src2\n\t" "vpaddq $tmp2,$tmp,$src2\n\t" "pshufd $tmp,$tmp2,0xE\n\t" "vpaddq $tmp2,$tmp2,$tmp\n\t" @@ -4771,7 +4892,7 @@ instruct rvadd4L_reduction_reg(rRegL dst, rRegL src1, vecY src2, regF tmp, regF "vpaddq $tmp2,$tmp2,$tmp\n\t" "movdq $dst,$tmp2\t! add reduction4L" %} ins_encode %{ - __ vextracti64x2h($tmp$$XMMRegister, $src2$$XMMRegister, 0x1); + __ vextracti128h($tmp$$XMMRegister, $src2$$XMMRegister); __ vpaddq($tmp2$$XMMRegister, $tmp$$XMMRegister, $src2$$XMMRegister, 0); __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0xE); __ vpaddq($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister, 0); @@ -4786,7 +4907,7 @@ instruct rvadd8L_reduction_reg(rRegL dst, rRegL src1, vecZ src2, regF tmp, regF predicate(UseAVX > 2); match(Set dst (AddReductionVL src1 src2)); effect(TEMP tmp, TEMP tmp2); - format %{ "vextracti64x4 $tmp2,$src2\n\t" + format %{ "vextracti64x4 $tmp2,$src2,0x1\n\t" "vpaddq $tmp2,$tmp2,$src2\n\t" "vextracti128 $tmp,$tmp2\n\t" "vpaddq $tmp2,$tmp2,$tmp\n\t" @@ -4796,7 +4917,7 @@ instruct rvadd8L_reduction_reg(rRegL dst, rRegL src1, vecZ src2, regF tmp, regF "vpaddq $tmp2,$tmp2,$tmp\n\t" "movdq $dst,$tmp2\t! add reduction8L" %} ins_encode %{ - __ vextracti64x4h($tmp2$$XMMRegister, $src2$$XMMRegister); + __ vextracti64x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 1); __ vpaddq($tmp2$$XMMRegister, $tmp2$$XMMRegister, $src2$$XMMRegister, 1); __ vextracti128h($tmp$$XMMRegister, $tmp2$$XMMRegister); __ vpaddq($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister, 0); @@ -4810,290 +4931,280 @@ instruct rvadd8L_reduction_reg(rRegL dst, rRegL src1, vecZ src2, regF tmp, regF %} #endif -instruct rsadd2F_reduction_reg(regF dst, regF src1, vecD src2, regF tmp, regF tmp2) %{ +instruct rsadd2F_reduction_reg(regF dst, vecD src2, regF tmp) %{ predicate(UseSSE >= 1 && UseAVX == 0); - match(Set dst (AddReductionVF src1 src2)); - effect(TEMP tmp, TEMP tmp2); - format %{ "movdqu $tmp,$src1\n\t" - "addss $tmp,$src2\n\t" - "pshufd $tmp2,$src2,0x01\n\t" - "addss $tmp,$tmp2\n\t" - "movdqu $dst,$tmp\t! add reduction2F" %} - ins_encode %{ - __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); - __ addss($tmp$$XMMRegister, $src2$$XMMRegister); - __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x01); - __ addss($tmp$$XMMRegister, $tmp2$$XMMRegister); - __ movdqu($dst$$XMMRegister, $tmp$$XMMRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct rvadd2F_reduction_reg(regF dst, regF src1, vecD src2, regF tmp, regF tmp2) %{ - predicate(UseAVX > 0); - match(Set dst (AddReductionVF src1 src2)); - effect(TEMP tmp2, TEMP tmp); - format %{ "vaddss $tmp2,$src1,$src2\n\t" + match(Set dst (AddReductionVF dst src2)); + effect(TEMP dst, TEMP tmp); + format %{ "addss $dst,$src2\n\t" "pshufd $tmp,$src2,0x01\n\t" - "vaddss $dst,$tmp2,$tmp\t! add reduction2F" %} + "addss $dst,$tmp\t! add reduction2F" %} ins_encode %{ - __ vaddss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ addss($dst$$XMMRegister, $src2$$XMMRegister); __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); - __ vaddss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ addss($dst$$XMMRegister, $tmp$$XMMRegister); %} ins_pipe( pipe_slow ); %} -instruct rsadd4F_reduction_reg(regF dst, regF src1, vecX src2, regF tmp, regF tmp2) %{ +instruct rvadd2F_reduction_reg(regF dst, vecD src2, regF tmp) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVF dst src2)); + effect(TEMP dst, TEMP tmp); + format %{ "vaddss $dst,$dst,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vaddss $dst,$dst,$tmp\t! add reduction2F" %} + ins_encode %{ + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsadd4F_reduction_reg(regF dst, vecX src2, regF tmp) %{ predicate(UseSSE >= 1 && UseAVX == 0); - match(Set dst (AddReductionVF src1 src2)); - effect(TEMP tmp, TEMP tmp2); - format %{ "movdqu $tmp,$src1\n\t" - "addss $tmp,$src2\n\t" - "pshufd $tmp2,$src2,0x01\n\t" - "addss $tmp,$tmp2\n\t" - "pshufd $tmp2,$src2,0x02\n\t" - "addss $tmp,$tmp2\n\t" - "pshufd $tmp2,$src2,0x03\n\t" - "addss $tmp,$tmp2\n\t" - "movdqu $dst,$tmp\t! add reduction4F" %} + match(Set dst (AddReductionVF dst src2)); + effect(TEMP dst, TEMP tmp); + format %{ "addss $dst,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "addss $dst,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "addss $dst,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "addss $dst,$tmp\t! add reduction4F" %} ins_encode %{ - __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); - __ addss($tmp$$XMMRegister, $src2$$XMMRegister); - __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x01); - __ addss($tmp$$XMMRegister, $tmp2$$XMMRegister); - __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x02); - __ addss($tmp$$XMMRegister, $tmp2$$XMMRegister); - __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x03); - __ addss($tmp$$XMMRegister, $tmp2$$XMMRegister); - __ movdqu($dst$$XMMRegister, $tmp$$XMMRegister); + __ addss($dst$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ addss($dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ addss($dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ addss($dst$$XMMRegister, $tmp$$XMMRegister); %} ins_pipe( pipe_slow ); %} -instruct rvadd4F_reduction_reg(regF dst, regF src1, vecX src2, regF tmp, regF tmp2) %{ +instruct rvadd4F_reduction_reg(regF dst, vecX src2, regF tmp) %{ predicate(UseAVX > 0); - match(Set dst (AddReductionVF src1 src2)); - effect(TEMP tmp, TEMP tmp2); - format %{ "vaddss $tmp2,$src1,$src2\n\t" - "pshufd $tmp,$src2,0x01\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$src2,0x02\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$src2,0x03\n\t" - "vaddss $dst,$tmp2,$tmp\t! add reduction4F" %} - ins_encode %{ - __ vaddss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); - __ vaddss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct radd8F_reduction_reg(regF dst, regF src1, vecY src2, regF tmp, regF tmp2, regF tmp3) %{ - predicate(UseAVX > 0); - match(Set dst (AddReductionVF src1 src2)); - effect(TEMP tmp, TEMP tmp2, TEMP tmp3); - format %{ "vaddss $tmp2,$src1,$src2\n\t" - "pshufd $tmp,$src2,0x01\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$src2,0x02\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$src2,0x03\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "vextractf128 $tmp3,$src2\n\t" - "vaddss $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0x01\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x02\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x03\n\t" - "vaddss $dst,$tmp2,$tmp\t! add reduction8F" %} - ins_encode %{ - __ vaddss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf128h($tmp3$$XMMRegister, $src2$$XMMRegister); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x01); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x02); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x03); - __ vaddss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct radd16F_reduction_reg(regF dst, regF src1, vecZ src2, regF tmp, regF tmp2, regF tmp3) %{ - predicate(UseAVX > 2); - match(Set dst (AddReductionVF src1 src2)); - effect(TEMP tmp, TEMP tmp2, TEMP tmp3); - format %{ "vaddss $tmp2,$src1,$src2\n\t" - "pshufd $tmp,$src2,0x01\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$src2,0x02\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$src2,0x03\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "vextractf64x2 $tmp3,$src2, 0x1\n\t" - "vaddss $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0x01\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x02\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x03\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "vextractf64x2 $tmp3,$src2, 0x2\n\t" - "vaddss $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0x01\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x02\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x03\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "vextractf64x2 $tmp3,$src2, 0x3\n\t" - "vaddss $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0x01\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x02\n\t" - "vaddss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x03\n\t" - "vaddss $dst,$tmp2,$tmp\t! add reduction16F" %} - ins_encode %{ - __ vaddss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf32x4h($tmp3$$XMMRegister, $src2$$XMMRegister, 0x1); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x01); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x02); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x03); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf32x4h($tmp3$$XMMRegister, $src2$$XMMRegister, 0x2); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x01); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x02); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x03); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf32x4h($tmp3$$XMMRegister, $src2$$XMMRegister, 0x3); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x01); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x02); - __ vaddss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x03); - __ vaddss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct rsadd2D_reduction_reg(regD dst, regD src1, vecX src2, regD tmp) %{ - predicate(UseSSE >= 1 && UseAVX == 0); - match(Set dst (AddReductionVD src1 src2)); + match(Set dst (AddReductionVF dst src2)); effect(TEMP tmp, TEMP dst); - format %{ "movdqu $tmp,$src1\n\t" - "addsd $tmp,$src2\n\t" - "pshufd $dst,$src2,0xE\n\t" + format %{ "vaddss $dst,dst,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "vaddss $dst,$dst,$tmp\t! add reduction4F" %} + ins_encode %{ + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct radd8F_reduction_reg(regF dst, vecY src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (AddReductionVF dst src2)); + effect(TEMP tmp, TEMP dst, TEMP tmp2); + format %{ "vaddss $dst,$dst,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "vextractf128 $tmp2,$src2\n\t" + "vaddss $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0x01\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x02\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x03\n\t" + "vaddss $dst,$dst,$tmp\t! add reduction8F" %} + ins_encode %{ + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf128h($tmp2$$XMMRegister, $src2$$XMMRegister); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x01); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x02); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x03); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct radd16F_reduction_reg(regF dst, vecZ src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 2); + match(Set dst (AddReductionVF dst src2)); + effect(TEMP tmp, TEMP dst, TEMP tmp2); + format %{ "vaddss $dst,$dst,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "vextractf32x4 $tmp2,$src2, 0x1\n\t" + "vaddss $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0x01\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x02\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x03\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "vextractf32x4 $tmp2,$src2, 0x2\n\t" + "vaddss $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0x01\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x02\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x03\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "vextractf32x4 $tmp2,$src2, 0x3\n\t" + "vaddss $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0x01\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x02\n\t" + "vaddss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x03\n\t" + "vaddss $dst,$dst,$tmp\t! add reduction16F" %} + ins_encode %{ + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf32x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 0x1); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x01); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x02); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x03); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf32x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 0x2); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x01); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x02); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x03); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf32x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 0x3); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x01); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x02); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x03); + __ vaddss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsadd2D_reduction_reg(regD dst, vecX src2, regD tmp) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (AddReductionVD dst src2)); + effect(TEMP tmp, TEMP dst); + format %{ "addsd $dst,$src2\n\t" + "pshufd $tmp,$src2,0xE\n\t" "addsd $dst,$tmp\t! add reduction2D" %} ins_encode %{ - __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); - __ addsd($tmp$$XMMRegister, $src2$$XMMRegister); - __ pshufd($dst$$XMMRegister, $src2$$XMMRegister, 0xE); + __ addsd($dst$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); __ addsd($dst$$XMMRegister, $tmp$$XMMRegister); %} ins_pipe( pipe_slow ); %} -instruct rvadd2D_reduction_reg(regD dst, regD src1, vecX src2, regD tmp, regD tmp2) %{ +instruct rvadd2D_reduction_reg(regD dst, vecX src2, regD tmp) %{ predicate(UseAVX > 0); - match(Set dst (AddReductionVD src1 src2)); - effect(TEMP tmp, TEMP tmp2); - format %{ "vaddsd $tmp2,$src1,$src2\n\t" + match(Set dst (AddReductionVD dst src2)); + effect(TEMP tmp, TEMP dst); + format %{ "vaddsd $dst,$dst,$src2\n\t" "pshufd $tmp,$src2,0xE\n\t" - "vaddsd $dst,$tmp2,$tmp\t! add reduction2D" %} + "vaddsd $dst,$dst,$tmp\t! add reduction2D" %} ins_encode %{ - __ vaddsd($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ vaddsd($dst$$XMMRegister, $dst$$XMMRegister, $src2$$XMMRegister); __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); - __ vaddsd($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vaddsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); %} ins_pipe( pipe_slow ); %} -instruct rvadd4D_reduction_reg(regD dst, regD src1, vecY src2, regD tmp, regD tmp2, regD tmp3) %{ +instruct rvadd4D_reduction_reg(regD dst, vecY src2, regD tmp, regD tmp2) %{ predicate(UseAVX > 0); - match(Set dst (AddReductionVD src1 src2)); - effect(TEMP tmp, TEMP tmp2, TEMP tmp3); - format %{ "vaddsd $tmp2,$src1,$src2\n\t" + match(Set dst (AddReductionVD dst src2)); + effect(TEMP tmp, TEMP dst, TEMP tmp2); + format %{ "vaddsd $dst,$dst,$src2\n\t" "pshufd $tmp,$src2,0xE\n\t" - "vaddsd $tmp2,$tmp2,$tmp\n\t" - "vextractf128 $tmp3,$src2\n\t" - "vaddsd $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0xE\n\t" - "vaddsd $dst,$tmp2,$tmp\t! add reduction4D" %} + "vaddsd $dst,$dst,$tmp\n\t" + "vextractf32x4h $tmp2,$src2, 0x1\n\t" + "vaddsd $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0xE\n\t" + "vaddsd $dst,$dst,$tmp\t! add reduction4D" %} ins_encode %{ - __ vaddsd($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ vaddsd($dst$$XMMRegister, $dst$$XMMRegister, $src2$$XMMRegister); __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); - __ vaddsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf128h($tmp3$$XMMRegister, $src2$$XMMRegister); - __ vaddsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0xE); - __ vaddsd($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vaddsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf32x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 0x1); + __ vaddsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0xE); + __ vaddsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); %} ins_pipe( pipe_slow ); %} -instruct rvadd8D_reduction_reg(regD dst, regD src1, vecZ src2, regD tmp, regD tmp2, regD tmp3) %{ +instruct rvadd8D_reduction_reg(regD dst, vecZ src2, regD tmp, regD tmp2) %{ predicate(UseAVX > 2); - match(Set dst (AddReductionVD src1 src2)); - effect(TEMP tmp, TEMP tmp2, TEMP tmp3); - format %{ "vaddsd $tmp2,$src1,$src2\n\t" + match(Set dst (AddReductionVD dst src2)); + effect(TEMP tmp, TEMP dst, TEMP tmp2); + format %{ "vaddsd $dst,$dst,$src2\n\t" "pshufd $tmp,$src2,0xE\n\t" - "vaddsd $tmp2,$tmp2,$tmp\n\t" - "vextractf64x2 $tmp3,$src2, 0x1\n\t" - "vaddsd $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0xE\n\t" - "vaddsd $tmp2,$tmp2,$tmp\n\t" - "vextractf64x2 $tmp3,$src2, 0x2\n\t" - "vaddsd $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0xE\n\t" - "vaddsd $tmp2,$tmp2,$tmp\n\t" - "vextractf64x2 $tmp3,$src2, 0x3\n\t" - "vaddsd $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0xE\n\t" - "vaddsd $dst,$tmp2,$tmp\t! add reduction8D" %} + "vaddsd $dst,$dst,$tmp\n\t" + "vextractf32x4 $tmp2,$src2, 0x1\n\t" + "vaddsd $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0xE\n\t" + "vaddsd $dst,$dst,$tmp\n\t" + "vextractf32x4 $tmp2,$src2, 0x2\n\t" + "vaddsd $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0xE\n\t" + "vaddsd $dst,$dst,$tmp\n\t" + "vextractf32x4 $tmp2,$src2, 0x3\n\t" + "vaddsd $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0xE\n\t" + "vaddsd $dst,$dst,$tmp\t! add reduction8D" %} ins_encode %{ - __ vaddsd($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ vaddsd($dst$$XMMRegister, $dst$$XMMRegister, $src2$$XMMRegister); __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); - __ vaddsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf64x2h($tmp3$$XMMRegister, $src2$$XMMRegister, 0x1); - __ vaddsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0xE); - __ vaddsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf64x2h($tmp3$$XMMRegister, $src2$$XMMRegister, 0x2); - __ vaddsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0xE); - __ vaddsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf64x2h($tmp3$$XMMRegister, $src2$$XMMRegister, 0x3); - __ vaddsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0xE); - __ vaddsd($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vaddsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf32x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 0x1); + __ vaddsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0xE); + __ vaddsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf32x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 0x2); + __ vaddsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0xE); + __ vaddsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf32x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 0x3); + __ vaddsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0xE); + __ vaddsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); %} ins_pipe( pipe_slow ); %} @@ -5216,7 +5327,7 @@ instruct rvmul16I_reduction_reg(rRegI dst, rRegI src1, vecZ src2, regF tmp, regF predicate(UseAVX > 2); match(Set dst (MulReductionVI src1 src2)); effect(TEMP tmp, TEMP tmp2, TEMP tmp3); - format %{ "vextracti64x4 $tmp3,$src2\n\t" + format %{ "vextracti64x4 $tmp3,$src2,0x1\n\t" "vpmulld $tmp3,$tmp3,$src2\n\t" "vextracti128 $tmp,$tmp3\n\t" "vpmulld $tmp,$tmp,$src2\n\t" @@ -5228,7 +5339,7 @@ instruct rvmul16I_reduction_reg(rRegI dst, rRegI src1, vecZ src2, regF tmp, regF "vpmulld $tmp2,$tmp,$tmp2\n\t" "movd $dst,$tmp2\t! mul reduction16I" %} ins_encode %{ - __ vextracti64x4h($tmp3$$XMMRegister, $src2$$XMMRegister); + __ vextracti64x4h($tmp3$$XMMRegister, $src2$$XMMRegister, 1); __ vpmulld($tmp3$$XMMRegister, $tmp3$$XMMRegister, $src2$$XMMRegister, 1); __ vextracti128h($tmp$$XMMRegister, $tmp3$$XMMRegister); __ vpmulld($tmp$$XMMRegister, $tmp$$XMMRegister, $tmp3$$XMMRegister, 0); @@ -5267,7 +5378,7 @@ instruct rvmul4L_reduction_reg(rRegL dst, rRegL src1, vecY src2, regF tmp, regF predicate(UseAVX > 2 && VM_Version::supports_avx512dq()); match(Set dst (MulReductionVL src1 src2)); effect(TEMP tmp, TEMP tmp2); - format %{ "vextracti64x2 $tmp,$src2, 0x1\n\t" + format %{ "vextracti128 $tmp,$src2\n\t" "vpmullq $tmp2,$tmp,$src2\n\t" "pshufd $tmp,$tmp2,0xE\n\t" "vpmullq $tmp2,$tmp2,$tmp\n\t" @@ -5275,7 +5386,7 @@ instruct rvmul4L_reduction_reg(rRegL dst, rRegL src1, vecY src2, regF tmp, regF "vpmullq $tmp2,$tmp2,$tmp\n\t" "movdq $dst,$tmp2\t! mul reduction4L" %} ins_encode %{ - __ vextracti64x2h($tmp$$XMMRegister, $src2$$XMMRegister, 0x1); + __ vextracti128h($tmp$$XMMRegister, $src2$$XMMRegister); __ vpmullq($tmp2$$XMMRegister, $tmp$$XMMRegister, $src2$$XMMRegister, 0); __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0xE); __ vpmullq($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister, 0); @@ -5290,7 +5401,7 @@ instruct rvmul8L_reduction_reg(rRegL dst, rRegL src1, vecZ src2, regF tmp, regF predicate(UseAVX > 2 && VM_Version::supports_avx512dq()); match(Set dst (MulReductionVL src1 src2)); effect(TEMP tmp, TEMP tmp2); - format %{ "vextracti64x4 $tmp2,$src2\n\t" + format %{ "vextracti64x4 $tmp2,$src2,0x1\n\t" "vpmullq $tmp2,$tmp2,$src2\n\t" "vextracti128 $tmp,$tmp2\n\t" "vpmullq $tmp2,$tmp2,$tmp\n\t" @@ -5300,7 +5411,7 @@ instruct rvmul8L_reduction_reg(rRegL dst, rRegL src1, vecZ src2, regF tmp, regF "vpmullq $tmp2,$tmp2,$tmp\n\t" "movdq $dst,$tmp2\t! mul reduction8L" %} ins_encode %{ - __ vextracti64x4h($tmp2$$XMMRegister, $src2$$XMMRegister); + __ vextracti64x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 1); __ vpmullq($tmp2$$XMMRegister, $tmp2$$XMMRegister, $src2$$XMMRegister, 1); __ vextracti128h($tmp$$XMMRegister, $tmp2$$XMMRegister); __ vpmullq($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister, 0); @@ -5314,290 +5425,280 @@ instruct rvmul8L_reduction_reg(rRegL dst, rRegL src1, vecZ src2, regF tmp, regF %} #endif -instruct rsmul2F_reduction(regF dst, regF src1, vecD src2, regF tmp, regF tmp2) %{ +instruct rsmul2F_reduction(regF dst, vecD src2, regF tmp) %{ predicate(UseSSE >= 1 && UseAVX == 0); - match(Set dst (MulReductionVF src1 src2)); - effect(TEMP tmp, TEMP tmp2); - format %{ "movdqu $tmp,$src1\n\t" - "mulss $tmp,$src2\n\t" - "pshufd $tmp2,$src2,0x01\n\t" - "mulss $tmp,$tmp2\n\t" - "movdqu $dst,$tmp\t! mul reduction2F" %} + match(Set dst (MulReductionVF dst src2)); + effect(TEMP dst, TEMP tmp); + format %{ "mulss $dst,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "mulss $dst,$tmp\t! mul reduction2F" %} ins_encode %{ - __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); - __ mulss($tmp$$XMMRegister, $src2$$XMMRegister); - __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x01); - __ mulss($tmp$$XMMRegister, $tmp2$$XMMRegister); - __ movdqu($dst$$XMMRegister, $tmp$$XMMRegister); + __ mulss($dst$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ mulss($dst$$XMMRegister, $tmp$$XMMRegister); %} ins_pipe( pipe_slow ); %} -instruct rvmul2F_reduction_reg(regF dst, regF src1, vecD src2, regF tmp, regF tmp2) %{ +instruct rvmul2F_reduction_reg(regF dst, vecD src2, regF tmp) %{ predicate(UseAVX > 0); - match(Set dst (MulReductionVF src1 src2)); - effect(TEMP tmp, TEMP tmp2); - format %{ "vmulss $tmp2,$src1,$src2\n\t" - "pshufd $tmp,$src2,0x01\n\t" - "vmulss $dst,$tmp2,$tmp\t! mul reduction2F" %} - ins_encode %{ - __ vmulss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); - __ vmulss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct rsmul4F_reduction_reg(regF dst, regF src1, vecX src2, regF tmp, regF tmp2) %{ - predicate(UseSSE >= 1 && UseAVX == 0); - match(Set dst (MulReductionVF src1 src2)); - effect(TEMP tmp, TEMP tmp2); - format %{ "movdqu $tmp,$src1\n\t" - "mulss $tmp,$src2\n\t" - "pshufd $tmp2,$src2,0x01\n\t" - "mulss $tmp,$tmp2\n\t" - "pshufd $tmp2,$src2,0x02\n\t" - "mulss $tmp,$tmp2\n\t" - "pshufd $tmp2,$src2,0x03\n\t" - "mulss $tmp,$tmp2\n\t" - "movdqu $dst,$tmp\t! mul reduction4F" %} - ins_encode %{ - __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); - __ mulss($tmp$$XMMRegister, $src2$$XMMRegister); - __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x01); - __ mulss($tmp$$XMMRegister, $tmp2$$XMMRegister); - __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x02); - __ mulss($tmp$$XMMRegister, $tmp2$$XMMRegister); - __ pshufd($tmp2$$XMMRegister, $src2$$XMMRegister, 0x03); - __ mulss($tmp$$XMMRegister, $tmp2$$XMMRegister); - __ movdqu($dst$$XMMRegister, $tmp$$XMMRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct rvmul4F_reduction_reg(regF dst, regF src1, vecX src2, regF tmp, regF tmp2) %{ - predicate(UseAVX > 0); - match(Set dst (MulReductionVF src1 src2)); - effect(TEMP tmp, TEMP tmp2); - format %{ "vmulss $tmp2,$src1,$src2\n\t" - "pshufd $tmp,$src2,0x01\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$src2,0x02\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$src2,0x03\n\t" - "vmulss $dst,$tmp2,$tmp\t! mul reduction4F" %} - ins_encode %{ - __ vmulss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); - __ vmulss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct rvmul8F_reduction_reg(regF dst, regF src1, vecY src2, regF tmp, regF tmp2, regF tmp3) %{ - predicate(UseAVX > 0); - match(Set dst (MulReductionVF src1 src2)); - effect(TEMP tmp, TEMP tmp2, TEMP tmp3); - format %{ "vmulss $tmp2,$src1,$src2\n\t" - "pshufd $tmp,$src2,0x01\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$src2,0x02\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$src2,0x03\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "vextractf128 $tmp3,$src2\n\t" - "vmulss $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0x01\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x02\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x03\n\t" - "vmulss $dst,$tmp2,$tmp\t! mul reduction8F" %} - ins_encode %{ - __ vmulss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf128h($tmp3$$XMMRegister, $src2$$XMMRegister); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x01); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x02); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x03); - __ vmulss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct rvmul16F_reduction_reg(regF dst, regF src1, vecZ src2, regF tmp, regF tmp2, regF tmp3) %{ - predicate(UseAVX > 2); - match(Set dst (MulReductionVF src1 src2)); - effect(TEMP tmp, TEMP tmp2, TEMP tmp3); - format %{ "vmulss $tmp2,$src1,$src2\n\t" - "pshufd $tmp,$src2,0x01\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$src2,0x02\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$src2,0x03\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "vextractf32x4 $tmp3,$src2, 0x1\n\t" - "vmulss $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0x01\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x02\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x03\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "vextractf32x4 $tmp3,$src2, 0x2\n\t" - "vmulss $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0x01\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x02\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x03\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "vextractf32x4 $tmp3,$src2, 0x3\n\t" - "vmulss $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0x01\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x02\n\t" - "vmulss $tmp2,$tmp2,$tmp\n\t" - "pshufd $tmp,$tmp3,0x03\n\t" - "vmulss $dst,$tmp2,$tmp\t! mul reduction16F" %} - ins_encode %{ - __ vmulss($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf32x4h($tmp3$$XMMRegister, $src2$$XMMRegister, 0x1); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x01); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x02); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x03); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf32x4h($tmp3$$XMMRegister, $src2$$XMMRegister, 0x2); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x01); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x02); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x03); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf32x4h($tmp3$$XMMRegister, $src2$$XMMRegister, 0x3); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x01); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x02); - __ vmulss($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0x03); - __ vmulss($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - %} - ins_pipe( pipe_slow ); -%} - -instruct rsmul2D_reduction_reg(regD dst, regD src1, vecX src2, regD tmp) %{ - predicate(UseSSE >= 1 && UseAVX == 0); - match(Set dst (MulReductionVD src1 src2)); + match(Set dst (MulReductionVF dst src2)); effect(TEMP tmp, TEMP dst); - format %{ "movdqu $tmp,$src1\n\t" - "mulsd $tmp,$src2\n\t" - "pshufd $dst,$src2,0xE\n\t" + format %{ "vmulss $dst,$dst,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vmulss $dst,$dst,$tmp\t! mul reduction2F" %} + ins_encode %{ + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsmul4F_reduction_reg(regF dst, vecX src2, regF tmp) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (MulReductionVF dst src2)); + effect(TEMP dst, TEMP tmp); + format %{ "mulss $dst,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "mulss $dst,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "mulss $dst,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "mulss $dst,$tmp\t! mul reduction4F" %} + ins_encode %{ + __ mulss($dst$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ mulss($dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ mulss($dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ mulss($dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul4F_reduction_reg(regF dst, vecX src2, regF tmp) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVF dst src2)); + effect(TEMP tmp, TEMP dst); + format %{ "vmulss $dst,$dst,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "vmulss $dst,$dst,$tmp\t! mul reduction4F" %} + ins_encode %{ + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul8F_reduction_reg(regF dst, vecY src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 0); + match(Set dst (MulReductionVF dst src2)); + effect(TEMP tmp, TEMP dst, TEMP tmp2); + format %{ "vmulss $dst,$dst,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "vextractf128 $tmp2,$src2\n\t" + "vmulss $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0x01\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x02\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x03\n\t" + "vmulss $dst,$dst,$tmp\t! mul reduction8F" %} + ins_encode %{ + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf128h($tmp2$$XMMRegister, $src2$$XMMRegister); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x01); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x02); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x03); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rvmul16F_reduction_reg(regF dst, vecZ src2, regF tmp, regF tmp2) %{ + predicate(UseAVX > 2); + match(Set dst (MulReductionVF dst src2)); + effect(TEMP tmp, TEMP dst, TEMP tmp2); + format %{ "vmulss $dst,$dst,$src2\n\t" + "pshufd $tmp,$src2,0x01\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$src2,0x02\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$src2,0x03\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "vextractf32x4 $tmp2,$src2, 0x1\n\t" + "vmulss $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0x01\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x02\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x03\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "vextractf32x4 $tmp2,$src2, 0x2\n\t" + "vmulss $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0x01\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x02\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x03\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "vextractf32x4 $tmp2,$src2, 0x3\n\t" + "vmulss $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0x01\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x02\n\t" + "vmulss $dst,$dst,$tmp\n\t" + "pshufd $tmp,$tmp2,0x03\n\t" + "vmulss $dst,$dst,$tmp\t! mul reduction16F" %} + ins_encode %{ + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x01); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x02); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0x03); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf32x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 0x1); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x01); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x02); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x03); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf32x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 0x2); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x01); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x02); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x03); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf32x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 0x3); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x01); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x02); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0x03); + __ vmulss($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct rsmul2D_reduction_reg(regD dst, vecX src2, regD tmp) %{ + predicate(UseSSE >= 1 && UseAVX == 0); + match(Set dst (MulReductionVD dst src2)); + effect(TEMP dst, TEMP tmp); + format %{ "mulsd $dst,$src2\n\t" + "pshufd $tmp,$src2,0xE\n\t" "mulsd $dst,$tmp\t! mul reduction2D" %} ins_encode %{ - __ movdqu($tmp$$XMMRegister, $src1$$XMMRegister); - __ mulsd($tmp$$XMMRegister, $src2$$XMMRegister); - __ pshufd($dst$$XMMRegister, $src2$$XMMRegister, 0xE); + __ mulsd($dst$$XMMRegister, $src2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); __ mulsd($dst$$XMMRegister, $tmp$$XMMRegister); %} ins_pipe( pipe_slow ); %} -instruct rvmul2D_reduction_reg(regD dst, regD src1, vecX src2, regD tmp, regD tmp2) %{ +instruct rvmul2D_reduction_reg(regD dst, vecX src2, regD tmp) %{ predicate(UseAVX > 0); - match(Set dst (MulReductionVD src1 src2)); - effect(TEMP tmp, TEMP tmp2); - format %{ "vmulsd $tmp2,$src1,$src2\n\t" + match(Set dst (MulReductionVD dst src2)); + effect(TEMP tmp, TEMP dst); + format %{ "vmulsd $dst,$dst,$src2\n\t" "pshufd $tmp,$src2,0xE\n\t" - "vmulsd $dst,$tmp2,$tmp\t! mul reduction2D" %} + "vmulsd $dst,$dst,$tmp\t! mul reduction2D" %} ins_encode %{ - __ vmulsd($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ vmulsd($dst$$XMMRegister, $dst$$XMMRegister, $src2$$XMMRegister); __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); - __ vmulsd($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vmulsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); %} ins_pipe( pipe_slow ); %} -instruct rvmul4D_reduction_reg(regD dst, regD src1, vecY src2, regD tmp, regD tmp2, regD tmp3) %{ +instruct rvmul4D_reduction_reg(regD dst, vecY src2, regD tmp, regD tmp2) %{ predicate(UseAVX > 0); - match(Set dst (MulReductionVD src1 src2)); - effect(TEMP tmp, TEMP tmp2, TEMP tmp3); - format %{ "vmulsd $tmp2,$src1,$src2\n\t" + match(Set dst (MulReductionVD dst src2)); + effect(TEMP tmp, TEMP dst, TEMP tmp2); + format %{ "vmulsd $dst,$dst,$src2\n\t" "pshufd $tmp,$src2,0xE\n\t" - "vmulsd $tmp2,$tmp2,$tmp\n\t" - "vextractf128 $tmp3,$src2\n\t" - "vmulsd $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0xE\n\t" - "vmulsd $dst,$tmp2,$tmp\t! mul reduction4D" %} + "vmulsd $dst,$dst,$tmp\n\t" + "vextractf128 $tmp2,$src2\n\t" + "vmulsd $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0xE\n\t" + "vmulsd $dst,$dst,$tmp\t! mul reduction4D" %} ins_encode %{ - __ vmulsd($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ vmulsd($dst$$XMMRegister, $dst$$XMMRegister, $src2$$XMMRegister); __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); - __ vmulsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf128h($tmp3$$XMMRegister, $src2$$XMMRegister); - __ vmulsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0xE); - __ vmulsd($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vmulsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf128h($tmp2$$XMMRegister, $src2$$XMMRegister); + __ vmulsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0xE); + __ vmulsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); %} ins_pipe( pipe_slow ); %} -instruct rvmul8D_reduction_reg(regD dst, regD src1, vecZ src2, regD tmp, regD tmp2, regD tmp3) %{ +instruct rvmul8D_reduction_reg(regD dst, vecZ src2, regD tmp, regD tmp2) %{ predicate(UseAVX > 2); - match(Set dst (MulReductionVD src1 src2)); - effect(TEMP tmp, TEMP tmp2, TEMP tmp3); - format %{ "vmulsd $tmp2,$src1,$src2\n\t" + match(Set dst (MulReductionVD dst src2)); + effect(TEMP tmp, TEMP dst, TEMP tmp2); + format %{ "vmulsd $dst,$dst,$src2\n\t" "pshufd $tmp,$src2,0xE\n\t" - "vmulsd $tmp2,$tmp2,$tmp\n\t" - "vextractf64x2 $tmp3,$src2, 0x1\n\t" - "vmulsd $tmp2,$tmp2,$tmp3\n\t" + "vmulsd $dst,$dst,$tmp\n\t" + "vextractf32x4 $tmp2,$src2, 0x1\n\t" + "vmulsd $dst,$dst,$tmp2\n\t" "pshufd $tmp,$src2,0xE\n\t" - "vmulsd $tmp2,$tmp2,$tmp\n\t" - "vextractf64x2 $tmp3,$src2, 0x2\n\t" - "vmulsd $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0xE\n\t" - "vmulsd $tmp2,$tmp2,$tmp\n\t" - "vextractf64x2 $tmp3,$src2, 0x3\n\t" - "vmulsd $tmp2,$tmp2,$tmp3\n\t" - "pshufd $tmp,$tmp3,0xE\n\t" - "vmulsd $dst,$tmp2,$tmp\t! mul reduction8D" %} + "vmulsd $dst,$dst,$tmp\n\t" + "vextractf32x4 $tmp2,$src2, 0x2\n\t" + "vmulsd $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0xE\n\t" + "vmulsd $dst,$dst,$tmp\n\t" + "vextractf32x4 $tmp2,$src2, 0x3\n\t" + "vmulsd $dst,$dst,$tmp2\n\t" + "pshufd $tmp,$tmp2,0xE\n\t" + "vmulsd $dst,$dst,$tmp\t! mul reduction8D" %} ins_encode %{ - __ vmulsd($tmp2$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); + __ vmulsd($dst$$XMMRegister, $dst$$XMMRegister, $src2$$XMMRegister); __ pshufd($tmp$$XMMRegister, $src2$$XMMRegister, 0xE); - __ vmulsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf64x2h($tmp3$$XMMRegister, $src2$$XMMRegister, 0x1); - __ vmulsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0xE); - __ vmulsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf64x2h($tmp3$$XMMRegister, $src2$$XMMRegister, 0x2); - __ vmulsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0xE); - __ vmulsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); - __ vextractf64x2h($tmp3$$XMMRegister, $src2$$XMMRegister, 0x3); - __ vmulsd($tmp2$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister); - __ pshufd($tmp$$XMMRegister, $tmp3$$XMMRegister, 0xE); - __ vmulsd($dst$$XMMRegister, $tmp2$$XMMRegister, $tmp$$XMMRegister); + __ vmulsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf32x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 0x1); + __ vmulsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0xE); + __ vmulsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf32x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 0x2); + __ vmulsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0xE); + __ vmulsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); + __ vextractf32x4h($tmp2$$XMMRegister, $src2$$XMMRegister, 0x3); + __ vmulsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp2$$XMMRegister); + __ pshufd($tmp$$XMMRegister, $tmp2$$XMMRegister, 0xE); + __ vmulsd($dst$$XMMRegister, $dst$$XMMRegister, $tmp$$XMMRegister); %} ins_pipe( pipe_slow ); %} @@ -5608,7 +5709,7 @@ instruct rvmul8D_reduction_reg(regD dst, regD src1, vecZ src2, regD tmp, regD tm // Bytes vector add instruct vadd4B(vecS dst, vecS src) %{ - predicate(n->as_Vector()->length() == 4); + predicate(UseAVX == 0 && n->as_Vector()->length() == 4); match(Set dst (AddVB dst src)); format %{ "paddb $dst,$src\t! add packed4B" %} ins_encode %{ @@ -5617,8 +5718,8 @@ instruct vadd4B(vecS dst, vecS src) %{ ins_pipe( pipe_slow ); %} -instruct vadd4B_reg(vecS dst, vecS src1, vecS src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vadd4B_reg_avx(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); match(Set dst (AddVB src1 src2)); format %{ "vpaddb $dst,$src1,$src2\t! add packed4B" %} ins_encode %{ @@ -5628,8 +5729,31 @@ instruct vadd4B_reg(vecS dst, vecS src1, vecS src2) %{ ins_pipe( pipe_slow ); %} -instruct vadd4B_mem(vecS dst, vecS src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vadd4B_reg_evex(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (AddVB src1 src2)); + format %{ "vpaddb $dst,$src1,$src2\t! add packed4B" %} + ins_encode %{ + int vector_len = 0; + __ vpaddb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd4B_reg_evex_special(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 4); + match(Set dst (AddVB dst src2)); + effect(TEMP src1); + format %{ "vpaddb $dst,$dst,$src2\t! add packed4B" %} + ins_encode %{ + int vector_len = 0; + __ vpaddb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd4B_mem_avx(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); match(Set dst (AddVB src (LoadVector mem))); format %{ "vpaddb $dst,$src,$mem\t! add packed4B" %} ins_encode %{ @@ -5639,8 +5763,31 @@ instruct vadd4B_mem(vecS dst, vecS src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vadd4B_mem_evex(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (AddVB src (LoadVector mem))); + format %{ "vpaddb $dst,$src,$mem\t! add packed4B" %} + ins_encode %{ + int vector_len = 0; + __ vpaddb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd4B_mem_evex_special(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (AddVB dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpaddb $dst,$src,$mem\t! add packed4B" %} + ins_encode %{ + int vector_len = 0; + __ vpaddb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vadd8B(vecD dst, vecD src) %{ - predicate(n->as_Vector()->length() == 8); + predicate(UseAVX == 0 && n->as_Vector()->length() == 8); match(Set dst (AddVB dst src)); format %{ "paddb $dst,$src\t! add packed8B" %} ins_encode %{ @@ -5649,8 +5796,8 @@ instruct vadd8B(vecD dst, vecD src) %{ ins_pipe( pipe_slow ); %} -instruct vadd8B_reg(vecD dst, vecD src1, vecD src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vadd8B_reg_avx(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (AddVB src1 src2)); format %{ "vpaddb $dst,$src1,$src2\t! add packed8B" %} ins_encode %{ @@ -5660,8 +5807,31 @@ instruct vadd8B_reg(vecD dst, vecD src1, vecD src2) %{ ins_pipe( pipe_slow ); %} -instruct vadd8B_mem(vecD dst, vecD src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vadd8B_reg_evex(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (AddVB src1 src2)); + format %{ "vpaddb $dst,$src1,$src2\t! add packed8B" %} + ins_encode %{ + int vector_len = 0; + __ vpaddb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd8B_reg_evex_special(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 8); + match(Set dst (AddVB dst src2)); + effect(TEMP src1); + format %{ "vpaddb $dst,$dst,$src2\t! add packed8B" %} + ins_encode %{ + int vector_len = 0; + __ vpaddb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd8B_mem_avx(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (AddVB src (LoadVector mem))); format %{ "vpaddb $dst,$src,$mem\t! add packed8B" %} ins_encode %{ @@ -5671,8 +5841,31 @@ instruct vadd8B_mem(vecD dst, vecD src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vadd8B_mem_evex(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (AddVB src (LoadVector mem))); + format %{ "vpaddb $dst,$src,$mem\t! add packed8B" %} + ins_encode %{ + int vector_len = 0; + __ vpaddb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd8B_mem_evex_special(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (AddVB dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpaddb $dst,$src,$mem\t! add packed8B" %} + ins_encode %{ + int vector_len = 0; + __ vpaddb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vadd16B(vecX dst, vecX src) %{ - predicate(n->as_Vector()->length() == 16); + predicate(UseAVX == 0 && n->as_Vector()->length() == 16); match(Set dst (AddVB dst src)); format %{ "paddb $dst,$src\t! add packed16B" %} ins_encode %{ @@ -5681,8 +5874,8 @@ instruct vadd16B(vecX dst, vecX src) %{ ins_pipe( pipe_slow ); %} -instruct vadd16B_reg(vecX dst, vecX src1, vecX src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 16); +instruct vadd16B_reg_avx(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 16); match(Set dst (AddVB src1 src2)); format %{ "vpaddb $dst,$src1,$src2\t! add packed16B" %} ins_encode %{ @@ -5692,8 +5885,31 @@ instruct vadd16B_reg(vecX dst, vecX src1, vecX src2) %{ ins_pipe( pipe_slow ); %} -instruct vadd16B_mem(vecX dst, vecX src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 16); +instruct vadd16B_reg_evex(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (AddVB src1 src2)); + format %{ "vpaddb $dst,$src1,$src2\t! add packed16B" %} + ins_encode %{ + int vector_len = 0; + __ vpaddb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd16B_reg_evex_special(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 16); + match(Set dst (AddVB dst src2)); + effect(TEMP src1); + format %{ "vpaddb $dst,$dst,$src2\t! add packed16B" %} + ins_encode %{ + int vector_len = 0; + __ vpaddb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd16B_mem_avx(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 16); match(Set dst (AddVB src (LoadVector mem))); format %{ "vpaddb $dst,$src,$mem\t! add packed16B" %} ins_encode %{ @@ -5703,8 +5919,31 @@ instruct vadd16B_mem(vecX dst, vecX src, memory mem) %{ ins_pipe( pipe_slow ); %} -instruct vadd32B_reg(vecY dst, vecY src1, vecY src2) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 32); +instruct vadd16B_mem_evex(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (AddVB src (LoadVector mem))); + format %{ "vpaddb $dst,$src,$mem\t! add packed16B" %} + ins_encode %{ + int vector_len = 0; + __ vpaddb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd16B_mem_evex_special(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (AddVB dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpaddb $dst,$src,$mem\t! add packed16B" %} + ins_encode %{ + int vector_len = 0; + __ vpaddb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd32B_reg_avx(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 32); match(Set dst (AddVB src1 src2)); format %{ "vpaddb $dst,$src1,$src2\t! add packed32B" %} ins_encode %{ @@ -5714,8 +5953,31 @@ instruct vadd32B_reg(vecY dst, vecY src1, vecY src2) %{ ins_pipe( pipe_slow ); %} -instruct vadd32B_mem(vecY dst, vecY src, memory mem) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 32); +instruct vadd32B_reg_evex(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); + match(Set dst (AddVB src1 src2)); + format %{ "vpaddb $dst,$src1,$src2\t! add packed32B" %} + ins_encode %{ + int vector_len = 1; + __ vpaddb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd32B_reg_evex_special(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 32); + match(Set dst (AddVB dst src2)); + effect(TEMP src1); + format %{ "vpaddb $dst,$dst,$src2\t! add packed32B" %} + ins_encode %{ + int vector_len = 1; + __ vpaddb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd32B_mem_avx(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 32); match(Set dst (AddVB src (LoadVector mem))); format %{ "vpaddb $dst,$src,$mem\t! add packed32B" %} ins_encode %{ @@ -5725,8 +5987,31 @@ instruct vadd32B_mem(vecY dst, vecY src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vadd32B_mem_evex(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); + match(Set dst (AddVB src (LoadVector mem))); + format %{ "vpaddb $dst,$src,$mem\t! add packed32B" %} + ins_encode %{ + int vector_len = 1; + __ vpaddb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd32B_mem_evex_special(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); + match(Set dst (AddVB dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpaddb $dst,$src,$mem\t! add packed32B" %} + ins_encode %{ + int vector_len = 1; + __ vpaddb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vadd64B_reg(vecZ dst, vecZ src1, vecZ src2) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 64); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 64); match(Set dst (AddVB src1 src2)); format %{ "vpaddb $dst,$src1,$src2\t! add packed64B" %} ins_encode %{ @@ -5737,7 +6022,7 @@ instruct vadd64B_reg(vecZ dst, vecZ src1, vecZ src2) %{ %} instruct vadd64B_mem(vecZ dst, vecZ src, memory mem) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 64); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 64); match(Set dst (AddVB src (LoadVector mem))); format %{ "vpaddb $dst,$src,$mem\t! add packed64B" %} ins_encode %{ @@ -5749,7 +6034,7 @@ instruct vadd64B_mem(vecZ dst, vecZ src, memory mem) %{ // Shorts/Chars vector add instruct vadd2S(vecS dst, vecS src) %{ - predicate(n->as_Vector()->length() == 2); + predicate(UseAVX == 0 && n->as_Vector()->length() == 2); match(Set dst (AddVS dst src)); format %{ "paddw $dst,$src\t! add packed2S" %} ins_encode %{ @@ -5758,8 +6043,8 @@ instruct vadd2S(vecS dst, vecS src) %{ ins_pipe( pipe_slow ); %} -instruct vadd2S_reg(vecS dst, vecS src1, vecS src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 2); +instruct vadd2S_reg_avx(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 2); match(Set dst (AddVS src1 src2)); format %{ "vpaddw $dst,$src1,$src2\t! add packed2S" %} ins_encode %{ @@ -5769,8 +6054,31 @@ instruct vadd2S_reg(vecS dst, vecS src1, vecS src2) %{ ins_pipe( pipe_slow ); %} -instruct vadd2S_mem(vecS dst, vecS src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 2); +instruct vadd2S_reg_evex(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 2); + match(Set dst (AddVS src1 src2)); + format %{ "vpaddw $dst,$src1,$src2\t! add packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpaddw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd2S_reg_evex_special(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 2); + match(Set dst (AddVS dst src2)); + effect(TEMP src1); + format %{ "vpaddw $dst,$dst,$src2\t! add packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpaddw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd2S_mem_avx(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 2); match(Set dst (AddVS src (LoadVector mem))); format %{ "vpaddw $dst,$src,$mem\t! add packed2S" %} ins_encode %{ @@ -5780,8 +6088,31 @@ instruct vadd2S_mem(vecS dst, vecS src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vadd2S_mem_evex(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 2); + match(Set dst (AddVS src (LoadVector mem))); + format %{ "vpaddw $dst,$src,$mem\t! add packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpaddw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd2S_mem_evex_special(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 2); + match(Set dst (AddVS dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpaddw $dst,$src,$mem\t! add packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpaddw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vadd4S(vecD dst, vecD src) %{ - predicate(n->as_Vector()->length() == 4); + predicate(UseAVX == 0 && n->as_Vector()->length() == 4); match(Set dst (AddVS dst src)); format %{ "paddw $dst,$src\t! add packed4S" %} ins_encode %{ @@ -5790,8 +6121,8 @@ instruct vadd4S(vecD dst, vecD src) %{ ins_pipe( pipe_slow ); %} -instruct vadd4S_reg(vecD dst, vecD src1, vecD src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vadd4S_reg_avx(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); match(Set dst (AddVS src1 src2)); format %{ "vpaddw $dst,$src1,$src2\t! add packed4S" %} ins_encode %{ @@ -5801,8 +6132,31 @@ instruct vadd4S_reg(vecD dst, vecD src1, vecD src2) %{ ins_pipe( pipe_slow ); %} -instruct vadd4S_mem(vecD dst, vecD src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vadd4S_reg_evex(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (AddVS src1 src2)); + format %{ "vpaddw $dst,$src1,$src2\t! add packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpaddw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd4S_reg_evex_special(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 4); + match(Set dst (AddVS dst src2)); + effect(TEMP src1); + format %{ "vpaddw $dst,$dst,$src2\t! add packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpaddw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd4S_mem_avx(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); match(Set dst (AddVS src (LoadVector mem))); format %{ "vpaddw $dst,$src,$mem\t! add packed4S" %} ins_encode %{ @@ -5812,8 +6166,31 @@ instruct vadd4S_mem(vecD dst, vecD src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vadd4S_mem_evex(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (AddVS src (LoadVector mem))); + format %{ "vpaddw $dst,$src,$mem\t! add packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpaddw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd4S_mem_evex_special(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (AddVS dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpaddw $dst,$src,$mem\t! add packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpaddw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vadd8S(vecX dst, vecX src) %{ - predicate(n->as_Vector()->length() == 8); + predicate(UseAVX == 0 && n->as_Vector()->length() == 8); match(Set dst (AddVS dst src)); format %{ "paddw $dst,$src\t! add packed8S" %} ins_encode %{ @@ -5822,8 +6199,8 @@ instruct vadd8S(vecX dst, vecX src) %{ ins_pipe( pipe_slow ); %} -instruct vadd8S_reg(vecX dst, vecX src1, vecX src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vadd8S_reg_avx(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (AddVS src1 src2)); format %{ "vpaddw $dst,$src1,$src2\t! add packed8S" %} ins_encode %{ @@ -5833,8 +6210,31 @@ instruct vadd8S_reg(vecX dst, vecX src1, vecX src2) %{ ins_pipe( pipe_slow ); %} -instruct vadd8S_mem(vecX dst, vecX src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vadd8S_reg_evex(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (AddVS src1 src2)); + format %{ "vpaddw $dst,$src1,$src2\t! add packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpaddw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd8S_reg_evex_special(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 8); + match(Set dst (AddVS dst src2)); + effect(TEMP src1); + format %{ "vpaddw $dst,$dst,$src2\t! add packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpaddw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd8S_mem_avx(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (AddVS src (LoadVector mem))); format %{ "vpaddw $dst,$src,$mem\t! add packed8S" %} ins_encode %{ @@ -5844,8 +6244,31 @@ instruct vadd8S_mem(vecX dst, vecX src, memory mem) %{ ins_pipe( pipe_slow ); %} -instruct vadd16S_reg(vecY dst, vecY src1, vecY src2) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 16); +instruct vadd8S_mem_evex(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (AddVS src (LoadVector mem))); + format %{ "vpaddw $dst,$src,$mem\t! add packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpaddw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd8S_mem_evex_special(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (AddVS dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpaddw $dst,$src,$mem\t! add packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpaddw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd16S_reg_avx(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 16); match(Set dst (AddVS src1 src2)); format %{ "vpaddw $dst,$src1,$src2\t! add packed16S" %} ins_encode %{ @@ -5855,8 +6278,31 @@ instruct vadd16S_reg(vecY dst, vecY src1, vecY src2) %{ ins_pipe( pipe_slow ); %} -instruct vadd16S_mem(vecY dst, vecY src, memory mem) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 16); +instruct vadd16S_reg_evex(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (AddVS src1 src2)); + format %{ "vpaddw $dst,$src1,$src2\t! add packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpaddw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd16S_reg_evex_special(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 16); + match(Set dst (AddVS dst src2)); + effect(TEMP src1); + format %{ "vpaddw $dst,$dst,$src2\t! add packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpaddw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd16S_mem_avx(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 16); match(Set dst (AddVS src (LoadVector mem))); format %{ "vpaddw $dst,$src,$mem\t! add packed16S" %} ins_encode %{ @@ -5866,8 +6312,31 @@ instruct vadd16S_mem(vecY dst, vecY src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vadd16S_mem_evex(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (AddVS src (LoadVector mem))); + format %{ "vpaddw $dst,$src,$mem\t! add packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpaddw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vadd16S_mem_evex_special(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (AddVS dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpaddw $dst,$src,$mem\t! add packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpaddw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vadd32S_reg(vecZ dst, vecZ src1, vecZ src2) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 32); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); match(Set dst (AddVS src1 src2)); format %{ "vpaddw $dst,$src1,$src2\t! add packed32S" %} ins_encode %{ @@ -5878,7 +6347,7 @@ instruct vadd32S_reg(vecZ dst, vecZ src1, vecZ src2) %{ %} instruct vadd32S_mem(vecZ dst, vecZ src, memory mem) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 32); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); match(Set dst (AddVS src (LoadVector mem))); format %{ "vpaddw $dst,$src,$mem\t! add packed32S" %} ins_encode %{ @@ -6264,7 +6733,7 @@ instruct vadd8D_mem(vecZ dst, vecZ src, memory mem) %{ // Bytes vector sub instruct vsub4B(vecS dst, vecS src) %{ - predicate(n->as_Vector()->length() == 4); + predicate(UseAVX == 0 && n->as_Vector()->length() == 4); match(Set dst (SubVB dst src)); format %{ "psubb $dst,$src\t! sub packed4B" %} ins_encode %{ @@ -6273,8 +6742,8 @@ instruct vsub4B(vecS dst, vecS src) %{ ins_pipe( pipe_slow ); %} -instruct vsub4B_reg(vecS dst, vecS src1, vecS src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vsub4B_reg_avx(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); match(Set dst (SubVB src1 src2)); format %{ "vpsubb $dst,$src1,$src2\t! sub packed4B" %} ins_encode %{ @@ -6284,8 +6753,31 @@ instruct vsub4B_reg(vecS dst, vecS src1, vecS src2) %{ ins_pipe( pipe_slow ); %} -instruct vsub4B_mem(vecS dst, vecS src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vsub4B_reg_evex(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (SubVB src1 src2)); + format %{ "vpsubb $dst,$src1,$src2\t! sub packed4B" %} + ins_encode %{ + int vector_len = 0; + __ vpsubb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub4B_reg_exex_special(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 4); + match(Set dst (SubVB dst src2)); + effect(TEMP src1); + format %{ "vpsubb $dst,$src1,$src2\t! sub packed4B" %} + ins_encode %{ + int vector_len = 0; + __ vpsubb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub4B_mem_avx(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); match(Set dst (SubVB src (LoadVector mem))); format %{ "vpsubb $dst,$src,$mem\t! sub packed4B" %} ins_encode %{ @@ -6295,8 +6787,31 @@ instruct vsub4B_mem(vecS dst, vecS src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vsub4B_mem_evex(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (SubVB src (LoadVector mem))); + format %{ "vpsubb $dst,$src,$mem\t! sub packed4B" %} + ins_encode %{ + int vector_len = 0; + __ vpsubb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub4B_mem_evex_special(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 4); + match(Set dst (SubVB dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpsubb $dst,$src,$mem\t! sub packed4B" %} + ins_encode %{ + int vector_len = 0; + __ vpsubb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vsub8B(vecD dst, vecD src) %{ - predicate(n->as_Vector()->length() == 8); + predicate(UseAVX == 0 && n->as_Vector()->length() == 8); match(Set dst (SubVB dst src)); format %{ "psubb $dst,$src\t! sub packed8B" %} ins_encode %{ @@ -6305,8 +6820,8 @@ instruct vsub8B(vecD dst, vecD src) %{ ins_pipe( pipe_slow ); %} -instruct vsub8B_reg(vecD dst, vecD src1, vecD src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vsub8B_reg_avx(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (SubVB src1 src2)); format %{ "vpsubb $dst,$src1,$src2\t! sub packed8B" %} ins_encode %{ @@ -6316,8 +6831,31 @@ instruct vsub8B_reg(vecD dst, vecD src1, vecD src2) %{ ins_pipe( pipe_slow ); %} -instruct vsub8B_mem(vecD dst, vecD src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vsub8B_reg_evex(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (SubVB src1 src2)); + format %{ "vpsubb $dst,$src1,$src2\t! sub packed8B" %} + ins_encode %{ + int vector_len = 0; + __ vpsubb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub8B_reg_evex_special(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 8); + match(Set dst (SubVB dst src2)); + effect(TEMP src1); + format %{ "vpsubb $dst,$src1,$src2\t! sub packed8B" %} + ins_encode %{ + int vector_len = 0; + __ vpsubb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub8B_mem_avx(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (SubVB src (LoadVector mem))); format %{ "vpsubb $dst,$src,$mem\t! sub packed8B" %} ins_encode %{ @@ -6327,8 +6865,31 @@ instruct vsub8B_mem(vecD dst, vecD src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vsub8B_mem_evex(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (SubVB src (LoadVector mem))); + format %{ "vpsubb $dst,$src,$mem\t! sub packed8B" %} + ins_encode %{ + int vector_len = 0; + __ vpsubb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub8B_mem_evex_special(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 8); + match(Set dst (SubVB dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpsubb $dst,$src,$mem\t! sub packed8B" %} + ins_encode %{ + int vector_len = 0; + __ vpsubb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vsub16B(vecX dst, vecX src) %{ - predicate(n->as_Vector()->length() == 16); + predicate(UseAVX == 0 && n->as_Vector()->length() == 16); match(Set dst (SubVB dst src)); format %{ "psubb $dst,$src\t! sub packed16B" %} ins_encode %{ @@ -6337,8 +6898,8 @@ instruct vsub16B(vecX dst, vecX src) %{ ins_pipe( pipe_slow ); %} -instruct vsub16B_reg(vecX dst, vecX src1, vecX src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 16); +instruct vsub16B_reg_avx(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 16); match(Set dst (SubVB src1 src2)); format %{ "vpsubb $dst,$src1,$src2\t! sub packed16B" %} ins_encode %{ @@ -6348,8 +6909,31 @@ instruct vsub16B_reg(vecX dst, vecX src1, vecX src2) %{ ins_pipe( pipe_slow ); %} -instruct vsub16B_mem(vecX dst, vecX src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 16); +instruct vsub16B_reg_evex(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (SubVB src1 src2)); + format %{ "vpsubb $dst,$src1,$src2\t! sub packed16B" %} + ins_encode %{ + int vector_len = 0; + __ vpsubb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub16B_reg_evex_special(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 16); + match(Set dst (SubVB dst src2)); + effect(TEMP src1); + format %{ "vpsubb $dst,$src1,$src2\t! sub packed16B" %} + ins_encode %{ + int vector_len = 0; + __ vpsubb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub16B_mem_avx(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 16); match(Set dst (SubVB src (LoadVector mem))); format %{ "vpsubb $dst,$src,$mem\t! sub packed16B" %} ins_encode %{ @@ -6359,8 +6943,31 @@ instruct vsub16B_mem(vecX dst, vecX src, memory mem) %{ ins_pipe( pipe_slow ); %} -instruct vsub32B_reg(vecY dst, vecY src1, vecY src2) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 32); +instruct vsub16B_mem_evex(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (SubVB src (LoadVector mem))); + format %{ "vpsubb $dst,$src,$mem\t! sub packed16B" %} + ins_encode %{ + int vector_len = 0; + __ vpsubb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub16B_mem_evex_special(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 16); + match(Set dst (SubVB dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpsubb $dst,$src,$mem\t! sub packed16B" %} + ins_encode %{ + int vector_len = 0; + __ vpsubb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub32B_reg_avx(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 32); match(Set dst (SubVB src1 src2)); format %{ "vpsubb $dst,$src1,$src2\t! sub packed32B" %} ins_encode %{ @@ -6370,8 +6977,31 @@ instruct vsub32B_reg(vecY dst, vecY src1, vecY src2) %{ ins_pipe( pipe_slow ); %} -instruct vsub32B_mem(vecY dst, vecY src, memory mem) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 32); +instruct vsub32B_reg_evex(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); + match(Set dst (SubVB src1 src2)); + format %{ "vpsubb $dst,$src1,$src2\t! sub packed32B" %} + ins_encode %{ + int vector_len = 1; + __ vpsubb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub32B_reg_evex_special(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 32); + match(Set dst (SubVB dst src2)); + effect(TEMP src1); + format %{ "vpsubb $dst,$src1,$src2\t! sub packed32B" %} + ins_encode %{ + int vector_len = 1; + __ vpsubb($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub32B_mem_avx(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 32); match(Set dst (SubVB src (LoadVector mem))); format %{ "vpsubb $dst,$src,$mem\t! sub packed32B" %} ins_encode %{ @@ -6381,8 +7011,31 @@ instruct vsub32B_mem(vecY dst, vecY src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vsub32B_mem_evex(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); + match(Set dst (SubVB src (LoadVector mem))); + format %{ "vpsubb $dst,$src,$mem\t! sub packed32B" %} + ins_encode %{ + int vector_len = 1; + __ vpsubb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub32B_mem_evex_special(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 32); + match(Set dst (SubVB dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpsubb $dst,$src,$mem\t! sub packed32B" %} + ins_encode %{ + int vector_len = 1; + __ vpsubb($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vsub64B_reg(vecZ dst, vecZ src1, vecZ src2) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 64); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 64); match(Set dst (SubVB src1 src2)); format %{ "vpsubb $dst,$src1,$src2\t! sub packed64B" %} ins_encode %{ @@ -6393,7 +7046,7 @@ instruct vsub64B_reg(vecZ dst, vecZ src1, vecZ src2) %{ %} instruct vsub64B_mem(vecZ dst, vecZ src, memory mem) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 64); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 64); match(Set dst (SubVB src (LoadVector mem))); format %{ "vpsubb $dst,$src,$mem\t! sub packed64B" %} ins_encode %{ @@ -6405,7 +7058,7 @@ instruct vsub64B_mem(vecZ dst, vecZ src, memory mem) %{ // Shorts/Chars vector sub instruct vsub2S(vecS dst, vecS src) %{ - predicate(n->as_Vector()->length() == 2); + predicate(UseAVX == 0 && n->as_Vector()->length() == 2); match(Set dst (SubVS dst src)); format %{ "psubw $dst,$src\t! sub packed2S" %} ins_encode %{ @@ -6414,8 +7067,8 @@ instruct vsub2S(vecS dst, vecS src) %{ ins_pipe( pipe_slow ); %} -instruct vsub2S_reg(vecS dst, vecS src1, vecS src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 2); +instruct vsub2S_reg_avx(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 2); match(Set dst (SubVS src1 src2)); format %{ "vpsubw $dst,$src1,$src2\t! sub packed2S" %} ins_encode %{ @@ -6425,8 +7078,31 @@ instruct vsub2S_reg(vecS dst, vecS src1, vecS src2) %{ ins_pipe( pipe_slow ); %} -instruct vsub2S_mem(vecS dst, vecS src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 2); +instruct vsub2S_reg_evex(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 2); + match(Set dst (SubVS src1 src2)); + format %{ "vpsubw $dst,$src1,$src2\t! sub packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsubw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub2S_reg_evex_special(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 2); + match(Set dst (SubVS dst src2)); + effect(TEMP src1); + format %{ "vpsubw $dst,$src1,$src2\t! sub packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsubw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub2S_mem_avx(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 2); match(Set dst (SubVS src (LoadVector mem))); format %{ "vpsubw $dst,$src,$mem\t! sub packed2S" %} ins_encode %{ @@ -6436,8 +7112,31 @@ instruct vsub2S_mem(vecS dst, vecS src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vsub2S_mem_evex(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 2); + match(Set dst (SubVS src (LoadVector mem))); + format %{ "vpsubw $dst,$src,$mem\t! sub packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsubw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub2S_mem_evex_special(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 2); + match(Set dst (SubVS dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpsubw $dst,$src,$mem\t! sub packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsubw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vsub4S(vecD dst, vecD src) %{ - predicate(n->as_Vector()->length() == 4); + predicate(UseAVX == 0 && n->as_Vector()->length() == 4); match(Set dst (SubVS dst src)); format %{ "psubw $dst,$src\t! sub packed4S" %} ins_encode %{ @@ -6446,8 +7145,8 @@ instruct vsub4S(vecD dst, vecD src) %{ ins_pipe( pipe_slow ); %} -instruct vsub4S_reg(vecD dst, vecD src1, vecD src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vsub4S_reg_avx(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); match(Set dst (SubVS src1 src2)); format %{ "vpsubw $dst,$src1,$src2\t! sub packed4S" %} ins_encode %{ @@ -6457,8 +7156,31 @@ instruct vsub4S_reg(vecD dst, vecD src1, vecD src2) %{ ins_pipe( pipe_slow ); %} -instruct vsub4S_mem(vecD dst, vecD src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vsub4S_reg_evex(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (SubVS src1 src2)); + format %{ "vpsubw $dst,$src1,$src2\t! sub packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsubw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub4S_reg_evex_special(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 4); + match(Set dst (SubVS dst src2)); + effect(TEMP src1); + format %{ "vpsubw $dst,$src1,$src2\t! sub packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsubw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub4S_mem_avx(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); match(Set dst (SubVS src (LoadVector mem))); format %{ "vpsubw $dst,$src,$mem\t! sub packed4S" %} ins_encode %{ @@ -6468,8 +7190,31 @@ instruct vsub4S_mem(vecD dst, vecD src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vsub4S_mem_evex(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (SubVS src (LoadVector mem))); + format %{ "vpsubw $dst,$src,$mem\t! sub packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsubw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub4S_mem_evex_special(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 4); + match(Set dst (SubVS dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpsubw $dst,$src,$mem\t! sub packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsubw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vsub8S(vecX dst, vecX src) %{ - predicate(n->as_Vector()->length() == 8); + predicate(UseAVX == 0 && n->as_Vector()->length() == 8); match(Set dst (SubVS dst src)); format %{ "psubw $dst,$src\t! sub packed8S" %} ins_encode %{ @@ -6478,8 +7223,8 @@ instruct vsub8S(vecX dst, vecX src) %{ ins_pipe( pipe_slow ); %} -instruct vsub8S_reg(vecX dst, vecX src1, vecX src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vsub8S_reg_avx(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (SubVS src1 src2)); format %{ "vpsubw $dst,$src1,$src2\t! sub packed8S" %} ins_encode %{ @@ -6489,8 +7234,31 @@ instruct vsub8S_reg(vecX dst, vecX src1, vecX src2) %{ ins_pipe( pipe_slow ); %} -instruct vsub8S_mem(vecX dst, vecX src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vsub8S_reg_evex(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (SubVS src1 src2)); + format %{ "vpsubw $dst,$src1,$src2\t! sub packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsubw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub8S_reg_evex_special(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 8); + match(Set dst (SubVS dst src2)); + effect(TEMP src1); + format %{ "vpsubw $dst,$src1,$src2\t! sub packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsubw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub8S_mem_avx(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (SubVS src (LoadVector mem))); format %{ "vpsubw $dst,$src,$mem\t! sub packed8S" %} ins_encode %{ @@ -6500,8 +7268,31 @@ instruct vsub8S_mem(vecX dst, vecX src, memory mem) %{ ins_pipe( pipe_slow ); %} -instruct vsub16S_reg(vecY dst, vecY src1, vecY src2) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 16); +instruct vsub8S_mem_evex(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (SubVS src (LoadVector mem))); + format %{ "vpsubw $dst,$src,$mem\t! sub packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsubw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub8S_mem_evex_special(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 8); + match(Set dst (SubVS dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpsubw $dst,$src,$mem\t! sub packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsubw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub16S_reg_avx(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 16); match(Set dst (SubVS src1 src2)); format %{ "vpsubw $dst,$src1,$src2\t! sub packed16S" %} ins_encode %{ @@ -6511,8 +7302,31 @@ instruct vsub16S_reg(vecY dst, vecY src1, vecY src2) %{ ins_pipe( pipe_slow ); %} -instruct vsub16S_mem(vecY dst, vecY src, memory mem) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 16); +instruct vsub16S_reg_evex(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (SubVS src1 src2)); + format %{ "vpsubw $dst,$src1,$src2\t! sub packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsubw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub16S_reg_evex_special(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 16); + match(Set dst (SubVS dst src2)); + effect(TEMP src1); + format %{ "vpsubw $dst,$src1,$src2\t! sub packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsubw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub16S_mem_avx(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 16); match(Set dst (SubVS src (LoadVector mem))); format %{ "vpsubw $dst,$src,$mem\t! sub packed16S" %} ins_encode %{ @@ -6522,8 +7336,31 @@ instruct vsub16S_mem(vecY dst, vecY src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vsub16S_mem_evex(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (SubVS src (LoadVector mem))); + format %{ "vpsubw $dst,$src,$mem\t! sub packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsubw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsub16S_mem_evex_special(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 16); + match(Set dst (SubVS dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpsubw $dst,$src,$mem\t! sub packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsubw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vsub32S_reg(vecZ dst, vecZ src1, vecZ src2) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 32); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); match(Set dst (SubVS src1 src2)); format %{ "vpsubw $dst,$src1,$src2\t! sub packed32S" %} ins_encode %{ @@ -6534,7 +7371,7 @@ instruct vsub32S_reg(vecZ dst, vecZ src1, vecZ src2) %{ %} instruct vsub32S_mem(vecZ dst, vecZ src, memory mem) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 32); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); match(Set dst (SubVS src (LoadVector mem))); format %{ "vpsubw $dst,$src,$mem\t! sub packed32S" %} ins_encode %{ @@ -6920,7 +7757,7 @@ instruct vsub8D_mem(vecZ dst, vecZ src, memory mem) %{ // Shorts/Chars vector mul instruct vmul2S(vecS dst, vecS src) %{ - predicate(n->as_Vector()->length() == 2); + predicate(UseAVX == 0 && n->as_Vector()->length() == 2); match(Set dst (MulVS dst src)); format %{ "pmullw $dst,$src\t! mul packed2S" %} ins_encode %{ @@ -6929,8 +7766,8 @@ instruct vmul2S(vecS dst, vecS src) %{ ins_pipe( pipe_slow ); %} -instruct vmul2S_reg(vecS dst, vecS src1, vecS src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 2); +instruct vmul2S_reg_avx(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 2); match(Set dst (MulVS src1 src2)); format %{ "vpmullw $dst,$src1,$src2\t! mul packed2S" %} ins_encode %{ @@ -6940,8 +7777,31 @@ instruct vmul2S_reg(vecS dst, vecS src1, vecS src2) %{ ins_pipe( pipe_slow ); %} -instruct vmul2S_mem(vecS dst, vecS src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 2); +instruct vmul2S_reg_evex(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 2); + match(Set dst (MulVS src1 src2)); + format %{ "vpmullw $dst,$src1,$src2\t! mul packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpmullw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmul2S_evex_special(vecS dst, vecS src1, vecS src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 2); + match(Set dst (MulVS dst src2)); + effect(TEMP src1); + format %{ "vpmullw $dst,$src1,$src2\t! mul packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpmullw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmul2S_mem_avx(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 2); match(Set dst (MulVS src (LoadVector mem))); format %{ "vpmullw $dst,$src,$mem\t! mul packed2S" %} ins_encode %{ @@ -6951,8 +7811,31 @@ instruct vmul2S_mem(vecS dst, vecS src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vmul2S_mem_evex(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 2); + match(Set dst (MulVS src (LoadVector mem))); + format %{ "vpmullw $dst,$src,$mem\t! mul packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpmullw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmul2S_mem_evex_special(vecS dst, vecS src, memory mem) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 2); + match(Set dst (MulVS dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpmullw $dst,$src,$mem\t! mul packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpmullw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vmul4S(vecD dst, vecD src) %{ - predicate(n->as_Vector()->length() == 4); + predicate(UseAVX == 0 && n->as_Vector()->length() == 4); match(Set dst (MulVS dst src)); format %{ "pmullw $dst,$src\t! mul packed4S" %} ins_encode %{ @@ -6961,8 +7844,8 @@ instruct vmul4S(vecD dst, vecD src) %{ ins_pipe( pipe_slow ); %} -instruct vmul4S_reg(vecD dst, vecD src1, vecD src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vmul4S_reg_avx(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); match(Set dst (MulVS src1 src2)); format %{ "vpmullw $dst,$src1,$src2\t! mul packed4S" %} ins_encode %{ @@ -6972,8 +7855,31 @@ instruct vmul4S_reg(vecD dst, vecD src1, vecD src2) %{ ins_pipe( pipe_slow ); %} -instruct vmul4S_mem(vecD dst, vecD src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vmul4S_reg_evex(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (MulVS src1 src2)); + format %{ "vpmullw $dst,$src1,$src2\t! mul packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpmullw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmul4S_reg_evex_special(vecD dst, vecD src1, vecD src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 4); + match(Set dst (MulVS dst src2)); + effect(TEMP src1); + format %{ "vpmullw $dst,$src1,$src2\t! mul packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpmullw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmul4S_mem_avx(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); match(Set dst (MulVS src (LoadVector mem))); format %{ "vpmullw $dst,$src,$mem\t! mul packed4S" %} ins_encode %{ @@ -6983,8 +7889,31 @@ instruct vmul4S_mem(vecD dst, vecD src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vmul4S_mem_evex(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (MulVS src (LoadVector mem))); + format %{ "vpmullw $dst,$src,$mem\t! mul packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpmullw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmul4S_mem_evex_special(vecD dst, vecD src, memory mem) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 4); + match(Set dst (MulVS dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpmullw $dst,$src,$mem\t! mul packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpmullw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vmul8S(vecX dst, vecX src) %{ - predicate(n->as_Vector()->length() == 8); + predicate(UseAVX == 0 && n->as_Vector()->length() == 8); match(Set dst (MulVS dst src)); format %{ "pmullw $dst,$src\t! mul packed8S" %} ins_encode %{ @@ -6993,8 +7922,8 @@ instruct vmul8S(vecX dst, vecX src) %{ ins_pipe( pipe_slow ); %} -instruct vmul8S_reg(vecX dst, vecX src1, vecX src2) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vmul8S_reg_avx(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (MulVS src1 src2)); format %{ "vpmullw $dst,$src1,$src2\t! mul packed8S" %} ins_encode %{ @@ -7004,8 +7933,31 @@ instruct vmul8S_reg(vecX dst, vecX src1, vecX src2) %{ ins_pipe( pipe_slow ); %} -instruct vmul8S_mem(vecX dst, vecX src, memory mem) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vmul8S_reg_evex(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (MulVS src1 src2)); + format %{ "vpmullw $dst,$src1,$src2\t! mul packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpmullw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmul8S_reg_evex_special(vecX dst, vecX src1, vecX src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 8); + match(Set dst (MulVS dst src2)); + effect(TEMP src1); + format %{ "vpmullw $dst,$src1,$src2\t! mul packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpmullw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmul8S_mem_avx(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (MulVS src (LoadVector mem))); format %{ "vpmullw $dst,$src,$mem\t! mul packed8S" %} ins_encode %{ @@ -7015,8 +7967,31 @@ instruct vmul8S_mem(vecX dst, vecX src, memory mem) %{ ins_pipe( pipe_slow ); %} -instruct vmul16S_reg(vecY dst, vecY src1, vecY src2) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 16); +instruct vmul8S_mem_evex(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (MulVS src (LoadVector mem))); + format %{ "vpmullw $dst,$src,$mem\t! mul packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpmullw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmul8S_mem_evex_special(vecX dst, vecX src, memory mem) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 8); + match(Set dst (MulVS dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpmullw $dst,$src,$mem\t! mul packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpmullw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmul16S_reg_avx(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 16); match(Set dst (MulVS src1 src2)); format %{ "vpmullw $dst,$src1,$src2\t! mul packed16S" %} ins_encode %{ @@ -7026,8 +8001,31 @@ instruct vmul16S_reg(vecY dst, vecY src1, vecY src2) %{ ins_pipe( pipe_slow ); %} -instruct vmul16S_mem(vecY dst, vecY src, memory mem) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 16); +instruct vmul16S_reg_evex(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (MulVS src1 src2)); + format %{ "vpmullw $dst,$src1,$src2\t! mul packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpmullw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmul16S_reg_evex_special(vecY dst, vecY src1, vecY src2) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 16); + match(Set dst (MulVS dst src2)); + effect(TEMP src1); + format %{ "vpmullw $dst,$src1,$src2\t! mul packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpmullw($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmul16S_mem_avx(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 16); match(Set dst (MulVS src (LoadVector mem))); format %{ "vpmullw $dst,$src,$mem\t! mul packed16S" %} ins_encode %{ @@ -7037,8 +8035,31 @@ instruct vmul16S_mem(vecY dst, vecY src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vmul16S_mem_evex(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (MulVS src (LoadVector mem))); + format %{ "vpmullw $dst,$src,$mem\t! mul packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpmullw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vmul16S_mem_evex_special(vecY dst, vecY src, memory mem) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 16); + match(Set dst (MulVS dst (LoadVector mem))); + effect(TEMP src); + format %{ "vpmullw $dst,$src,$mem\t! mul packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpmullw($dst$$XMMRegister, $src$$XMMRegister, $mem$$Address, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vmul32S_reg(vecZ dst, vecZ src1, vecZ src2) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 32); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); match(Set dst (MulVS src1 src2)); format %{ "vpmullw $dst,$src1,$src2\t! mul packed32S" %} ins_encode %{ @@ -7049,7 +8070,7 @@ instruct vmul32S_reg(vecZ dst, vecZ src1, vecZ src2) %{ %} instruct vmul32S_mem(vecZ dst, vecZ src, memory mem) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 32); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); match(Set dst (MulVS src (LoadVector mem))); format %{ "vpmullw $dst,$src,$mem\t! mul packed32S" %} ins_encode %{ @@ -7711,7 +8732,7 @@ instruct vsqrt8D_mem(vecZ dst, memory mem) %{ // Shorts/Chars vector left shift instruct vsll2S(vecS dst, vecS shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(UseAVX == 0 && n->as_Vector()->length() == 2); match(Set dst (LShiftVS dst shift)); format %{ "psllw $dst,$shift\t! left shift packed2S" %} ins_encode %{ @@ -7721,7 +8742,7 @@ instruct vsll2S(vecS dst, vecS shift) %{ %} instruct vsll2S_imm(vecS dst, immI8 shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(UseAVX == 0 && n->as_Vector()->length() == 2); match(Set dst (LShiftVS dst shift)); format %{ "psllw $dst,$shift\t! left shift packed2S" %} ins_encode %{ @@ -7730,8 +8751,8 @@ instruct vsll2S_imm(vecS dst, immI8 shift) %{ ins_pipe( pipe_slow ); %} -instruct vsll2S_reg(vecS dst, vecS src, vecS shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 2); +instruct vsll2S_reg_avx(vecS dst, vecS src, vecS shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 2); match(Set dst (LShiftVS src shift)); format %{ "vpsllw $dst,$src,$shift\t! left shift packed2S" %} ins_encode %{ @@ -7741,10 +8762,56 @@ instruct vsll2S_reg(vecS dst, vecS src, vecS shift) %{ ins_pipe( pipe_slow ); %} -instruct vsll2S_reg_imm(vecS dst, vecS src, immI8 shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 2); +instruct vsll2S_reg_evex(vecS dst, vecS src, vecS shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 2); match(Set dst (LShiftVS src shift)); format %{ "vpsllw $dst,$src,$shift\t! left shift packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll2S_reg_evex_special(vecS dst, vecS src, vecS shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 2); + match(Set dst (LShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll2S_reg_imm_avx(vecS dst, vecS src, immI8 shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 2); + match(Set dst (LShiftVS src shift)); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll2S_reg_imm_evex(vecS dst, vecS src, immI8 shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 2); + match(Set dst (LShiftVS src shift)); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll2S_reg_imm_evex_special(vecS dst, vecS src, immI8 shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 2); + match(Set dst (LShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed2S" %} ins_encode %{ int vector_len = 0; __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); @@ -7753,7 +8820,7 @@ instruct vsll2S_reg_imm(vecS dst, vecS src, immI8 shift) %{ %} instruct vsll4S(vecD dst, vecS shift) %{ - predicate(n->as_Vector()->length() == 4); + predicate(UseAVX == 0 && n->as_Vector()->length() == 4); match(Set dst (LShiftVS dst shift)); format %{ "psllw $dst,$shift\t! left shift packed4S" %} ins_encode %{ @@ -7763,7 +8830,7 @@ instruct vsll4S(vecD dst, vecS shift) %{ %} instruct vsll4S_imm(vecD dst, immI8 shift) %{ - predicate(n->as_Vector()->length() == 4); + predicate(UseAVX == 0 && n->as_Vector()->length() == 4); match(Set dst (LShiftVS dst shift)); format %{ "psllw $dst,$shift\t! left shift packed4S" %} ins_encode %{ @@ -7772,8 +8839,8 @@ instruct vsll4S_imm(vecD dst, immI8 shift) %{ ins_pipe( pipe_slow ); %} -instruct vsll4S_reg(vecD dst, vecD src, vecS shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vsll4S_reg_avx(vecD dst, vecD src, vecS shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); match(Set dst (LShiftVS src shift)); format %{ "vpsllw $dst,$src,$shift\t! left shift packed4S" %} ins_encode %{ @@ -7783,10 +8850,56 @@ instruct vsll4S_reg(vecD dst, vecD src, vecS shift) %{ ins_pipe( pipe_slow ); %} -instruct vsll4S_reg_imm(vecD dst, vecD src, immI8 shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vsll4S_reg_evex(vecD dst, vecD src, vecS shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); match(Set dst (LShiftVS src shift)); format %{ "vpsllw $dst,$src,$shift\t! left shift packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll4S_reg_evex_special(vecD dst, vecD src, vecS shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 4); + match(Set dst (LShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll4S_reg_imm_avx(vecD dst, vecD src, immI8 shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); + match(Set dst (LShiftVS src shift)); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll4S_reg_imm_evex(vecD dst, vecD src, immI8 shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (LShiftVS src shift)); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll4S_reg_imm_evex_special(vecD dst, vecD src, immI8 shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 4); + match(Set dst (LShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed4S" %} ins_encode %{ int vector_len = 0; __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); @@ -7795,7 +8908,7 @@ instruct vsll4S_reg_imm(vecD dst, vecD src, immI8 shift) %{ %} instruct vsll8S(vecX dst, vecS shift) %{ - predicate(n->as_Vector()->length() == 8); + predicate(UseAVX == 0 && n->as_Vector()->length() == 8); match(Set dst (LShiftVS dst shift)); format %{ "psllw $dst,$shift\t! left shift packed8S" %} ins_encode %{ @@ -7805,7 +8918,7 @@ instruct vsll8S(vecX dst, vecS shift) %{ %} instruct vsll8S_imm(vecX dst, immI8 shift) %{ - predicate(n->as_Vector()->length() == 8); + predicate(UseAVX == 0 && n->as_Vector()->length() == 8); match(Set dst (LShiftVS dst shift)); format %{ "psllw $dst,$shift\t! left shift packed8S" %} ins_encode %{ @@ -7814,8 +8927,8 @@ instruct vsll8S_imm(vecX dst, immI8 shift) %{ ins_pipe( pipe_slow ); %} -instruct vsll8S_reg(vecX dst, vecX src, vecS shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vsll8S_reg_avx(vecX dst, vecX src, vecS shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (LShiftVS src shift)); format %{ "vpsllw $dst,$src,$shift\t! left shift packed8S" %} ins_encode %{ @@ -7825,8 +8938,31 @@ instruct vsll8S_reg(vecX dst, vecX src, vecS shift) %{ ins_pipe( pipe_slow ); %} -instruct vsll8S_reg_imm(vecX dst, vecX src, immI8 shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vsll8S_reg_evex(vecX dst, vecX src, vecS shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (LShiftVS src shift)); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll8S_reg_evex_special(vecX dst, vecX src, vecS shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 8); + match(Set dst (LShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll8S_reg_imm_avx(vecX dst, vecX src, immI8 shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (LShiftVS src shift)); format %{ "vpsllw $dst,$src,$shift\t! left shift packed8S" %} ins_encode %{ @@ -7836,8 +8972,31 @@ instruct vsll8S_reg_imm(vecX dst, vecX src, immI8 shift) %{ ins_pipe( pipe_slow ); %} -instruct vsll16S_reg(vecY dst, vecY src, vecS shift) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 16); +instruct vsll8S_reg_imm_evex(vecX dst, vecX src, immI8 shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (LShiftVS src shift)); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll8S_reg_imm_evex_special(vecX dst, vecX src, immI8 shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 8); + match(Set dst (LShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll16S_reg_avx(vecY dst, vecY src, vecS shift) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 16); match(Set dst (LShiftVS src shift)); format %{ "vpsllw $dst,$src,$shift\t! left shift packed16S" %} ins_encode %{ @@ -7847,10 +9006,56 @@ instruct vsll16S_reg(vecY dst, vecY src, vecS shift) %{ ins_pipe( pipe_slow ); %} -instruct vsll16S_reg_imm(vecY dst, vecY src, immI8 shift) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 16); +instruct vsll16S_reg_evex(vecY dst, vecY src, vecS shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); match(Set dst (LShiftVS src shift)); format %{ "vpsllw $dst,$src,$shift\t! left shift packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll16S_reg_evex_special(vecY dst, vecY src, vecS shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 16); + match(Set dst (LShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll16S_reg_imm_avx(vecY dst, vecY src, immI8 shift) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 16); + match(Set dst (LShiftVS src shift)); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll16S_reg_imm_evex(vecY dst, vecY src, immI8 shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (LShiftVS src shift)); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsll16S_reg_imm_evex_special(vecY dst, vecY src, immI8 shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 16); + match(Set dst (LShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsllw $dst,$src,$shift\t! left shift packed16S" %} ins_encode %{ int vector_len = 1; __ vpsllw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); @@ -7859,7 +9064,7 @@ instruct vsll16S_reg_imm(vecY dst, vecY src, immI8 shift) %{ %} instruct vsll32S_reg(vecZ dst, vecZ src, vecS shift) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 32); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); match(Set dst (LShiftVS src shift)); format %{ "vpsllw $dst,$src,$shift\t! left shift packed32S" %} ins_encode %{ @@ -7870,7 +9075,7 @@ instruct vsll32S_reg(vecZ dst, vecZ src, vecS shift) %{ %} instruct vsll32S_reg_imm(vecZ dst, vecZ src, immI8 shift) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 32); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); match(Set dst (LShiftVS src shift)); format %{ "vpsllw $dst,$src,$shift\t! left shift packed32S" %} ins_encode %{ @@ -8104,7 +9309,7 @@ instruct vsll8L_reg_imm(vecZ dst, vecZ src, immI8 shift) %{ // unsigned values. instruct vsrl2S(vecS dst, vecS shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(UseAVX == 0 && n->as_Vector()->length() == 2); match(Set dst (URShiftVS dst shift)); format %{ "psrlw $dst,$shift\t! logical right shift packed2S" %} ins_encode %{ @@ -8114,7 +9319,7 @@ instruct vsrl2S(vecS dst, vecS shift) %{ %} instruct vsrl2S_imm(vecS dst, immI8 shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(UseAVX == 0 && n->as_Vector()->length() == 2); match(Set dst (URShiftVS dst shift)); format %{ "psrlw $dst,$shift\t! logical right shift packed2S" %} ins_encode %{ @@ -8123,8 +9328,8 @@ instruct vsrl2S_imm(vecS dst, immI8 shift) %{ ins_pipe( pipe_slow ); %} -instruct vsrl2S_reg(vecS dst, vecS src, vecS shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 2); +instruct vsrl2S_reg_avx(vecS dst, vecS src, vecS shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 2); match(Set dst (URShiftVS src shift)); format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed2S" %} ins_encode %{ @@ -8134,10 +9339,56 @@ instruct vsrl2S_reg(vecS dst, vecS src, vecS shift) %{ ins_pipe( pipe_slow ); %} -instruct vsrl2S_reg_imm(vecS dst, vecS src, immI8 shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 2); +instruct vsrl2S_reg_evex(vecS dst, vecS src, vecS shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 2); match(Set dst (URShiftVS src shift)); format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl2S_reg_evex_special(vecS dst, vecS src, vecS shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 2); + match(Set dst (URShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl2S_reg_imm_avx(vecS dst, vecS src, immI8 shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 2); + match(Set dst (URShiftVS src shift)); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl2S_reg_imm_evex(vecS dst, vecS src, immI8 shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 2); + match(Set dst (URShiftVS src shift)); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl2S_reg_imm_evex_special(vecS dst, vecS src, immI8 shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 2); + match(Set dst (URShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed2S" %} ins_encode %{ int vector_len = 0; __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); @@ -8146,7 +9397,7 @@ instruct vsrl2S_reg_imm(vecS dst, vecS src, immI8 shift) %{ %} instruct vsrl4S(vecD dst, vecS shift) %{ - predicate(n->as_Vector()->length() == 4); + predicate(UseAVX == 0 && n->as_Vector()->length() == 4); match(Set dst (URShiftVS dst shift)); format %{ "psrlw $dst,$shift\t! logical right shift packed4S" %} ins_encode %{ @@ -8156,7 +9407,7 @@ instruct vsrl4S(vecD dst, vecS shift) %{ %} instruct vsrl4S_imm(vecD dst, immI8 shift) %{ - predicate(n->as_Vector()->length() == 4); + predicate(UseAVX == 0 && n->as_Vector()->length() == 4); match(Set dst (URShiftVS dst shift)); format %{ "psrlw $dst,$shift\t! logical right shift packed4S" %} ins_encode %{ @@ -8165,8 +9416,8 @@ instruct vsrl4S_imm(vecD dst, immI8 shift) %{ ins_pipe( pipe_slow ); %} -instruct vsrl4S_reg(vecD dst, vecD src, vecS shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vsrl4S_reg_avx(vecD dst, vecD src, vecS shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); match(Set dst (URShiftVS src shift)); format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed4S" %} ins_encode %{ @@ -8176,10 +9427,56 @@ instruct vsrl4S_reg(vecD dst, vecD src, vecS shift) %{ ins_pipe( pipe_slow ); %} -instruct vsrl4S_reg_imm(vecD dst, vecD src, immI8 shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vsrl4S_reg_evex(vecD dst, vecD src, vecS shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); match(Set dst (URShiftVS src shift)); format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl4S_reg_evex_special(vecD dst, vecD src, vecS shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 4); + match(Set dst (URShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl4S_reg_imm_avx(vecD dst, vecD src, immI8 shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); + match(Set dst (URShiftVS src shift)); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl4S_reg_imm_evex(vecD dst, vecD src, immI8 shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (URShiftVS src shift)); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl4S_reg_imm_evex_special(vecD dst, vecD src, immI8 shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 4); + match(Set dst (URShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed4S" %} ins_encode %{ int vector_len = 0; __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); @@ -8188,7 +9485,7 @@ instruct vsrl4S_reg_imm(vecD dst, vecD src, immI8 shift) %{ %} instruct vsrl8S(vecX dst, vecS shift) %{ - predicate(n->as_Vector()->length() == 8); + predicate(UseAVX == 0 && n->as_Vector()->length() == 8); match(Set dst (URShiftVS dst shift)); format %{ "psrlw $dst,$shift\t! logical right shift packed8S" %} ins_encode %{ @@ -8198,7 +9495,7 @@ instruct vsrl8S(vecX dst, vecS shift) %{ %} instruct vsrl8S_imm(vecX dst, immI8 shift) %{ - predicate(n->as_Vector()->length() == 8); + predicate(UseAVX == 0 && n->as_Vector()->length() == 8); match(Set dst (URShiftVS dst shift)); format %{ "psrlw $dst,$shift\t! logical right shift packed8S" %} ins_encode %{ @@ -8207,8 +9504,8 @@ instruct vsrl8S_imm(vecX dst, immI8 shift) %{ ins_pipe( pipe_slow ); %} -instruct vsrl8S_reg(vecX dst, vecX src, vecS shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vsrl8S_reg_avx(vecX dst, vecX src, vecS shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (URShiftVS src shift)); format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed8S" %} ins_encode %{ @@ -8218,8 +9515,31 @@ instruct vsrl8S_reg(vecX dst, vecX src, vecS shift) %{ ins_pipe( pipe_slow ); %} -instruct vsrl8S_reg_imm(vecX dst, vecX src, immI8 shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vsrl8S_reg_evex(vecX dst, vecX src, vecS shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (URShiftVS src shift)); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl8S_reg_evex_special(vecX dst, vecX src, vecS shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 8); + match(Set dst (URShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl8S_reg_imm_avx(vecX dst, vecX src, immI8 shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (URShiftVS src shift)); format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed8S" %} ins_encode %{ @@ -8229,8 +9549,31 @@ instruct vsrl8S_reg_imm(vecX dst, vecX src, immI8 shift) %{ ins_pipe( pipe_slow ); %} -instruct vsrl16S_reg(vecY dst, vecY src, vecS shift) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 16); +instruct vsrl8S_reg_imm_evex(vecX dst, vecX src, immI8 shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (URShiftVS src shift)); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl8S_reg_imm_evex_special(vecX dst, vecX src, immI8 shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 8); + match(Set dst (URShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl16S_reg_avx(vecY dst, vecY src, vecS shift) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 16); match(Set dst (URShiftVS src shift)); format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed16S" %} ins_encode %{ @@ -8240,10 +9583,56 @@ instruct vsrl16S_reg(vecY dst, vecY src, vecS shift) %{ ins_pipe( pipe_slow ); %} -instruct vsrl16S_reg_imm(vecY dst, vecY src, immI8 shift) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 16); +instruct vsrl16S_reg_evex(vecY dst, vecY src, vecS shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); match(Set dst (URShiftVS src shift)); format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl16S_reg_evex_special(vecY dst, vecY src, vecS shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 16); + match(Set dst (URShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl16S_reg_imm_avx(vecY dst, vecY src, immI8 shift) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 16); + match(Set dst (URShiftVS src shift)); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl16S_reg_imm_evex(vecY dst, vecY src, immI8 shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (URShiftVS src shift)); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsrl16S_reg_imm_evex_special(vecY dst, vecY src, immI8 shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 16); + match(Set dst (URShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed16S" %} ins_encode %{ int vector_len = 1; __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); @@ -8252,7 +9641,7 @@ instruct vsrl16S_reg_imm(vecY dst, vecY src, immI8 shift) %{ %} instruct vsrl32S_reg(vecZ dst, vecZ src, vecS shift) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 32); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); match(Set dst (URShiftVS src shift)); format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed32S" %} ins_encode %{ @@ -8263,7 +9652,7 @@ instruct vsrl32S_reg(vecZ dst, vecZ src, vecS shift) %{ %} instruct vsrl32S_reg_imm(vecZ dst, vecZ src, immI8 shift) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 32); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); match(Set dst (URShiftVS src shift)); format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed32S" %} ins_encode %{ @@ -8493,7 +9882,7 @@ instruct vsrl8L_reg_imm(vecZ dst, vecZ src, immI8 shift) %{ // Shorts/Chars vector arithmetic right shift instruct vsra2S(vecS dst, vecS shift) %{ - predicate(n->as_Vector()->length() == 2); + predicate(UseAVX == 0 && n->as_Vector()->length() == 2); match(Set dst (RShiftVS dst shift)); format %{ "psraw $dst,$shift\t! arithmetic right shift packed2S" %} ins_encode %{ @@ -8512,8 +9901,8 @@ instruct vsra2S_imm(vecS dst, immI8 shift) %{ ins_pipe( pipe_slow ); %} -instruct vsra2S_reg(vecS dst, vecS src, vecS shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 2); +instruct vsra2S_reg_avx(vecS dst, vecS src, vecS shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 2); match(Set dst (RShiftVS src shift)); format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed2S" %} ins_encode %{ @@ -8523,10 +9912,56 @@ instruct vsra2S_reg(vecS dst, vecS src, vecS shift) %{ ins_pipe( pipe_slow ); %} -instruct vsra2S_reg_imm(vecS dst, vecS src, immI8 shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 2); +instruct vsra2S_reg_evex(vecS dst, vecS src, vecS shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 2); match(Set dst (RShiftVS src shift)); format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra2S_reg_evex_special(vecS dst, vecS src, vecS shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 2); + match(Set dst (RShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra2S_reg_imm_avx(vecS dst, vecS src, immI8 shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 2); + match(Set dst (RShiftVS src shift)); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra2S_reg_imm_evex(vecS dst, vecS src, immI8 shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 2); + match(Set dst (RShiftVS src shift)); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed2S" %} + ins_encode %{ + int vector_len = 0; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra2S_reg_imm_evex_special(vecS dst, vecS src, immI8 shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 2); + match(Set dst (RShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed2S" %} ins_encode %{ int vector_len = 0; __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); @@ -8535,7 +9970,7 @@ instruct vsra2S_reg_imm(vecS dst, vecS src, immI8 shift) %{ %} instruct vsra4S(vecD dst, vecS shift) %{ - predicate(n->as_Vector()->length() == 4); + predicate(UseAVX == 0 && n->as_Vector()->length() == 4); match(Set dst (RShiftVS dst shift)); format %{ "psraw $dst,$shift\t! arithmetic right shift packed4S" %} ins_encode %{ @@ -8545,7 +9980,7 @@ instruct vsra4S(vecD dst, vecS shift) %{ %} instruct vsra4S_imm(vecD dst, immI8 shift) %{ - predicate(n->as_Vector()->length() == 4); + predicate(UseAVX == 0 && n->as_Vector()->length() == 4); match(Set dst (RShiftVS dst shift)); format %{ "psraw $dst,$shift\t! arithmetic right shift packed4S" %} ins_encode %{ @@ -8554,8 +9989,8 @@ instruct vsra4S_imm(vecD dst, immI8 shift) %{ ins_pipe( pipe_slow ); %} -instruct vsra4S_reg(vecD dst, vecD src, vecS shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vsra4S_reg_avx(vecD dst, vecD src, vecS shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); match(Set dst (RShiftVS src shift)); format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed4S" %} ins_encode %{ @@ -8565,10 +10000,56 @@ instruct vsra4S_reg(vecD dst, vecD src, vecS shift) %{ ins_pipe( pipe_slow ); %} -instruct vsra4S_reg_imm(vecD dst, vecD src, immI8 shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 4); +instruct vsra4S_reg_evex(vecD dst, vecD src, vecS shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); match(Set dst (RShiftVS src shift)); format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra4S_reg_evex_special(vecD dst, vecD src, vecS shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 4); + match(Set dst (RShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra4S_reg_imm_avx(vecD dst, vecD src, immI8 shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 4); + match(Set dst (RShiftVS src shift)); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra4S_reg_imm_evex(vecD dst, vecD src, immI8 shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 4); + match(Set dst (RShiftVS src shift)); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed4S" %} + ins_encode %{ + int vector_len = 0; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra4S_reg_imm_evex_special(vecD dst, vecD src, immI8 shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 4); + match(Set dst (RShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed4S" %} ins_encode %{ int vector_len = 0; __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); @@ -8577,7 +10058,7 @@ instruct vsra4S_reg_imm(vecD dst, vecD src, immI8 shift) %{ %} instruct vsra8S(vecX dst, vecS shift) %{ - predicate(n->as_Vector()->length() == 8); + predicate(UseAVX == 0 && n->as_Vector()->length() == 8); match(Set dst (RShiftVS dst shift)); format %{ "psraw $dst,$shift\t! arithmetic right shift packed8S" %} ins_encode %{ @@ -8587,7 +10068,7 @@ instruct vsra8S(vecX dst, vecS shift) %{ %} instruct vsra8S_imm(vecX dst, immI8 shift) %{ - predicate(n->as_Vector()->length() == 8); + predicate(UseAVX == 0 && n->as_Vector()->length() == 8); match(Set dst (RShiftVS dst shift)); format %{ "psraw $dst,$shift\t! arithmetic right shift packed8S" %} ins_encode %{ @@ -8596,8 +10077,8 @@ instruct vsra8S_imm(vecX dst, immI8 shift) %{ ins_pipe( pipe_slow ); %} -instruct vsra8S_reg(vecX dst, vecX src, vecS shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vsra8S_reg_avx(vecX dst, vecX src, vecS shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (RShiftVS src shift)); format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed8S" %} ins_encode %{ @@ -8607,8 +10088,31 @@ instruct vsra8S_reg(vecX dst, vecX src, vecS shift) %{ ins_pipe( pipe_slow ); %} -instruct vsra8S_reg_imm(vecX dst, vecX src, immI8 shift) %{ - predicate(UseAVX > 0 && n->as_Vector()->length() == 8); +instruct vsra8S_reg_evex(vecX dst, vecX src, vecS shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (RShiftVS src shift)); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra8S_reg_evex_special(vecX dst, vecX src, vecS shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 8); + match(Set dst (RShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra8S_reg_imm_avx(vecX dst, vecX src, immI8 shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 8); match(Set dst (RShiftVS src shift)); format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed8S" %} ins_encode %{ @@ -8618,8 +10122,31 @@ instruct vsra8S_reg_imm(vecX dst, vecX src, immI8 shift) %{ ins_pipe( pipe_slow ); %} -instruct vsra16S_reg(vecY dst, vecY src, vecS shift) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 16); +instruct vsra8S_reg_imm_evex(vecX dst, vecX src, immI8 shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 8); + match(Set dst (RShiftVS src shift)); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra8S_reg_imm_evex_special(vecX dst, vecX src, immI8 shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 8); + match(Set dst (RShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed8S" %} + ins_encode %{ + int vector_len = 0; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra16S_reg_avx(vecY dst, vecY src, vecS shift) %{ + predicate(VM_Version::supports_avx256only() && n->as_Vector()->length() == 16); match(Set dst (RShiftVS src shift)); format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed16S" %} ins_encode %{ @@ -8629,10 +10156,56 @@ instruct vsra16S_reg(vecY dst, vecY src, vecS shift) %{ ins_pipe( pipe_slow ); %} -instruct vsra16S_reg_imm(vecY dst, vecY src, immI8 shift) %{ - predicate(UseAVX > 1 && n->as_Vector()->length() == 16); +instruct vsra16S_reg_evex(vecY dst, vecY src, vecS shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); match(Set dst (RShiftVS src shift)); format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra16S_reg_evex_special(vecY dst, vecY src, vecS shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 16); + match(Set dst (RShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra16S_reg_imm_avx(vecY dst, vecY src, immI8 shift) %{ + predicate(VM_Version::supports_avxonly() && n->as_Vector()->length() == 16); + match(Set dst (RShiftVS src shift)); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra16S_reg_imm_evex(vecY dst, vecY src, immI8 shift) %{ + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 16); + match(Set dst (RShiftVS src shift)); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed16S" %} + ins_encode %{ + int vector_len = 1; + __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); + %} + ins_pipe( pipe_slow ); +%} + +instruct vsra16S_reg_imm_evex_special(vecY dst, vecY src, immI8 shift) %{ + predicate(VM_Version::supports_avx512nobw() && n->as_Vector()->length() == 16); + match(Set dst (RShiftVS dst shift)); + effect(TEMP src); + format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed16S" %} ins_encode %{ int vector_len = 1; __ vpsraw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector_len); @@ -8641,7 +10214,7 @@ instruct vsra16S_reg_imm(vecY dst, vecY src, immI8 shift) %{ %} instruct vsra32S_reg(vecZ dst, vecZ src, vecS shift) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 32); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); match(Set dst (RShiftVS src shift)); format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed32S" %} ins_encode %{ @@ -8652,7 +10225,7 @@ instruct vsra32S_reg(vecZ dst, vecZ src, vecS shift) %{ %} instruct vsra32S_reg_imm(vecZ dst, vecZ src, immI8 shift) %{ - predicate(UseAVX > 2 && n->as_Vector()->length() == 32); + predicate(VM_Version::supports_avx512bw() && n->as_Vector()->length() == 32); match(Set dst (RShiftVS src shift)); format %{ "vpsraw $dst,$src,$shift\t! arithmetic right shift packed32S" %} ins_encode %{ diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index 36c2b6fba90..1f38927626c 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -291,9 +291,7 @@ static int pre_call_resets_size() { size += 6; // fldcw } if (C->max_vector_size() > 16) { - if(UseAVX <= 2) { - size += 3; // vzeroupper - } + size += 3; // vzeroupper } return size; } @@ -1915,7 +1913,7 @@ encode %{ if (stub == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; - } + } } %} diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index d63e5b68b20..9b4f9f9ebce 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -536,11 +536,7 @@ source %{ #define __ _masm. static int clear_avx_size() { - if(UseAVX > 2) { - return 0; // vzeroupper is ignored - } else { - return (Compile::current()->max_vector_size() > 16) ? 3 : 0; // vzeroupper - } + return (Compile::current()->max_vector_size() > 16) ? 3 : 0; // vzeroupper } // !!!!! Special hack to get all types of calls to specify the byte offset @@ -871,7 +867,7 @@ void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const { if (framesize > 0) { st->print("\n\t"); st->print("addq rbp, #%d", framesize); - } + } } } diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index ccb07bfe09a..ba3a535111d 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -186,9 +186,9 @@ "Maximum number of unrolls for main loop") \ range(0, max_jint) \ \ - product(bool, SuperWordLoopUnrollAnalysis, false, \ - "Map number of unrolls for main loop via " \ - "Superword Level Parallelism analysis") \ + product_pd(bool, SuperWordLoopUnrollAnalysis, \ + "Map number of unrolls for main loop via " \ + "Superword Level Parallelism analysis") \ \ notproduct(bool, TraceSuperWordLoopUnrollAnalysis, false, \ "Trace what Superword Level Parallelism analysis applies") \ diff --git a/hotspot/src/share/vm/opto/matcher.hpp b/hotspot/src/share/vm/opto/matcher.hpp index fc0c66cf345..64cc48c65ec 100644 --- a/hotspot/src/share/vm/opto/matcher.hpp +++ b/hotspot/src/share/vm/opto/matcher.hpp @@ -269,6 +269,10 @@ public: // should generate this one. static const bool match_rule_supported(int opcode); + // identify extra cases that we might want to provide match rules for + // e.g. Op_ vector nodes and other intrinsics while guarding with vlen + static const bool match_rule_supported_vector(int opcode, int vlen); + // Some uarchs have different sized float register resources static const int float_pressure(int default_pressure_threshold); diff --git a/hotspot/src/share/vm/opto/superword.cpp b/hotspot/src/share/vm/opto/superword.cpp index 1b37e0adcee..0d07effbfd3 100644 --- a/hotspot/src/share/vm/opto/superword.cpp +++ b/hotspot/src/share/vm/opto/superword.cpp @@ -2247,7 +2247,10 @@ void SuperWord::output() { NOT_PRODUCT(if (TraceSuperWordLoopUnrollAnalysis) tty->print_cr("vector loop(unroll=%d, len=%d)\n", max_vlen, max_vlen_in_bytes*BitsPerByte)); // For atomic unrolled loops which are vector mapped, instigate more unrolling. cl->set_notpassed_slp(); - C->set_major_progress(); + // if vector resources are limited, do not allow additional unrolling + if (FLOATPRESSURE > 8) { + C->set_major_progress(); + } cl->mark_do_unroll_only(); } } diff --git a/hotspot/src/share/vm/opto/vectornode.cpp b/hotspot/src/share/vm/opto/vectornode.cpp index 9402cb14b90..3ba33385071 100644 --- a/hotspot/src/share/vm/opto/vectornode.cpp +++ b/hotspot/src/share/vm/opto/vectornode.cpp @@ -188,7 +188,7 @@ bool VectorNode::implemented(int opc, uint vlen, BasicType bt) { (vlen > 1) && is_power_of_2(vlen) && Matcher::vector_size_supported(bt, vlen)) { int vopc = VectorNode::opcode(opc, bt); - return vopc > 0 && Matcher::match_rule_supported(vopc) && (vopc != Op_CMoveD || vlen == 4); + return vopc > 0 && Matcher::match_rule_supported_vector(vopc, vlen); } return false; } From fa6545ccc194c4e4944b981b50712182b0cb9dbf Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Mon, 9 Nov 2015 11:28:31 +0100 Subject: [PATCH 017/260] 8137168: Replace IfNode with a new RangeCheckNode for range checks New RangeCheckNode to enable optimization of explicit library level range checks Reviewed-by: kvn, thartmann --- hotspot/src/share/vm/opto/cfgnode.hpp | 25 +- hotspot/src/share/vm/opto/classes.hpp | 1 + hotspot/src/share/vm/opto/compile.cpp | 10 +- hotspot/src/share/vm/opto/ifnode.cpp | 554 +++++++++++--------- hotspot/src/share/vm/opto/loopPredicate.cpp | 38 +- hotspot/src/share/vm/opto/loopTransform.cpp | 9 +- hotspot/src/share/vm/opto/loopUnswitch.cpp | 8 +- hotspot/src/share/vm/opto/loopnode.hpp | 6 +- hotspot/src/share/vm/opto/loopopts.cpp | 10 +- hotspot/src/share/vm/opto/multnode.cpp | 6 +- hotspot/src/share/vm/opto/node.hpp | 3 + hotspot/src/share/vm/opto/parse2.cpp | 10 +- hotspot/src/share/vm/opto/phaseX.hpp | 3 +- 13 files changed, 397 insertions(+), 286 deletions(-) diff --git a/hotspot/src/share/vm/opto/cfgnode.hpp b/hotspot/src/share/vm/opto/cfgnode.hpp index 33a378e5be5..a87a70a41e6 100644 --- a/hotspot/src/share/vm/opto/cfgnode.hpp +++ b/hotspot/src/share/vm/opto/cfgnode.hpp @@ -270,7 +270,6 @@ class IfNode : public MultiBranchNode { virtual uint size_of() const { return sizeof(*this); } private: - ProjNode* range_check_trap_proj(int& flip, Node*& l, Node*& r); ProjNode* range_check_trap_proj() { int flip_test = 0; Node* l = NULL; @@ -283,7 +282,7 @@ private: bool is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn); bool has_shared_region(ProjNode* proj, ProjNode*& success, ProjNode*& fail); bool has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNode*& fail, PhaseIterGVN* igvn); - static void merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn); + Node* merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn); static void improve_address_types(Node* l, Node* r, ProjNode* fail, PhaseIterGVN* igvn); bool is_cmp_with_loadrange(ProjNode* proj); bool is_null_check(ProjNode* proj, PhaseIterGVN* igvn); @@ -292,6 +291,12 @@ private: ProjNode* uncommon_trap_proj(CallStaticJavaNode*& call) const; bool fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn); +protected: + ProjNode* range_check_trap_proj(int& flip, Node*& l, Node*& r); + Node* Ideal_common(PhaseGVN *phase, bool can_reshape); + Node* dominated_by(Node* prev_dom, PhaseIterGVN* igvn); + Node* search_identical(int dist); + public: // Degrees of branch prediction probability by order of magnitude: @@ -375,8 +380,6 @@ public: virtual const Type *Value( PhaseTransform *phase ) const; virtual int required_outcnt() const { return 2; } virtual const RegMask &out_RegMask() const; - void dominated_by(Node* prev_dom, PhaseIterGVN* igvn); - int is_range_check(Node* &range, Node* &index, jint &offset); Node* fold_compares(PhaseIterGVN* phase); static Node* up_one_dom(Node* curr, bool linear_only = false); @@ -391,6 +394,20 @@ public: #endif }; +class RangeCheckNode : public IfNode { +private: + int is_range_check(Node* &range, Node* &index, jint &offset); + +public: + RangeCheckNode(Node* control, Node *b, float p, float fcnt) + : IfNode(control, b, p, fcnt) { + init_class_id(Class_RangeCheck); + } + + virtual int Opcode() const; + virtual Node* Ideal(PhaseGVN *phase, bool can_reshape); +}; + class IfProjNode : public CProjNode { public: IfProjNode(IfNode *ifnode, uint idx) : CProjNode(ifnode,idx) {} diff --git a/hotspot/src/share/vm/opto/classes.hpp b/hotspot/src/share/vm/opto/classes.hpp index 754c8f6a08f..0779c3b96a8 100644 --- a/hotspot/src/share/vm/opto/classes.hpp +++ b/hotspot/src/share/vm/opto/classes.hpp @@ -138,6 +138,7 @@ macro(Goto) macro(Halt) macro(HasNegatives) macro(If) +macro(RangeCheck) macro(IfFalse) macro(IfTrue) macro(Initialize) diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 94a97e3d5ae..1ad17284915 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -3181,6 +3181,13 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { n->set_req(MemBarNode::Precedent, top()); } break; + case Op_RangeCheck: { + RangeCheckNode* rc = n->as_RangeCheck(); + Node* iff = new IfNode(rc->in(0), rc->in(1), rc->_prob, rc->_fcnt); + n->subsume_by(iff, this); + frc._tests.push(iff); + break; + } default: assert( !n->is_Call(), "" ); assert( !n->is_Mem(), "" ); @@ -3189,8 +3196,9 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { } // Collect CFG split points - if (n->is_MultiBranch()) + if (n->is_MultiBranch() && !n->is_RangeCheck()) { frc._tests.push(n); + } } //------------------------------final_graph_reshaping_walk--------------------- diff --git a/hotspot/src/share/vm/opto/ifnode.cpp b/hotspot/src/share/vm/opto/ifnode.cpp index e560e6533e7..b43b35f1610 100644 --- a/hotspot/src/share/vm/opto/ifnode.cpp +++ b/hotspot/src/share/vm/opto/ifnode.cpp @@ -306,12 +306,16 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) { Node *b_c = phase->transform(new BoolNode(cmp_c,b->_test._test)); Node *b_x = phase->transform(new BoolNode(cmp_x,b->_test._test)); // Make the IfNode - IfNode *iff_c = new IfNode(region_c,b_c,iff->_prob,iff->_fcnt); + IfNode* iff_c = iff->clone()->as_If(); + iff_c->set_req(0, region_c); + iff_c->set_req(1, b_c); igvn->set_type_bottom(iff_c); igvn->_worklist.push(iff_c); hook->init_req(2, iff_c); - IfNode *iff_x = new IfNode(region_x,b_x,iff->_prob, iff->_fcnt); + IfNode* iff_x = iff->clone()->as_If(); + iff_x->set_req(0, region_x); + iff_x->set_req(1, b_x); igvn->set_type_bottom(iff_x); igvn->_worklist.push(iff_x); hook->init_req(3, iff_x); @@ -496,7 +500,7 @@ ProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) { // Return 0 if not a range check. Return 1 if a range check and set index and // offset. Return 2 if we had to negate the test. Index is NULL if the check // is versus a constant. -int IfNode::is_range_check(Node* &range, Node* &index, jint &offset) { +int RangeCheckNode::is_range_check(Node* &range, Node* &index, jint &offset) { int flip_test = 0; Node* l = NULL; Node* r = NULL; @@ -724,7 +728,7 @@ bool IfNode::is_ctrl_folds(Node* ctrl, PhaseIterGVN* igvn) { return ctrl != NULL && ctrl->is_Proj() && ctrl->in(0) != NULL && - ctrl->in(0)->is_If() && + ctrl->in(0)->Opcode() == Op_If && ctrl->in(0)->outcnt() == 2 && ctrl->in(0)->as_If()->cmpi_folds(igvn) && // Must compare same value @@ -972,8 +976,8 @@ bool IfNode::fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* f if (failtype->_lo > failtype->_hi) { // previous if determines the result of this if so // replace Bool with constant - igvn->hash_delete(this); - set_req(1, igvn->intcon(success->_con)); + igvn->_worklist.push(in(1)); + igvn->replace_input_of(this, 1, igvn->intcon(success->_con)); return true; } } @@ -992,7 +996,8 @@ bool IfNode::fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* f Node* newbool = igvn->transform(new BoolNode(newcmp, cond)); igvn->replace_input_of(dom_iff, 1, igvn->intcon(proj->_con)); - set_req(1, newbool); + igvn->_worklist.push(in(1)); + igvn->replace_input_of(this, 1, newbool); return true; } @@ -1002,7 +1007,10 @@ bool IfNode::fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* f // Merge the branches that trap for this If and the dominating If into // a single region that branches to the uncommon trap for the // dominating If -void IfNode::merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn) { +Node* IfNode::merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn) { + Node* res = this; + assert(success->in(0) == this, "bad projection"); + ProjNode* otherproj = proj->other_if_proj(); CallStaticJavaNode* unc = success->is_uncommon_trap_proj(Deoptimization::Reason_none); @@ -1038,6 +1046,8 @@ void IfNode::merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* f trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_range_check, action); improve_address_types(l, r, fail, igvn); + + res = igvn->transform(new RangeCheckNode(in(0), in(1), _prob, _fcnt)); } else if (unc != dom_unc) { // If we trap we won't know what CmpI would have caused the trap // so use a special trap reason to mark this pair of CmpI nodes as @@ -1047,6 +1057,7 @@ void IfNode::merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* f trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_unstable_fused_if, action); } igvn->replace_input_of(dom_unc, TypeFunc::Parms, igvn->intcon(trap_request)); + return res; } // If we are turning 2 CmpI nodes into a CmpU that follows the pattern @@ -1240,8 +1251,7 @@ Node* IfNode::fold_compares(PhaseIterGVN* igvn) { if (has_only_uncommon_traps(dom_cmp, success, fail, igvn) && // Next call modifies graph so must be last fold_compares_helper(dom_cmp, success, fail, igvn)) { - merge_uncommon_traps(dom_cmp, success, fail, igvn); - return this; + return merge_uncommon_traps(dom_cmp, success, fail, igvn); } return NULL; } else if (ctrl->in(0) != NULL && @@ -1260,8 +1270,7 @@ Node* IfNode::fold_compares(PhaseIterGVN* igvn) { // Next call modifies graph so must be last fold_compares_helper(dom_cmp, success, fail, igvn)) { reroute_side_effect_free_unc(other_cmp, dom_cmp, igvn); - merge_uncommon_traps(dom_cmp, success, fail, igvn); - return this; + return merge_uncommon_traps(dom_cmp, success, fail, igvn); } } } @@ -1342,14 +1351,10 @@ struct RangeCheck { jint off; }; -//------------------------------Ideal------------------------------------------ -// Return a node which is more "ideal" than the current node. Strip out -// control copies -Node *IfNode::Ideal(PhaseGVN *phase, bool can_reshape) { +Node* IfNode::Ideal_common(PhaseGVN *phase, bool can_reshape) { if (remove_dead_region(phase, can_reshape)) return this; // No Def-Use info? if (!can_reshape) return NULL; - PhaseIterGVN *igvn = phase->is_IterGVN(); // Don't bother trying to transform a dead if if (in(0)->is_top()) return NULL; @@ -1365,24 +1370,291 @@ Node *IfNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (idt_if != NULL) return idt_if; // Try to split the IF + PhaseIterGVN *igvn = phase->is_IterGVN(); Node *s = split_if(this, igvn); if (s != NULL) return s; + return NodeSentinel; +} + +//------------------------------Ideal------------------------------------------ +// Return a node which is more "ideal" than the current node. Strip out +// control copies +Node* IfNode::Ideal(PhaseGVN *phase, bool can_reshape) { + Node* res = Ideal_common(phase, can_reshape); + if (res != NodeSentinel) { + return res; + } + // Check for people making a useless boolean: things like // if( (x < y ? true : false) ) { ... } // Replace with if( x < y ) { ... } Node *bol2 = remove_useless_bool(this, phase); if( bol2 ) return bol2; + if (in(0) == NULL) return NULL; // Dead loop? + + PhaseIterGVN *igvn = phase->is_IterGVN(); + Node* result = fold_compares(igvn); + if (result != NULL) { + return result; + } + + // Scan for an equivalent test + Node *cmp; + int dist = 0; // Cutoff limit for search + int op = Opcode(); + if( op == Op_If && + (cmp=in(1)->in(1))->Opcode() == Op_CmpP ) { + if( cmp->in(2) != NULL && // make sure cmp is not already dead + cmp->in(2)->bottom_type() == TypePtr::NULL_PTR ) { + dist = 64; // Limit for null-pointer scans + } else { + dist = 4; // Do not bother for random pointer tests + } + } else { + dist = 4; // Limit for random junky scans + } + + Node* prev_dom = search_identical(dist); + + if (prev_dom == NULL) { + return NULL; + } + + // Replace dominated IfNode + return dominated_by(prev_dom, igvn); +} + +//------------------------------dominated_by----------------------------------- +Node* IfNode::dominated_by(Node* prev_dom, PhaseIterGVN *igvn) { +#ifndef PRODUCT + if (TraceIterativeGVN) { + tty->print(" Removing IfNode: "); this->dump(); + } + if (VerifyOpto && !igvn->allow_progress()) { + // Found an equivalent dominating test, + // we can not guarantee reaching a fix-point for these during iterativeGVN + // since intervening nodes may not change. + return NULL; + } +#endif + + igvn->hash_delete(this); // Remove self to prevent spurious V-N + Node *idom = in(0); + // Need opcode to decide which way 'this' test goes + int prev_op = prev_dom->Opcode(); + Node *top = igvn->C->top(); // Shortcut to top + + // Loop predicates may have depending checks which should not + // be skipped. For example, range check predicate has two checks + // for lower and upper bounds. + ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj(); + if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != NULL) + prev_dom = idom; + + // Now walk the current IfNode's projections. + // Loop ends when 'this' has no more uses. + for (DUIterator_Last imin, i = last_outs(imin); i >= imin; --i) { + Node *ifp = last_out(i); // Get IfTrue/IfFalse + igvn->add_users_to_worklist(ifp); + // Check which projection it is and set target. + // Data-target is either the dominating projection of the same type + // or TOP if the dominating projection is of opposite type. + // Data-target will be used as the new control edge for the non-CFG + // nodes like Casts and Loads. + Node *data_target = (ifp->Opcode() == prev_op) ? prev_dom : top; + // Control-target is just the If's immediate dominator or TOP. + Node *ctrl_target = (ifp->Opcode() == prev_op) ? idom : top; + + // For each child of an IfTrue/IfFalse projection, reroute. + // Loop ends when projection has no more uses. + for (DUIterator_Last jmin, j = ifp->last_outs(jmin); j >= jmin; --j) { + Node* s = ifp->last_out(j); // Get child of IfTrue/IfFalse + if( !s->depends_only_on_test() ) { + // Find the control input matching this def-use edge. + // For Regions it may not be in slot 0. + uint l; + for( l = 0; s->in(l) != ifp; l++ ) { } + igvn->replace_input_of(s, l, ctrl_target); + } else { // Else, for control producers, + igvn->replace_input_of(s, 0, data_target); // Move child to data-target + } + } // End for each child of a projection + + igvn->remove_dead_node(ifp); + } // End for each IfTrue/IfFalse child of If + + // Kill the IfNode + igvn->remove_dead_node(this); + + // Must return either the original node (now dead) or a new node + // (Do not return a top here, since that would break the uniqueness of top.) + return new ConINode(TypeInt::ZERO); +} + +Node* IfNode::search_identical(int dist) { // Setup to scan up the CFG looking for a dominating test - Node *dom = in(0); - Node *prev_dom = this; + Node* dom = in(0); + Node* prev_dom = this; + int op = Opcode(); + // Search up the dominator tree for an If with an identical test + while( dom->Opcode() != op || // Not same opcode? + dom->in(1) != in(1) || // Not same input 1? + (req() == 3 && dom->in(2) != in(2)) || // Not same input 2? + prev_dom->in(0) != dom ) { // One path of test does not dominate? + if( dist < 0 ) return NULL; + + dist--; + prev_dom = dom; + dom = up_one_dom( dom ); + if( !dom ) return NULL; + } + + // Check that we did not follow a loop back to ourselves + if( this == dom ) + return NULL; + + if( dist > 2 ) // Add to count of NULL checks elided + explicit_null_checks_elided++; + + return prev_dom; +} + +//------------------------------Identity--------------------------------------- +// If the test is constant & we match, then we are the input Control +Node *IfProjNode::Identity(PhaseTransform *phase) { + // Can only optimize if cannot go the other way + const TypeTuple *t = phase->type(in(0))->is_tuple(); + if (t == TypeTuple::IFNEITHER || + // kill dead branch first otherwise the IfNode's control will + // have 2 control uses (the IfNode that doesn't go away because + // it still has uses and this branch of the + // If). Node::has_special_unique_user() will cause this node to + // be reprocessed once the dead branch is killed. + (always_taken(t) && in(0)->outcnt() == 1)) { + // IfNode control + return in(0)->in(0); + } + // no progress + return this; +} + +#ifndef PRODUCT +//-------------------------------related--------------------------------------- +// An IfProjNode's related node set consists of its input (an IfNode) including +// the IfNode's condition, plus all of its outputs at level 1. In compact mode, +// the restrictions for IfNode apply (see IfNode::rel). +void IfProjNode::related(GrowableArray *in_rel, GrowableArray *out_rel, bool compact) const { + Node* ifNode = this->in(0); + in_rel->append(ifNode); + if (compact) { + ifNode->collect_nodes(in_rel, 3, false, true); + } else { + ifNode->collect_nodes_in_all_data(in_rel, false); + } + this->collect_nodes(out_rel, -1, false, false); +} + +//------------------------------dump_spec-------------------------------------- +void IfNode::dump_spec(outputStream *st) const { + st->print("P=%f, C=%f",_prob,_fcnt); +} + +//-------------------------------related--------------------------------------- +// For an IfNode, the set of related output nodes is just the output nodes till +// depth 2, i.e, the IfTrue/IfFalse projection nodes plus the nodes they refer. +// The related input nodes contain no control nodes, but all data nodes +// pertaining to the condition. In compact mode, the input nodes are collected +// up to a depth of 3. +void IfNode::related(GrowableArray *in_rel, GrowableArray *out_rel, bool compact) const { + if (compact) { + this->collect_nodes(in_rel, 3, false, true); + } else { + this->collect_nodes_in_all_data(in_rel, false); + } + this->collect_nodes(out_rel, -2, false, false); +} +#endif + +//------------------------------idealize_test---------------------------------- +// Try to canonicalize tests better. Peek at the Cmp/Bool/If sequence and +// come up with a canonical sequence. Bools getting 'eq', 'gt' and 'ge' forms +// converted to 'ne', 'le' and 'lt' forms. IfTrue/IfFalse get swapped as +// needed. +static IfNode* idealize_test(PhaseGVN* phase, IfNode* iff) { + assert(iff->in(0) != NULL, "If must be live"); + + if (iff->outcnt() != 2) return NULL; // Malformed projections. + Node* old_if_f = iff->proj_out(false); + Node* old_if_t = iff->proj_out(true); + + // CountedLoopEnds want the back-control test to be TRUE, irregardless of + // whether they are testing a 'gt' or 'lt' condition. The 'gt' condition + // happens in count-down loops + if (iff->is_CountedLoopEnd()) return NULL; + if (!iff->in(1)->is_Bool()) return NULL; // Happens for partially optimized IF tests + BoolNode *b = iff->in(1)->as_Bool(); + BoolTest bt = b->_test; + // Test already in good order? + if( bt.is_canonical() ) + return NULL; + + // Flip test to be canonical. Requires flipping the IfFalse/IfTrue and + // cloning the IfNode. + Node* new_b = phase->transform( new BoolNode(b->in(1), bt.negate()) ); + if( !new_b->is_Bool() ) return NULL; + b = new_b->as_Bool(); + + PhaseIterGVN *igvn = phase->is_IterGVN(); + assert( igvn, "Test is not canonical in parser?" ); + + // The IF node never really changes, but it needs to be cloned + iff = iff->clone()->as_If(); + iff->set_req(1, b); + iff->_prob = 1.0-iff->_prob; + + Node *prior = igvn->hash_find_insert(iff); + if( prior ) { + igvn->remove_dead_node(iff); + iff = (IfNode*)prior; + } else { + // Cannot call transform on it just yet + igvn->set_type_bottom(iff); + } + igvn->_worklist.push(iff); + + // Now handle projections. Cloning not required. + Node* new_if_f = (Node*)(new IfFalseNode( iff )); + Node* new_if_t = (Node*)(new IfTrueNode ( iff )); + + igvn->register_new_node_with_optimizer(new_if_f); + igvn->register_new_node_with_optimizer(new_if_t); + // Flip test, so flip trailing control + igvn->replace_node(old_if_f, new_if_t); + igvn->replace_node(old_if_t, new_if_f); + + // Progress + return iff; +} + +Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { + Node* res = Ideal_common(phase, can_reshape); + if (res != NodeSentinel) { + return res; + } + + PhaseIterGVN *igvn = phase->is_IterGVN(); + // Setup to scan up the CFG looking for a dominating test + Node* prev_dom = this; // Check for range-check vs other kinds of tests - Node *index1, *range1; + Node* index1; + Node* range1; jint offset1; int flip1 = is_range_check(range1, index1, offset1); - if( flip1 ) { + if (flip1) { + Node* dom = in(0); // Try to remove extra range checks. All 'up_one_dom' gives up at merges // so all checks we inspect post-dominate the top-most check we find. // If we are going to fail the current check and we reach the top check @@ -1403,13 +1675,14 @@ Node *IfNode::Ideal(PhaseGVN *phase, bool can_reshape) { // Scan for the top checks and collect range of offsets for (int dist = 0; dist < 999; dist++) { // Range-Check scan limit - if (dom->Opcode() == Op_If && // Not same opcode? + if (dom->Opcode() == Op_RangeCheck && // Not same opcode? prev_dom->in(0) == dom) { // One path of test does dominate? if (dom == this) return NULL; // dead loop // See if this is a range check - Node *index2, *range2; + Node* index2; + Node* range2; jint offset2; - int flip2 = dom->as_If()->is_range_check(range2, index2, offset2); + int flip2 = dom->as_RangeCheck()->is_range_check(range2, index2, offset2); // See if this is a _matching_ range check, checking against // the same array bounds. if (flip2 == flip1 && range2 == range1 && index2 == index1 && @@ -1517,237 +1790,14 @@ Node *IfNode::Ideal(PhaseGVN *phase, bool can_reshape) { prev_dom = rc0.ctl; } } + } else { + prev_dom = search_identical(4); - } else { // Scan for an equivalent test - - Node *cmp; - int dist = 0; // Cutoff limit for search - int op = Opcode(); - if( op == Op_If && - (cmp=in(1)->in(1))->Opcode() == Op_CmpP ) { - if( cmp->in(2) != NULL && // make sure cmp is not already dead - cmp->in(2)->bottom_type() == TypePtr::NULL_PTR ) { - dist = 64; // Limit for null-pointer scans - } else { - dist = 4; // Do not bother for random pointer tests - } - } else { - dist = 4; // Limit for random junky scans - } - - // Normal equivalent-test check. - if( !dom ) return NULL; // Dead loop? - - Node* result = fold_compares(igvn); - if (result != NULL) { - return result; - } - - // Search up the dominator tree for an If with an identical test - while( dom->Opcode() != op || // Not same opcode? - dom->in(1) != in(1) || // Not same input 1? - (req() == 3 && dom->in(2) != in(2)) || // Not same input 2? - prev_dom->in(0) != dom ) { // One path of test does not dominate? - if( dist < 0 ) return NULL; - - dist--; - prev_dom = dom; - dom = up_one_dom( dom ); - if( !dom ) return NULL; - } - - // Check that we did not follow a loop back to ourselves - if( this == dom ) + if (prev_dom == NULL) { return NULL; - - if( dist > 2 ) // Add to count of NULL checks elided - explicit_null_checks_elided++; - - } // End of Else scan for an equivalent test - - // Hit! Remove this IF -#ifndef PRODUCT - if( TraceIterativeGVN ) { - tty->print(" Removing IfNode: "); this->dump(); + } } - if( VerifyOpto && !phase->allow_progress() ) { - // Found an equivalent dominating test, - // we can not guarantee reaching a fix-point for these during iterativeGVN - // since intervening nodes may not change. - return NULL; - } -#endif // Replace dominated IfNode - dominated_by( prev_dom, igvn ); - - // Must return either the original node (now dead) or a new node - // (Do not return a top here, since that would break the uniqueness of top.) - return new ConINode(TypeInt::ZERO); -} - -//------------------------------dominated_by----------------------------------- -void IfNode::dominated_by( Node *prev_dom, PhaseIterGVN *igvn ) { - igvn->hash_delete(this); // Remove self to prevent spurious V-N - Node *idom = in(0); - // Need opcode to decide which way 'this' test goes - int prev_op = prev_dom->Opcode(); - Node *top = igvn->C->top(); // Shortcut to top - - // Loop predicates may have depending checks which should not - // be skipped. For example, range check predicate has two checks - // for lower and upper bounds. - ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj(); - if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != NULL) - prev_dom = idom; - - // Now walk the current IfNode's projections. - // Loop ends when 'this' has no more uses. - for (DUIterator_Last imin, i = last_outs(imin); i >= imin; --i) { - Node *ifp = last_out(i); // Get IfTrue/IfFalse - igvn->add_users_to_worklist(ifp); - // Check which projection it is and set target. - // Data-target is either the dominating projection of the same type - // or TOP if the dominating projection is of opposite type. - // Data-target will be used as the new control edge for the non-CFG - // nodes like Casts and Loads. - Node *data_target = (ifp->Opcode() == prev_op) ? prev_dom : top; - // Control-target is just the If's immediate dominator or TOP. - Node *ctrl_target = (ifp->Opcode() == prev_op) ? idom : top; - - // For each child of an IfTrue/IfFalse projection, reroute. - // Loop ends when projection has no more uses. - for (DUIterator_Last jmin, j = ifp->last_outs(jmin); j >= jmin; --j) { - Node* s = ifp->last_out(j); // Get child of IfTrue/IfFalse - if( !s->depends_only_on_test() ) { - // Find the control input matching this def-use edge. - // For Regions it may not be in slot 0. - uint l; - for( l = 0; s->in(l) != ifp; l++ ) { } - igvn->replace_input_of(s, l, ctrl_target); - } else { // Else, for control producers, - igvn->replace_input_of(s, 0, data_target); // Move child to data-target - } - } // End for each child of a projection - - igvn->remove_dead_node(ifp); - } // End for each IfTrue/IfFalse child of If - - // Kill the IfNode - igvn->remove_dead_node(this); -} - -//------------------------------Identity--------------------------------------- -// If the test is constant & we match, then we are the input Control -Node *IfProjNode::Identity(PhaseTransform *phase) { - // Can only optimize if cannot go the other way - const TypeTuple *t = phase->type(in(0))->is_tuple(); - if (t == TypeTuple::IFNEITHER || - // kill dead branch first otherwise the IfNode's control will - // have 2 control uses (the IfNode that doesn't go away because - // it still has uses and this branch of the - // If). Node::has_special_unique_user() will cause this node to - // be reprocessed once the dead branch is killed. - (always_taken(t) && in(0)->outcnt() == 1)) { - // IfNode control - return in(0)->in(0); - } - // no progress - return this; -} - -#ifndef PRODUCT -//-------------------------------related--------------------------------------- -// An IfProjNode's related node set consists of its input (an IfNode) including -// the IfNode's condition, plus all of its outputs at level 1. In compact mode, -// the restrictions for IfNode apply (see IfNode::rel). -void IfProjNode::related(GrowableArray *in_rel, GrowableArray *out_rel, bool compact) const { - Node* ifNode = this->in(0); - in_rel->append(ifNode); - if (compact) { - ifNode->collect_nodes(in_rel, 3, false, true); - } else { - ifNode->collect_nodes_in_all_data(in_rel, false); - } - this->collect_nodes(out_rel, -1, false, false); -} - -//------------------------------dump_spec-------------------------------------- -void IfNode::dump_spec(outputStream *st) const { - st->print("P=%f, C=%f",_prob,_fcnt); -} - -//-------------------------------related--------------------------------------- -// For an IfNode, the set of related output nodes is just the output nodes till -// depth 2, i.e, the IfTrue/IfFalse projection nodes plus the nodes they refer. -// The related input nodes contain no control nodes, but all data nodes -// pertaining to the condition. In compact mode, the input nodes are collected -// up to a depth of 3. -void IfNode::related(GrowableArray *in_rel, GrowableArray *out_rel, bool compact) const { - if (compact) { - this->collect_nodes(in_rel, 3, false, true); - } else { - this->collect_nodes_in_all_data(in_rel, false); - } - this->collect_nodes(out_rel, -2, false, false); -} -#endif - -//------------------------------idealize_test---------------------------------- -// Try to canonicalize tests better. Peek at the Cmp/Bool/If sequence and -// come up with a canonical sequence. Bools getting 'eq', 'gt' and 'ge' forms -// converted to 'ne', 'le' and 'lt' forms. IfTrue/IfFalse get swapped as -// needed. -static IfNode* idealize_test(PhaseGVN* phase, IfNode* iff) { - assert(iff->in(0) != NULL, "If must be live"); - - if (iff->outcnt() != 2) return NULL; // Malformed projections. - Node* old_if_f = iff->proj_out(false); - Node* old_if_t = iff->proj_out(true); - - // CountedLoopEnds want the back-control test to be TRUE, irregardless of - // whether they are testing a 'gt' or 'lt' condition. The 'gt' condition - // happens in count-down loops - if (iff->is_CountedLoopEnd()) return NULL; - if (!iff->in(1)->is_Bool()) return NULL; // Happens for partially optimized IF tests - BoolNode *b = iff->in(1)->as_Bool(); - BoolTest bt = b->_test; - // Test already in good order? - if( bt.is_canonical() ) - return NULL; - - // Flip test to be canonical. Requires flipping the IfFalse/IfTrue and - // cloning the IfNode. - Node* new_b = phase->transform( new BoolNode(b->in(1), bt.negate()) ); - if( !new_b->is_Bool() ) return NULL; - b = new_b->as_Bool(); - - PhaseIterGVN *igvn = phase->is_IterGVN(); - assert( igvn, "Test is not canonical in parser?" ); - - // The IF node never really changes, but it needs to be cloned - iff = new IfNode( iff->in(0), b, 1.0-iff->_prob, iff->_fcnt); - - Node *prior = igvn->hash_find_insert(iff); - if( prior ) { - igvn->remove_dead_node(iff); - iff = (IfNode*)prior; - } else { - // Cannot call transform on it just yet - igvn->set_type_bottom(iff); - } - igvn->_worklist.push(iff); - - // Now handle projections. Cloning not required. - Node* new_if_f = (Node*)(new IfFalseNode( iff )); - Node* new_if_t = (Node*)(new IfTrueNode ( iff )); - - igvn->register_new_node_with_optimizer(new_if_f); - igvn->register_new_node_with_optimizer(new_if_t); - // Flip test, so flip trailing control - igvn->replace_node(old_if_f, new_if_t); - igvn->replace_node(old_if_t, new_if_f); - - // Progress - return iff; + return dominated_by(prev_dom, igvn); } diff --git a/hotspot/src/share/vm/opto/loopPredicate.cpp b/hotspot/src/share/vm/opto/loopPredicate.cpp index 8d202294807..6ed9e9f5006 100644 --- a/hotspot/src/share/vm/opto/loopPredicate.cpp +++ b/hotspot/src/share/vm/opto/loopPredicate.cpp @@ -91,7 +91,8 @@ void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred) // The true projecttion (if_cont) of the new_iff is returned. // This code is also used to clone predicates to cloned loops. ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, - Deoptimization::DeoptReason reason) { + Deoptimization::DeoptReason reason, + int opcode) { assert(cont_proj->is_uncommon_trap_if_pattern(reason), "must be a uct if pattern!"); IfNode* iff = cont_proj->in(0)->as_If(); @@ -133,8 +134,13 @@ ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* } // Create new_iff IdealLoopTree* lp = get_loop(entry); - IfNode *new_iff = iff->clone()->as_If(); - new_iff->set_req(0, entry); + IfNode* new_iff = NULL; + if (opcode == Op_If) { + new_iff = new IfNode(entry, iff->in(1), iff->_prob, iff->_fcnt); + } else { + assert(opcode == Op_RangeCheck, "no other if variant here"); + new_iff = new RangeCheckNode(entry, iff->in(1), iff->_prob, iff->_fcnt); + } register_control(new_iff, lp, entry); Node *if_cont = new IfTrueNode(new_iff); Node *if_uct = new IfFalseNode(new_iff); @@ -183,7 +189,8 @@ ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* //------------------------------create_new_if_for_predicate------------------------ // Create a new if below new_entry for the predicate to be cloned (IGVN optimization) ProjNode* PhaseIterGVN::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, - Deoptimization::DeoptReason reason) { + Deoptimization::DeoptReason reason, + int opcode) { assert(new_entry != 0, "only used for clone predicate"); assert(cont_proj->is_uncommon_trap_if_pattern(reason), "must be a uct if pattern!"); IfNode* iff = cont_proj->in(0)->as_If(); @@ -208,8 +215,13 @@ ProjNode* PhaseIterGVN::create_new_if_for_predicate(ProjNode* cont_proj, Node* n } // Create new_iff in new location. - IfNode *new_iff = iff->clone()->as_If(); - new_iff->set_req(0, new_entry); + IfNode* new_iff = NULL; + if (opcode == Op_If) { + new_iff = new IfNode(new_entry, iff->in(1), iff->_prob, iff->_fcnt); + } else { + assert(opcode == Op_RangeCheck, "no other if variant here"); + new_iff = new RangeCheckNode(new_entry, iff->in(1), iff->_prob, iff->_fcnt); + } register_new_node_with_optimizer(new_iff); Node *if_cont = new IfTrueNode(new_iff); @@ -249,9 +261,9 @@ ProjNode* PhaseIdealLoop::clone_predicate(ProjNode* predicate_proj, Node* new_en PhaseIterGVN* igvn) { ProjNode* new_predicate_proj; if (loop_phase != NULL) { - new_predicate_proj = loop_phase->create_new_if_for_predicate(predicate_proj, new_entry, reason); + new_predicate_proj = loop_phase->create_new_if_for_predicate(predicate_proj, new_entry, reason, Op_If); } else { - new_predicate_proj = igvn->create_new_if_for_predicate(predicate_proj, new_entry, reason); + new_predicate_proj = igvn->create_new_if_for_predicate(predicate_proj, new_entry, reason, Op_If); } IfNode* iff = new_predicate_proj->in(0)->as_If(); Node* ctrl = iff->in(0); @@ -714,7 +726,8 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { while (current_proj != head) { if (loop == get_loop(current_proj) && // still in the loop ? current_proj->is_Proj() && // is a projection ? - current_proj->in(0)->Opcode() == Op_If) { // is a if projection ? + (current_proj->in(0)->Opcode() == Op_If || + current_proj->in(0)->Opcode() == Op_RangeCheck)) { // is a if projection ? if_proj_list.push(current_proj); } current_proj = idom(current_proj); @@ -753,7 +766,8 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { if (invar.is_invariant(bol)) { // Invariant test new_predicate_proj = create_new_if_for_predicate(predicate_proj, NULL, - Deoptimization::Reason_predicate); + Deoptimization::Reason_predicate, + iff->Opcode()); Node* ctrl = new_predicate_proj->in(0)->as_If()->in(0); BoolNode* new_predicate_bol = invar.clone(bol, ctrl)->as_Bool(); @@ -797,8 +811,8 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { // lower_bound test will dominate the upper bound test and all // cloned or created nodes will use the lower bound test as // their declared control. - ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate); - ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate); + ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate, iff->Opcode()); + ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate, iff->Opcode()); assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate"); Node *ctrl = lower_bound_proj->in(0)->as_If()->in(0); diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index 735a00dd1a1..692ef9f58c0 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -290,7 +290,7 @@ bool IdealLoopTree::policy_peeling( PhaseIdealLoop *phase ) const { if (ctrl->is_top()) return false; // Found dead test on live IF? No peeling! // Standard IF only has one input value to check for loop invariance - assert( test->Opcode() == Op_If || test->Opcode() == Op_CountedLoopEnd, "Check this code when new subtype is added"); + assert(test->Opcode() == Op_If || test->Opcode() == Op_CountedLoopEnd || test->Opcode() == Op_RangeCheck, "Check this code when new subtype is added"); // Condition is not a member of this loop? if( !is_member(phase->get_loop(ctrl)) && is_loop_exit(test) ) @@ -856,7 +856,8 @@ bool IdealLoopTree::policy_range_check( PhaseIdealLoop *phase ) const { // loop-invariant. for (uint i = 0; i < _body.size(); i++) { Node *iff = _body[i]; - if (iff->Opcode() == Op_If) { // Test? + if (iff->Opcode() == Op_If || + iff->Opcode() == Op_RangeCheck) { // Test? // Comparing trip+off vs limit Node *bol = iff->in(1); @@ -2035,8 +2036,8 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { // loop-invariant. for( uint i = 0; i < loop->_body.size(); i++ ) { Node *iff = loop->_body[i]; - if( iff->Opcode() == Op_If ) { // Test? - + if (iff->Opcode() == Op_If || + iff->Opcode() == Op_RangeCheck) { // Test? // Test is an IfNode, has 2 projections. If BOTH are in the loop // we need loop unswitching instead of iteration splitting. Node *exit = loop->is_loop_exit(iff); diff --git a/hotspot/src/share/vm/opto/loopUnswitch.cpp b/hotspot/src/share/vm/opto/loopUnswitch.cpp index 49e1052a2cd..a5976f4c93d 100644 --- a/hotspot/src/share/vm/opto/loopUnswitch.cpp +++ b/hotspot/src/share/vm/opto/loopUnswitch.cpp @@ -132,7 +132,7 @@ void PhaseIdealLoop::do_unswitching (IdealLoopTree *loop, Node_List &old_new) { head->as_CountedLoop()->set_normal_loop(); } - ProjNode* proj_true = create_slow_version_of_loop(loop, old_new); + ProjNode* proj_true = create_slow_version_of_loop(loop, old_new, unswitch_iff->Opcode()); #ifdef ASSERT Node* uniqc = proj_true->unique_ctrl_out(); @@ -222,7 +222,8 @@ void PhaseIdealLoop::do_unswitching (IdealLoopTree *loop, Node_List &old_new) { // and inserting an if to select fast-slow versions. // Return control projection of the entry to the fast version. ProjNode* PhaseIdealLoop::create_slow_version_of_loop(IdealLoopTree *loop, - Node_List &old_new) { + Node_List &old_new, + int opcode) { LoopNode* head = loop->_head->as_Loop(); bool counted_loop = head->is_CountedLoop(); Node* entry = head->in(LoopNode::EntryControl); @@ -235,7 +236,8 @@ ProjNode* PhaseIdealLoop::create_slow_version_of_loop(IdealLoopTree *loop, register_node(opq, outer_loop, entry, dom_depth(entry)); Node *bol = new Conv2BNode(opq); register_node(bol, outer_loop, entry, dom_depth(entry)); - IfNode* iff = new IfNode(entry, bol, PROB_MAX, COUNT_UNKNOWN); + IfNode* iff = (opcode == Op_RangeCheck) ? new RangeCheckNode(entry, bol, PROB_MAX, COUNT_UNKNOWN) : + new IfNode(entry, bol, PROB_MAX, COUNT_UNKNOWN); register_node(iff, outer_loop, entry, dom_depth(entry)); ProjNode* iffast = new IfTrueNode(iff); register_node(iffast, outer_loop, iff, dom_depth(iff)); diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp index 98d8c2533b0..fd736bbf426 100644 --- a/hotspot/src/share/vm/opto/loopnode.hpp +++ b/hotspot/src/share/vm/opto/loopnode.hpp @@ -916,7 +916,8 @@ public: // Create a new if above the uncommon_trap_if_pattern for the predicate to be promoted ProjNode* create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, - Deoptimization::DeoptReason reason); + Deoptimization::DeoptReason reason, + int opcode); void register_control(Node* n, IdealLoopTree *loop, Node* pred); // Clone loop predicates to cloned loops (peeled, unswitched) @@ -966,7 +967,8 @@ public: // Create a slow version of the loop by cloning the loop // and inserting an if to select fast-slow versions. ProjNode* create_slow_version_of_loop(IdealLoopTree *loop, - Node_List &old_new); + Node_List &old_new, + int opcode); // Clone a loop and return the clone head (clone_loop_head). // Added nodes include int(1), int(0) - disconnected, If, IfTrue, IfFalse, diff --git a/hotspot/src/share/vm/opto/loopopts.cpp b/hotspot/src/share/vm/opto/loopopts.cpp index 3256a06d8be..ecdf1d7f8e9 100644 --- a/hotspot/src/share/vm/opto/loopopts.cpp +++ b/hotspot/src/share/vm/opto/loopopts.cpp @@ -206,7 +206,7 @@ void PhaseIdealLoop::dominated_by( Node *prevdom, Node *iff, bool flip, bool exc // prevdom is the dominating projection of the dominating test. assert( iff->is_If(), "" ); - assert( iff->Opcode() == Op_If || iff->Opcode() == Op_CountedLoopEnd, "Check this code when new subtype is added"); + assert(iff->Opcode() == Op_If || iff->Opcode() == Op_CountedLoopEnd || iff->Opcode() == Op_RangeCheck, "Check this code when new subtype is added"); int pop = prevdom->Opcode(); assert( pop == Op_IfFalse || pop == Op_IfTrue, "" ); if (flip) { @@ -1123,7 +1123,8 @@ void PhaseIdealLoop::split_if_with_blocks_post( Node *n ) { int n_op = n->Opcode(); // Check for an IF being dominated by another IF same test - if (n_op == Op_If) { + if (n_op == Op_If || + n_op == Op_RangeCheck) { Node *bol = n->in(1); uint max = bol->outcnt(); // Check for same test used more than once? @@ -1945,7 +1946,10 @@ ProjNode* PhaseIdealLoop::insert_if_before_proj(Node* left, bool Signed, BoolTes BoolNode* bol = new BoolNode(cmp, relop); register_node(bol, loop, proj2, ddepth); - IfNode* new_if = new IfNode(proj2, bol, iff->_prob, iff->_fcnt); + int opcode = iff->Opcode(); + assert(opcode == Op_If || opcode == Op_RangeCheck, "unexpected opcode"); + IfNode* new_if = (opcode == Op_If) ? new IfNode(proj2, bol, iff->_prob, iff->_fcnt): + new RangeCheckNode(proj2, bol, iff->_prob, iff->_fcnt); register_node(new_if, loop, proj2, ddepth); proj->set_req(0, new_if); // reattach diff --git a/hotspot/src/share/vm/opto/multnode.cpp b/hotspot/src/share/vm/opto/multnode.cpp index 3648fef790e..83ef36b7621 100644 --- a/hotspot/src/share/vm/opto/multnode.cpp +++ b/hotspot/src/share/vm/opto/multnode.cpp @@ -44,14 +44,14 @@ Node *MultiNode::match( const ProjNode *proj, const Matcher *m ) { return proj-> //------------------------------proj_out--------------------------------------- // Get a named projection ProjNode* MultiNode::proj_out(uint which_proj) const { - assert(Opcode() != Op_If || which_proj == (uint)true || which_proj == (uint)false, "must be 1 or 0"); - assert(Opcode() != Op_If || outcnt() == 2, "bad if #1"); + assert((Opcode() != Op_If && Opcode() != Op_RangeCheck) || which_proj == (uint)true || which_proj == (uint)false, "must be 1 or 0"); + assert((Opcode() != Op_If && Opcode() != Op_RangeCheck) || outcnt() == 2, "bad if #1"); for( DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++ ) { Node *p = fast_out(i); if (p->is_Proj()) { ProjNode *proj = p->as_Proj(); if (proj->_con == which_proj) { - assert(Opcode() != Op_If || proj->Opcode() == (which_proj?Op_IfTrue:Op_IfFalse), "bad if #2"); + assert((Opcode() != Op_If && Opcode() != Op_RangeCheck) || proj->Opcode() == (which_proj ? Op_IfTrue : Op_IfFalse), "bad if #2"); return proj; } } else { diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp index a779923db00..0117027d5d5 100644 --- a/hotspot/src/share/vm/opto/node.hpp +++ b/hotspot/src/share/vm/opto/node.hpp @@ -125,6 +125,7 @@ class PhaseValues; class PhiNode; class Pipeline; class ProjNode; +class RangeCheckNode; class RegMask; class RegionNode; class RootNode; @@ -584,6 +585,7 @@ public: DEFINE_CLASS_ID(Jump, PCTable, 1) DEFINE_CLASS_ID(If, MultiBranch, 1) DEFINE_CLASS_ID(CountedLoopEnd, If, 0) + DEFINE_CLASS_ID(RangeCheck, If, 1) DEFINE_CLASS_ID(NeverBranch, MultiBranch, 2) DEFINE_CLASS_ID(Start, Multi, 2) DEFINE_CLASS_ID(MemBar, Multi, 3) @@ -758,6 +760,7 @@ public: DEFINE_CLASS_QUERY(FastLock) DEFINE_CLASS_QUERY(FastUnlock) DEFINE_CLASS_QUERY(If) + DEFINE_CLASS_QUERY(RangeCheck) DEFINE_CLASS_QUERY(IfFalse) DEFINE_CLASS_QUERY(IfTrue) DEFINE_CLASS_QUERY(Initialize) diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp index cd68d761568..eced1be6b92 100644 --- a/hotspot/src/share/vm/opto/parse2.cpp +++ b/hotspot/src/share/vm/opto/parse2.cpp @@ -136,8 +136,16 @@ Node* Parse::array_addressing(BasicType type, int vals, const Type* *result2) { BoolTest::mask btest = BoolTest::lt; tst = _gvn.transform( new BoolNode(chk, btest) ); } + RangeCheckNode* rc = new RangeCheckNode(control(), tst, PROB_MAX, COUNT_UNKNOWN); + _gvn.set_type(rc, rc->Value(&_gvn)); + if (!tst->is_Con()) { + record_for_igvn(rc); + } + set_control(_gvn.transform(new IfTrueNode(rc))); // Branch to failure if out of bounds - { BuildCutout unless(this, tst, PROB_MAX); + { + PreserveJVMState pjvms(this); + set_control(_gvn.transform(new IfFalseNode(rc))); if (C->allow_range_check_smearing()) { // Do not use builtin_throw, since range checks are sometimes // made more stringent by an optimistic transformation. diff --git a/hotspot/src/share/vm/opto/phaseX.hpp b/hotspot/src/share/vm/opto/phaseX.hpp index a3e06c825a7..efd7b456853 100644 --- a/hotspot/src/share/vm/opto/phaseX.hpp +++ b/hotspot/src/share/vm/opto/phaseX.hpp @@ -521,7 +521,8 @@ public: Node* clone_loop_predicates(Node* old_entry, Node* new_entry, bool clone_limit_check); // Create a new if below new_entry for the predicate to be cloned ProjNode* create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, - Deoptimization::DeoptReason reason); + Deoptimization::DeoptReason reason, + int opcode); void remove_speculative_types(); void check_no_speculative_types() { From 3d745923ca0f6ec0be558e7a0e74201498488cb5 Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Tue, 10 Nov 2015 10:34:39 -1000 Subject: [PATCH 018/260] 8142329: [JVMCI] pass Handle by value Reviewed-by: coleenp, twisti --- .../src/share/vm/compiler/compileBroker.cpp | 3 +- .../src/share/vm/jvmci/jvmciCodeInstaller.cpp | 4 +-- .../src/share/vm/jvmci/jvmciCodeInstaller.hpp | 4 +-- hotspot/src/share/vm/jvmci/jvmciCompiler.cpp | 2 +- hotspot/src/share/vm/jvmci/jvmciCompiler.hpp | 2 +- .../src/share/vm/jvmci/jvmciCompilerToVM.cpp | 2 +- .../src/share/vm/jvmci/jvmciCompilerToVM.hpp | 2 +- hotspot/src/share/vm/jvmci/jvmciEnv.cpp | 34 +++++++++---------- hotspot/src/share/vm/jvmci/jvmciEnv.hpp | 34 +++++++++---------- .../src/share/vm/jvmci/jvmciJavaClasses.hpp | 4 +-- 10 files changed, 46 insertions(+), 45 deletions(-) diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 7e28599fda1..c7453649cdb 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -1716,7 +1716,8 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { EventCompilation event; JVMCIEnv env(task, system_dictionary_modification_counter); - jvmci->compile_method(target_handle, osr_bci, &env); + methodHandle method(thread, target_handle); + jvmci->compile_method(method, osr_bci, &env); post_compile(thread, task, event, task->code() != NULL, NULL); } else diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp index 53d78754386..df84301f5bf 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp @@ -475,7 +475,7 @@ void RelocBuffer::ensure_size(size_t bytes) { _size = bytes; } -JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle& compiled_code, CodeMetadata& metadata, TRAPS) { +JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle compiled_code, CodeMetadata& metadata, TRAPS) { CodeBuffer buffer("JVMCI Compiler CodeBuffer for Metadata"); jobject compiled_code_obj = JNIHandles::make_local(compiled_code()); initialize_dependencies(JNIHandles::resolve(compiled_code_obj), NULL, CHECK_OK); @@ -508,7 +508,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle } // constructor used to create a method -JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Handle target, Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log, TRAPS) { +JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Handle target, Handle compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log, TRAPS) { CodeBuffer buffer("JVMCI Compiler CodeBuffer"); jobject compiled_code_obj = JNIHandles::make_local(compiled_code()); OopRecorder* recorder = new OopRecorder(&_arena, true); diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp index 2114e0c9166..d2e40c86338 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp @@ -177,8 +177,8 @@ public: CodeInstaller() : _arena(mtCompiler) {} - JVMCIEnv::CodeInstallResult gather_metadata(Handle target, Handle& compiled_code, CodeMetadata& metadata, TRAPS); - JVMCIEnv::CodeInstallResult install(JVMCICompiler* compiler, Handle target, Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log, TRAPS); + JVMCIEnv::CodeInstallResult gather_metadata(Handle target, Handle compiled_code, CodeMetadata& metadata, TRAPS); + JVMCIEnv::CodeInstallResult install(JVMCICompiler* compiler, Handle target, Handle compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log, TRAPS); static address runtime_call_target_address(oop runtime_call); static VMReg get_hotspot_reg(jint jvmciRegisterNumber, TRAPS); diff --git a/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp b/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp index 836d407c8d5..69912980a66 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp @@ -112,7 +112,7 @@ void JVMCICompiler::bootstrap() { _bootstrapping = false; } -void JVMCICompiler::compile_method(methodHandle method, int entry_bci, JVMCIEnv* env) { +void JVMCICompiler::compile_method(const methodHandle& method, int entry_bci, JVMCIEnv* env) { JVMCI_EXCEPTION_CONTEXT bool is_osr = entry_bci != InvocationEntryBci; diff --git a/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp b/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp index 0b0a38d5afa..f1f5c079433 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp @@ -71,7 +71,7 @@ public: // Compilation entry point for methods virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive); - void compile_method(methodHandle target, int entry_bci, JVMCIEnv* env); + void compile_method(const methodHandle& target, int entry_bci, JVMCIEnv* env); virtual bool is_trivial(Method* method); diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp index bc20b2a7354..220e8d4d80f 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -60,7 +60,7 @@ #define C2V_END } -oop CompilerToVM::get_jvmci_method(methodHandle method, TRAPS) { +oop CompilerToVM::get_jvmci_method(const methodHandle& method, TRAPS) { if (method() != NULL) { JavaValue result(T_OBJECT); JavaCallArguments args; diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp index e05033bf893..cbcf27b4738 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp @@ -94,7 +94,7 @@ public: return (MethodData*) (address) metaspaceMethodData; } - static oop get_jvmci_method(methodHandle method, TRAPS); + static oop get_jvmci_method(const methodHandle& method, TRAPS); static oop get_jvmci_type(KlassHandle klass, TRAPS); diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp index 039049bf07f..8181949e886 100644 --- a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp @@ -82,8 +82,8 @@ bool JVMCIEnv::check_klass_accessibility(KlassHandle accessing_klass, KlassHandl } // ------------------------------------------------------------------ -KlassHandle JVMCIEnv::get_klass_by_name_impl(KlassHandle& accessing_klass, - constantPoolHandle& cpool, +KlassHandle JVMCIEnv::get_klass_by_name_impl(KlassHandle accessing_klass, + const constantPoolHandle& cpool, Symbol* sym, bool require_local) { JVMCI_EXCEPTION_CONTEXT; @@ -161,7 +161,7 @@ KlassHandle JVMCIEnv::get_klass_by_name_impl(KlassHandle& accessing_klass, } // ------------------------------------------------------------------ -KlassHandle JVMCIEnv::get_klass_by_name(KlassHandle& accessing_klass, +KlassHandle JVMCIEnv::get_klass_by_name(KlassHandle accessing_klass, Symbol* klass_name, bool require_local) { ResourceMark rm; @@ -174,10 +174,10 @@ KlassHandle JVMCIEnv::get_klass_by_name(KlassHandle& accessing_klass, // ------------------------------------------------------------------ // Implementation of get_klass_by_index. -KlassHandle JVMCIEnv::get_klass_by_index_impl(constantPoolHandle& cpool, +KlassHandle JVMCIEnv::get_klass_by_index_impl(const constantPoolHandle& cpool, int index, bool& is_accessible, - KlassHandle& accessor) { + KlassHandle accessor) { JVMCI_EXCEPTION_CONTEXT; KlassHandle klass (THREAD, ConstantPool::klass_at_if_loaded(cpool, index)); Symbol* klass_name = NULL; @@ -215,10 +215,10 @@ KlassHandle JVMCIEnv::get_klass_by_index_impl(constantPoolHandle& cpool, // ------------------------------------------------------------------ // Get a klass from the constant pool. -KlassHandle JVMCIEnv::get_klass_by_index(constantPoolHandle& cpool, +KlassHandle JVMCIEnv::get_klass_by_index(const constantPoolHandle& cpool, int index, bool& is_accessible, - KlassHandle& accessor) { + KlassHandle accessor) { ResourceMark rm; KlassHandle result = get_klass_by_index_impl(cpool, index, is_accessible, accessor); return result; @@ -229,7 +229,7 @@ KlassHandle JVMCIEnv::get_klass_by_index(constantPoolHandle& cpool, // // Implementation note: the results of field lookups are cached // in the accessor klass. -void JVMCIEnv::get_field_by_index_impl(instanceKlassHandle& klass, fieldDescriptor& field_desc, +void JVMCIEnv::get_field_by_index_impl(instanceKlassHandle klass, fieldDescriptor& field_desc, int index) { JVMCI_EXCEPTION_CONTEXT; @@ -270,7 +270,7 @@ void JVMCIEnv::get_field_by_index_impl(instanceKlassHandle& klass, fieldDescript // ------------------------------------------------------------------ // Get a field by index from a klass's constant pool. -void JVMCIEnv::get_field_by_index(instanceKlassHandle& accessor, fieldDescriptor& fd, int index) { +void JVMCIEnv::get_field_by_index(instanceKlassHandle accessor, fieldDescriptor& fd, int index) { ResourceMark rm; return get_field_by_index_impl(accessor, fd, index); } @@ -278,8 +278,8 @@ void JVMCIEnv::get_field_by_index(instanceKlassHandle& accessor, fieldDescriptor // ------------------------------------------------------------------ // Perform an appropriate method lookup based on accessor, holder, // name, signature, and bytecode. -methodHandle JVMCIEnv::lookup_method(instanceKlassHandle& h_accessor, - instanceKlassHandle& h_holder, +methodHandle JVMCIEnv::lookup_method(instanceKlassHandle h_accessor, + instanceKlassHandle h_holder, Symbol* name, Symbol* sig, Bytecodes::Code bc) { @@ -312,9 +312,9 @@ methodHandle JVMCIEnv::lookup_method(instanceKlassHandle& h_accessor, // ------------------------------------------------------------------ -methodHandle JVMCIEnv::get_method_by_index_impl(constantPoolHandle& cpool, +methodHandle JVMCIEnv::get_method_by_index_impl(const constantPoolHandle& cpool, int index, Bytecodes::Code bc, - instanceKlassHandle& accessor) { + instanceKlassHandle accessor) { if (bc == Bytecodes::_invokedynamic) { ConstantPoolCacheEntry* cpce = cpool->invokedynamic_cp_cache_entry_at(index); bool is_resolved = !cpce->is_f1_null(); @@ -379,7 +379,7 @@ methodHandle JVMCIEnv::get_method_by_index_impl(constantPoolHandle& cpool, } // ------------------------------------------------------------------ -instanceKlassHandle JVMCIEnv::get_instance_klass_for_declared_method_holder(KlassHandle& method_holder) { +instanceKlassHandle JVMCIEnv::get_instance_klass_for_declared_method_holder(KlassHandle method_holder) { // For the case of .clone(), the method holder can be an ArrayKlass* // instead of an InstanceKlass*. For that case simply pretend that the // declared holder is Object.clone since that's where the call will bottom out. @@ -395,9 +395,9 @@ instanceKlassHandle JVMCIEnv::get_instance_klass_for_declared_method_holder(Klas // ------------------------------------------------------------------ -methodHandle JVMCIEnv::get_method_by_index(constantPoolHandle& cpool, +methodHandle JVMCIEnv::get_method_by_index(const constantPoolHandle& cpool, int index, Bytecodes::Code bc, - instanceKlassHandle& accessor) { + instanceKlassHandle accessor) { ResourceMark rm; return get_method_by_index_impl(cpool, index, bc, accessor); } @@ -452,7 +452,7 @@ JVMCIEnv::CodeInstallResult JVMCIEnv::check_for_system_dictionary_modification(D // ------------------------------------------------------------------ JVMCIEnv::CodeInstallResult JVMCIEnv::register_method( - methodHandle& method, + const methodHandle& method, nmethod*& nm, int entry_bci, CodeOffsets* offsets, diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp index db88196310a..2ddefacbf26 100644 --- a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp @@ -78,20 +78,20 @@ public: // The CI treats a klass as loaded if it is consistently defined in // another loader, even if it hasn't yet been loaded in all loaders // that could potentially see it via delegation. - static KlassHandle get_klass_by_name(KlassHandle& accessing_klass, + static KlassHandle get_klass_by_name(KlassHandle accessing_klass, Symbol* klass_name, bool require_local); // Constant pool access. - static KlassHandle get_klass_by_index(constantPoolHandle& cpool, + static KlassHandle get_klass_by_index(const constantPoolHandle& cpool, int klass_index, bool& is_accessible, - KlassHandle& loading_klass); - static void get_field_by_index(instanceKlassHandle& loading_klass, fieldDescriptor& fd, + KlassHandle loading_klass); + static void get_field_by_index(instanceKlassHandle loading_klass, fieldDescriptor& fd, int field_index); - static methodHandle get_method_by_index(constantPoolHandle& cpool, + static methodHandle get_method_by_index(const constantPoolHandle& cpool, int method_index, Bytecodes::Code bc, - instanceKlassHandle& loading_klass); + instanceKlassHandle loading_klass); JVMCIEnv(CompileTask* task, int system_dictionary_modification_counter); @@ -105,24 +105,24 @@ private: bool _jvmti_can_post_on_exceptions; // Implementation methods for loading and constant pool access. - static KlassHandle get_klass_by_name_impl(KlassHandle& accessing_klass, - constantPoolHandle& cpool, + static KlassHandle get_klass_by_name_impl(KlassHandle accessing_klass, + const constantPoolHandle& cpool, Symbol* klass_name, bool require_local); - static KlassHandle get_klass_by_index_impl(constantPoolHandle& cpool, + static KlassHandle get_klass_by_index_impl(const constantPoolHandle& cpool, int klass_index, bool& is_accessible, - KlassHandle& loading_klass); - static void get_field_by_index_impl(instanceKlassHandle& loading_klass, fieldDescriptor& fd, + KlassHandle loading_klass); + static void get_field_by_index_impl(instanceKlassHandle loading_klass, fieldDescriptor& fd, int field_index); - static methodHandle get_method_by_index_impl(constantPoolHandle& cpool, + static methodHandle get_method_by_index_impl(const constantPoolHandle& cpool, int method_index, Bytecodes::Code bc, - instanceKlassHandle& loading_klass); + instanceKlassHandle loading_klass); // Helper methods static bool check_klass_accessibility(KlassHandle accessing_klass, KlassHandle resolved_klass); - static methodHandle lookup_method(instanceKlassHandle& accessor, - instanceKlassHandle& holder, + static methodHandle lookup_method(instanceKlassHandle accessor, + instanceKlassHandle holder, Symbol* name, Symbol* sig, Bytecodes::Code bc); @@ -142,7 +142,7 @@ public: // Register the result of a compilation. static JVMCIEnv::CodeInstallResult register_method( - methodHandle& target, + const methodHandle& target, nmethod*& nm, int entry_bci, CodeOffsets* offsets, @@ -166,7 +166,7 @@ public: // InstanceKlass*. This is needed since the holder of a method in // the bytecodes could be an array type. Basically this converts // array types into java/lang/Object and other types stay as they are. - static instanceKlassHandle get_instance_klass_for_declared_method_holder(KlassHandle& klass); + static instanceKlassHandle get_instance_klass_for_declared_method_holder(KlassHandle klass); }; #endif // SHARE_VM_JVMCI_JVMCIENV_HPP diff --git a/hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp index 966e4fd35ba..1a8f7d1cb2b 100644 --- a/hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp @@ -315,10 +315,10 @@ class name : AllStatic { #define FIELD(name, type, accessor, cast) \ static int _##name##_offset; \ static type name(oop obj) { check(obj, #name, _##name##_offset); return cast obj->accessor(_##name##_offset); } \ - static type name(Handle& obj) { check(obj(), #name, _##name##_offset); return cast obj->accessor(_##name##_offset); } \ + static type name(Handle obj) { check(obj(), #name, _##name##_offset); return cast obj->accessor(_##name##_offset); } \ static type name(jobject obj) { check(JNIHandles::resolve(obj), #name, _##name##_offset); return cast JNIHandles::resolve(obj)->accessor(_##name##_offset); } \ static void set_##name(oop obj, type x) { check(obj, #name, _##name##_offset); obj->accessor##_put(_##name##_offset, x); } \ - static void set_##name(Handle& obj, type x) { check(obj(), #name, _##name##_offset); obj->accessor##_put(_##name##_offset, x); } \ + static void set_##name(Handle obj, type x) { check(obj(), #name, _##name##_offset); obj->accessor##_put(_##name##_offset, x); } \ static void set_##name(jobject obj, type x) { check(JNIHandles::resolve(obj), #name, _##name##_offset); JNIHandles::resolve(obj)->accessor##_put(_##name##_offset, x); } #define EMPTY_CAST From 323c22ecfa293fc0c27663a7fc866bc733310129 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Tue, 10 Nov 2015 11:49:42 -1000 Subject: [PATCH 019/260] 8142435: [JVMCI] restore missing InstalledCode.version increment Reviewed-by: twisti --- hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp index 220e8d4d80f..1950f559f8f 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -690,6 +690,7 @@ C2V_VMENTRY(jint, installCode, (JNIEnv *jniEnv, jobject, jobject target, jobject assert(installed_code_handle->is_a(InstalledCode::klass()), "wrong type"); CompilerToVM::invalidate_installed_code(installed_code_handle, CHECK_0); InstalledCode::set_address(installed_code_handle, (jlong) cb); + InstalledCode::set_version(installed_code_handle, InstalledCode::version(installed_code_handle) + 1); if (cb->is_nmethod()) { InstalledCode::set_entryPoint(installed_code_handle, (jlong) cb->as_nmethod_or_null()->verified_entry_point()); } else { From e73df9dee629fcd960cfe45c791cd496f9c843d7 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Tue, 10 Nov 2015 11:50:20 -1000 Subject: [PATCH 020/260] 8142436: [JVMCI] fix management of nmethod::_installed_code field Reviewed-by: twisti --- hotspot/src/share/vm/code/nmethod.cpp | 39 ++++++++------------------- hotspot/src/share/vm/code/nmethod.hpp | 2 +- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index bdf7bd8fb19..c5eda7de5be 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -1823,9 +1823,7 @@ void nmethod::do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred) if (_jvmci_installed_code != NULL) { if (_jvmci_installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(_jvmci_installed_code)) { if (!is_alive->do_object_b(_jvmci_installed_code)) { - bs->write_ref_nmethod_pre(&_jvmci_installed_code, this); - _jvmci_installed_code = NULL; - bs->write_ref_nmethod_post(&_jvmci_installed_code, this); + clear_jvmci_installed_code(); } } else { if (can_unload(is_alive, (oop*)&_jvmci_installed_code, unloading_occurred)) { @@ -1926,27 +1924,6 @@ bool nmethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_ unloading_occurred = true; } -#if INCLUDE_JVMCI - // Follow JVMCI method - if (_jvmci_installed_code != NULL) { - if (_jvmci_installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(_jvmci_installed_code)) { - if (!is_alive->do_object_b(_jvmci_installed_code)) { - _jvmci_installed_code = NULL; - } - } else { - if (can_unload(is_alive, (oop*)&_jvmci_installed_code, unloading_occurred)) { - return false; - } - } - } - - if (_speculation_log != NULL) { - if (!is_alive->do_object_b(_speculation_log)) { - _speculation_log = NULL; - } - } -#endif - // Exception cache clean_exception_cache(is_alive); @@ -2010,9 +1987,7 @@ bool nmethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unloading_ if (_jvmci_installed_code != NULL) { if (_jvmci_installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(_jvmci_installed_code)) { if (!is_alive->do_object_b(_jvmci_installed_code)) { - bs->write_ref_nmethod_pre(&_jvmci_installed_code, this); - _jvmci_installed_code = NULL; - bs->write_ref_nmethod_post(&_jvmci_installed_code, this); + clear_jvmci_installed_code(); } } else { if (can_unload(is_alive, (oop*)&_jvmci_installed_code, unloading_occurred)) { @@ -3377,6 +3352,14 @@ void nmethod::print_statistics() { #endif // !PRODUCT #if INCLUDE_JVMCI +void nmethod::clear_jvmci_installed_code() { + // This must be done carefully to maintain nmethod remembered sets properly + BarrierSet* bs = Universe::heap()->barrier_set(); + bs->write_ref_nmethod_pre(&_jvmci_installed_code, this); + _jvmci_installed_code = NULL; + bs->write_ref_nmethod_post(&_jvmci_installed_code, this); +} + void nmethod::maybe_invalidate_installed_code() { if (_jvmci_installed_code != NULL) { if (!is_alive()) { @@ -3386,7 +3369,7 @@ void nmethod::maybe_invalidate_installed_code() { // might want to invalidate all existing activations. InstalledCode::set_address(_jvmci_installed_code, 0); InstalledCode::set_entryPoint(_jvmci_installed_code, 0); - _jvmci_installed_code = NULL; + clear_jvmci_installed_code(); } else if (is_not_entrant()) { InstalledCode::set_entryPoint(_jvmci_installed_code, 0); } diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 6d4f19e93d3..41b25b4bdc0 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -602,7 +602,7 @@ public: #if INCLUDE_JVMCI oop jvmci_installed_code() { return _jvmci_installed_code ; } char* jvmci_installed_code_name(char* buf, size_t buflen); - void set_jvmci_installed_code(oop installed_code) { _jvmci_installed_code = installed_code; } + void clear_jvmci_installed_code(); void maybe_invalidate_installed_code(); oop speculation_log() { return _speculation_log ; } void set_speculation_log(oop speculation_log) { _speculation_log = speculation_log; } From 6ed8c235818d6ad458585187bec5d728d77caec8 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Tue, 10 Nov 2015 21:36:35 -0800 Subject: [PATCH 021/260] 8141624: Limit calculation of pre loop during super word optimization is wrong Reviewed-by: vlivanov, kvn --- hotspot/src/share/vm/opto/superword.cpp | 2 +- .../loopopts/superword/TestBestAlign.java | 56 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 hotspot/test/compiler/loopopts/superword/TestBestAlign.java diff --git a/hotspot/src/share/vm/opto/superword.cpp b/hotspot/src/share/vm/opto/superword.cpp index 0d07effbfd3..2d1e2a4a0c3 100644 --- a/hotspot/src/share/vm/opto/superword.cpp +++ b/hotspot/src/share/vm/opto/superword.cpp @@ -558,7 +558,7 @@ void SuperWord::find_adjacent_refs() { assert(!same_velt_type(s, mem_ref), "sanity"); memops.push(s); } - MemNode* best_align_to_mem_ref = find_align_to_ref(memops); + best_align_to_mem_ref = find_align_to_ref(memops); if (best_align_to_mem_ref == NULL) { NOT_PRODUCT(if (TraceSuperWord) tty->print_cr("SuperWord::find_adjacent_refs(): best_align_to_mem_ref == NULL");) break; diff --git a/hotspot/test/compiler/loopopts/superword/TestBestAlign.java b/hotspot/test/compiler/loopopts/superword/TestBestAlign.java new file mode 100644 index 00000000000..9063798e63a --- /dev/null +++ b/hotspot/test/compiler/loopopts/superword/TestBestAlign.java @@ -0,0 +1,56 @@ +/* + * Copyright 2015 SAP AG. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8141624 + * @summary Limit calculation of pre loop during super word optimization is wrong + * @run main/othervm TestBestAlign + * @author gunter.haug@sap.com + */ + +public class TestBestAlign { + + static final int initVal = -1; + static int intArray []; + static boolean boolArray[]; + static int limit; + static public void clear() { + for (int i = 0; i < limit; i++) { + boolArray[1] = true; + intArray[i] = initVal; + boolArray[2] = true; + } + } + + public static void main(String argv[]) throws Exception { + limit = 64; + boolArray = new boolean[8]; + intArray = new int[limit + 4]; + for (int i = 0; i < 10000000; ++i) { + if(i % 1000000 == 0) + System.out.println(i); + clear(); + } + } +} From ac09d8a13514d291e097fa569d836d957c6c9ef3 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 11 Nov 2015 01:27:36 +0300 Subject: [PATCH 022/260] 8140650: Method::is_accessor should cover getters and setters for all types Reviewed-by: vlivanov, coleenp, sgehwolf --- .../src/cpu/zero/vm/cppInterpreter_zero.cpp | 5 +- hotspot/src/share/vm/ci/ciMethod.cpp | 2 + hotspot/src/share/vm/ci/ciMethod.hpp | 2 + .../src/share/vm/interpreter/interpreter.cpp | 5 +- hotspot/src/share/vm/oops/method.cpp | 39 ++++- hotspot/src/share/vm/oops/method.hpp | 6 + hotspot/src/share/vm/opto/callnode.cpp | 2 +- .../compiler/inlining/InlineAccessors.java | 141 ++++++++++++++++++ 8 files changed, 196 insertions(+), 6 deletions(-) create mode 100644 hotspot/test/compiler/inlining/InlineAccessors.java diff --git a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp index 78dad699f97..02497845c28 100644 --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp @@ -497,12 +497,15 @@ int CppInterpreter::accessor_entry(Method* method, intptr_t UNUSED, TRAPS) { // 1: getfield // 2: index // 3: index - // 4: ireturn/areturn + // 4: ireturn/areturn/freturn/lreturn/dreturn // NB this is not raw bytecode: index is in machine order u1 *code = method->code_base(); assert(code[0] == Bytecodes::_aload_0 && code[1] == Bytecodes::_getfield && (code[4] == Bytecodes::_ireturn || + code[4] == Bytecodes::_freturn || + code[4] == Bytecodes::_lreturn || + code[4] == Bytecodes::_dreturn || code[4] == Bytecodes::_areturn), "should do"); u2 index = Bytes::get_native_u2(&code[2]); diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index 3014c7f4a0b..cd79debfc38 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -1262,6 +1262,8 @@ bool ciMethod::is_empty_method() const { FETCH_FLAG_FROM_VM(is_empty_met bool ciMethod::is_vanilla_constructor() const { FETCH_FLAG_FROM_VM(is_vanilla_constructor); } bool ciMethod::has_loops () const { FETCH_FLAG_FROM_VM(has_loops); } bool ciMethod::has_jsrs () const { FETCH_FLAG_FROM_VM(has_jsrs); } +bool ciMethod::is_getter () const { FETCH_FLAG_FROM_VM(is_getter); } +bool ciMethod::is_setter () const { FETCH_FLAG_FROM_VM(is_setter); } bool ciMethod::is_accessor () const { FETCH_FLAG_FROM_VM(is_accessor); } bool ciMethod::is_initializer () const { FETCH_FLAG_FROM_VM(is_initializer); } diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index 743a16463ee..5b19e95d39f 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -311,6 +311,8 @@ class ciMethod : public ciMetadata { bool is_final_method() const { return is_final() || holder()->is_final(); } bool has_loops () const; bool has_jsrs () const; + bool is_getter () const; + bool is_setter () const; bool is_accessor () const; bool is_initializer () const; bool can_be_statically_bound() const { return _can_be_statically_bound; } diff --git a/hotspot/src/share/vm/interpreter/interpreter.cpp b/hotspot/src/share/vm/interpreter/interpreter.cpp index eada76cb3bb..08495d3a8f8 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.cpp +++ b/hotspot/src/share/vm/interpreter/interpreter.cpp @@ -300,7 +300,10 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(methodHandle m) } // Accessor method? - if (m->is_accessor()) { + if (m->is_getter()) { + // TODO: We should have used ::is_accessor above, but fast accessors in Zero expect only getters. + // See CppInterpreter::accessor_entry in cppInterpreter_zero.cpp. This should be fixed in Zero, + // then the call above updated to ::is_accessor assert(m->size_of_parameters() == 1, "fast code for accessors assumes parameter size = 1"); return accessor; } diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 192769f7226..f6440484b21 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -582,12 +582,45 @@ bool Method::can_be_statically_bound() const { } bool Method::is_accessor() const { + return is_getter() || is_setter(); +} + +bool Method::is_getter() const { if (code_size() != 5) return false; if (size_of_parameters() != 1) return false; - if (java_code_at(0) != Bytecodes::_aload_0 ) return false; + if (java_code_at(0) != Bytecodes::_aload_0) return false; if (java_code_at(1) != Bytecodes::_getfield) return false; - if (java_code_at(4) != Bytecodes::_areturn && - java_code_at(4) != Bytecodes::_ireturn ) return false; + switch (java_code_at(4)) { + case Bytecodes::_ireturn: + case Bytecodes::_lreturn: + case Bytecodes::_freturn: + case Bytecodes::_dreturn: + case Bytecodes::_areturn: + break; + default: + return false; + } + return true; +} + +bool Method::is_setter() const { + if (code_size() != 6) return false; + if (java_code_at(0) != Bytecodes::_aload_0) return false; + switch (java_code_at(1)) { + case Bytecodes::_iload_1: + case Bytecodes::_aload_1: + case Bytecodes::_fload_1: + if (size_of_parameters() != 2) return false; + break; + case Bytecodes::_dload_1: + case Bytecodes::_lload_1: + if (size_of_parameters() != 3) return false; + break; + default: + return false; + } + if (java_code_at(2) != Bytecodes::_putfield) return false; + if (java_code_at(5) != Bytecodes::_return) return false; return true; } diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index f1a2e916f7d..003b596f74b 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -595,6 +595,12 @@ class Method : public Metadata { // returns true if the method is an accessor function (setter/getter). bool is_accessor() const; + // returns true if the method is a getter + bool is_getter() const; + + // returns true if the method is a setter + bool is_setter() const; + // returns true if the method does nothing but return a constant of primitive type bool is_constant_getter() const; diff --git a/hotspot/src/share/vm/opto/callnode.cpp b/hotspot/src/share/vm/opto/callnode.cpp index 56fd109f7a5..c82a149d444 100644 --- a/hotspot/src/share/vm/opto/callnode.cpp +++ b/hotspot/src/share/vm/opto/callnode.cpp @@ -778,7 +778,7 @@ bool CallNode::may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase) { } if (is_CallJava() && as_CallJava()->method() != NULL) { ciMethod* meth = as_CallJava()->method(); - if (meth->is_accessor()) { + if (meth->is_getter()) { return false; } // May modify (by reflection) if an boxing object is passed diff --git a/hotspot/test/compiler/inlining/InlineAccessors.java b/hotspot/test/compiler/inlining/InlineAccessors.java new file mode 100644 index 00000000000..60f8986a829 --- /dev/null +++ b/hotspot/test/compiler/inlining/InlineAccessors.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +/** + * @test + * @bug 8140650 + * @summary Method::is_accessor should cover getters and setters for all types + * @library /testlibrary + * @run main/othervm InlineAccessors + */ +import java.lang.invoke.*; +import jdk.test.lib.*; +import static jdk.test.lib.Asserts.*; + +public class InlineAccessors { + public static void main(String[] args) throws Exception { + // try some sanity checks first + doTest(); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", "-showversion", + "-server", "-XX:-TieredCompilation", "-Xbatch", "-Xcomp", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "InlineAccessors$Launcher"); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + // The test is applicable only to C2 (present in Server VM). + if (analyzer.getStderr().contains("Server VM")) { + analyzer.shouldContain("InlineAccessors::setBool (6 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::setByte (6 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::setChar (6 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::setShort (6 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::setInt (6 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::setFloat (6 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::setLong (6 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::setDouble (6 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::setObject (6 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::setArray (6 bytes) accessor"); + + analyzer.shouldContain("InlineAccessors::getBool (5 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::getByte (5 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::getChar (5 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::getShort (5 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::getInt (5 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::getFloat (5 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::getLong (5 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::getDouble (5 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::getObject (5 bytes) accessor"); + analyzer.shouldContain("InlineAccessors::getArray (5 bytes) accessor"); + } + } + + boolean bool; + byte b; + char c; + short s; + int i; + float f; + long l; + double d; + Object o; + Object[] a; + + public void setBool(boolean v) { bool = v; } + public void setByte(byte v) { b = v; } + public void setChar(char v) { c = v; } + public void setShort(short v) { s = v; } + public void setInt(int v) { i = v; } + public void setFloat(float v) { f = v; } + public void setLong(long v) { l = v; } + public void setDouble(double v) { d = v; } + public void setObject(Object v) { o = v; } + public void setArray(Object[] v) { a = v; } + + public boolean getBool() { return bool; } + public byte getByte() { return b; } + public char getChar() { return c; } + public short getShort() { return s; } + public int getInt() { return i; } + public float getFloat() { return f; } + public long getLong() { return l; } + public double getDouble() { return d; } + public Object getObject() { return o; } + public Object[] getArray() { return a; } + + static void doTest() { + InlineAccessors o = new InlineAccessors(); + o.setBool(false); + o.setByte((byte)0); + o.setChar('a'); + o.setShort((short)0); + o.setInt(0); + o.setFloat(0F); + o.setLong(0L); + o.setDouble(0D); + o.setObject(new Object()); + o.setArray(new Object[1]); + + o.getBool(); + o.getByte(); + o.getChar(); + o.getShort(); + o.getInt(); + o.getFloat(); + o.getLong(); + o.getDouble(); + o.getObject(); + o.getArray(); + } + + static class Launcher { + public static void main(String[] args) throws Exception { + for (int c = 0; c < 20_000; c++) { + doTest(); + } + } + } +} From bace7d99aa778fe6ae71d90fbc249fa93166d1ca Mon Sep 17 00:00:00 2001 From: Gunter Haug Date: Tue, 10 Nov 2015 11:01:28 +0100 Subject: [PATCH 023/260] 8142314: Bug in C1 ControlFlowOptimizer::delete_unnecessary_jumps with bytecode profiling Reviewed-by: kvn --- hotspot/src/share/vm/c1/c1_LIR.cpp | 2 +- hotspot/src/share/vm/c1/c1_LinearScan.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/c1/c1_LIR.cpp b/hotspot/src/share/vm/c1/c1_LIR.cpp index 9247a1c6eb5..0e967babd3e 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.cpp +++ b/hotspot/src/share/vm/c1/c1_LIR.cpp @@ -2004,7 +2004,7 @@ void LIR_OpRoundFP::print_instr(outputStream* out) const { // LIR_Op2 void LIR_Op2::print_instr(outputStream* out) const { - if (code() == lir_cmove) { + if (code() == lir_cmove || code() == lir_cmp) { print_condition(out, condition()); out->print(" "); } in_opr1()->print(out); out->print(" "); diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.cpp b/hotspot/src/share/vm/c1/c1_LinearScan.cpp index c5e4dc44012..c5682ceabcf 100644 --- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp +++ b/hotspot/src/share/vm/c1/c1_LinearScan.cpp @@ -6233,9 +6233,19 @@ void ControlFlowOptimizer::delete_unnecessary_jumps(BlockList* code) { if (prev_branch->stub() == NULL) { LIR_Op2* prev_cmp = NULL; + // There might be a cmove inserted for profiling which depends on the same + // compare. If we change the condition of the respective compare, we have + // to take care of this cmove as well. + LIR_Op2* prev_cmove = NULL; for(int j = instructions->length() - 3; j >= 0 && prev_cmp == NULL; j--) { prev_op = instructions->at(j); + // check for the cmove + if (prev_op->code() == lir_cmove) { + assert(prev_op->as_Op2() != NULL, "cmove must be of type LIR_Op2"); + prev_cmove = (LIR_Op2*)prev_op; + assert(prev_branch->cond() == prev_cmove->condition(), "should be the same"); + } if (prev_op->code() == lir_cmp) { assert(prev_op->as_Op2() != NULL, "branch must be of type LIR_Op2"); prev_cmp = (LIR_Op2*)prev_op; @@ -6252,6 +6262,13 @@ void ControlFlowOptimizer::delete_unnecessary_jumps(BlockList* code) { prev_branch->negate_cond(); prev_cmp->set_condition(prev_branch->cond()); instructions->truncate(instructions->length() - 1); + // if we do change the condition, we have to change the cmove as well + if (prev_cmove != NULL) { + prev_cmove->set_condition(prev_branch->cond()); + LIR_Opr t = prev_cmove->in_opr1(); + prev_cmove->set_in_opr1(prev_cmove->in_opr2()); + prev_cmove->set_in_opr2(t); + } } } } From e0d743ff05a958a65504b33bf6a3a77bb02285ee Mon Sep 17 00:00:00 2001 From: Tatiana Pivovarova Date: Wed, 11 Nov 2015 15:04:15 +0300 Subject: [PATCH 024/260] 8138810: rework tests for CompilerToVM::allocateCompiledId Reviewed-by: twisti --- .../compilerToVM/AllocateCompileIdTest.java | 66 ++++++++----------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java b/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java index 0e97f5e6019..17fe5a57e40 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java @@ -34,7 +34,6 @@ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. * -XX:-BackgroundCompilation - -XX:+LogCompilation * compiler.jvmci.compilerToVM.AllocateCompileIdTest */ @@ -45,22 +44,21 @@ import compiler.jvmci.common.CTVMUtilities; import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.HashSet; +import java.util.stream.Collectors; +import java.util.stream.Stream; -import compiler.jvmci.common.testcases.TestCase; import jdk.vm.ci.hotspot.CompilerToVMHelper; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; import jdk.test.lib.Asserts; import jdk.test.lib.Pair; import jdk.test.lib.Utils; -import sun.hotspot.WhiteBox; import sun.hotspot.code.NMethod; public class AllocateCompileIdTest { + private static final int SOME_REPEAT_VALUE = 5; private final HashSet ids = new HashSet<>(); public static void main(String[] args) { @@ -69,7 +67,6 @@ public class AllocateCompileIdTest { createTestCasesIncorrectBci().forEach(test::runSanityIncorrectTest); } - private static List createTestCasesCorrectBci() { List result = new ArrayList<>(); try { @@ -84,29 +81,29 @@ public class AllocateCompileIdTest { return result; } - private static List>> createTestCasesIncorrectBci() { List>> result = new ArrayList<>(); - try { Class aClass = DummyClass.class; Object receiver = new DummyClass(); Method method = aClass.getMethod("dummyInstanceFunction"); // greater than bytecode.length - int[] bcis = new int[] {30, 50, 200}; - for (int bci : bcis) { - result.add(new Pair<>( - new CompileCodeTestCase(receiver, method, bci), - IllegalArgumentException.class)); - } - bcis = new int[] {-4, -50, -200}; - for (int bci : bcis) { - result.add(new Pair<>( - new CompileCodeTestCase(receiver, method, bci), - IllegalArgumentException.class)); - } + byte[] bytecode = CompilerToVMHelper.getBytecode(CTVMUtilities + .getResolvedMethod(method)); + Stream.of( + // greater than bytecode.length + bytecode.length + 4, + bytecode.length + 50, + bytecode.length + 200, + // negative cases + -4, -50, -200) + .map(bci -> new Pair>( + new CompileCodeTestCase(receiver, method, bci), + IllegalArgumentException.class)) + .collect(Collectors.toList()); } catch (NoSuchMethodException e) { throw new Error("TEST BUG : " + e.getMessage(), e); } @@ -117,27 +114,20 @@ public class AllocateCompileIdTest { System.out.println(testCase); Executable aMethod = testCase.executable; // to generate ciTypeFlow - System.out.println(testCase.invoke(Utils.getNullValues(aMethod.getParameterTypes()))); + testCase.invoke(Utils.getNullValues(aMethod.getParameterTypes())); int bci = testCase.bci; HotSpotResolvedJavaMethod method = CTVMUtilities .getResolvedMethod(aMethod); - int wbCompileID = getWBCompileID(testCase); - int id = CompilerToVMHelper.allocateCompileId(method, bci); - Asserts.assertNE(id, 0, testCase + " : zero compile id"); - - if (wbCompileID > 0) { + for (int i = 0; i < SOME_REPEAT_VALUE; ++i) { + int wbCompileID = getWBCompileID(testCase); + int id = CompilerToVMHelper.allocateCompileId(method, bci); + Asserts.assertNE(id, 0, testCase + " : zero compile id"); Asserts.assertGT(id, wbCompileID, testCase + " : allocated 'compile id' not greater than existed"); - if (!ids.add(wbCompileID)) { - throw new AssertionError(String.format( - "%s : vm compilation allocated existed id -- %d", - testCase, id)); - } - } - if (!ids.add(id)) { - throw new AssertionError(String.format( - "%s : allocateCompileId returned existed id %d", - testCase, id)); + Asserts.assertTrue(ids.add(wbCompileID), testCase + + " : vm compilation allocated existing id " + id); + Asserts.assertTrue(ids.add(id), testCase + + " : allocateCompileId returned existing id " + id); } } @@ -156,8 +146,8 @@ public class AllocateCompileIdTest { private int getWBCompileID(CompileCodeTestCase testCase) { NMethod nm = testCase.deoptimizeAndCompile(); - if (nm == null) { - throw new Error("[TEST BUG] cannot compile method " + testCase); + if (nm == null || nm.compile_id <= 0) { + throw new Error("TEST BUG : cannot compile method " + testCase); } return nm.compile_id; } From 163e0435dca2724ea8b40feae0c3f8282daf007b Mon Sep 17 00:00:00 2001 From: Tatiana Pivovarova Date: Tue, 10 Nov 2015 21:09:49 +0300 Subject: [PATCH 025/260] 8139388: [TESTBUG] JVMCI test failed with RuntimeException profiling info wasn't changed after 100 invocations (assert failed: BaseProfilingInfo<> != BaseProfilingInfo<>) Reviewed-by: twisti --- .../jvmci/compilerToVM/ReprofileTest.java | 21 ++++++++----------- .../whitebox/CompilerWhiteBoxTest.java | 4 +--- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java index 0f7c1892918..fd198dff114 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java @@ -45,18 +45,15 @@ import compiler.jvmci.common.CTVMUtilities; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; -import java.util.Random; + +import compiler.whitebox.CompilerWhiteBoxTest; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; import jdk.vm.ci.hotspot.CompilerToVMHelper; import jdk.vm.ci.meta.ProfilingInfo; import jdk.test.lib.Asserts; -import jdk.test.lib.Utils; -import sun.hotspot.WhiteBox; public class ReprofileTest { - private static final WhiteBox WB = WhiteBox.getWhiteBox(); - public static void main(String[] args) { List testCases = createTestCases(); testCases.forEach(ReprofileTest::runSanityTest); @@ -67,10 +64,10 @@ public class ReprofileTest { try { Class aClass = DummyClass.class; - testCases.add(aClass.getMethod("withLoop")); + testCases.add(aClass.getMethod("dummyInstanceFunction")); aClass = DummyClass.class; - testCases.add(aClass.getDeclaredMethod("dummyFunction")); + testCases.add(aClass.getMethod("dummyFunction")); } catch (NoSuchMethodException e) { throw new Error("TEST BUG " + e.getMessage(), e); } @@ -78,17 +75,17 @@ public class ReprofileTest { } private static void runSanityTest(Method aMethod) { + System.out.println(aMethod); HotSpotResolvedJavaMethod method = CTVMUtilities .getResolvedMethod(aMethod); ProfilingInfo startProfile = method.getProfilingInfo(); Asserts.assertFalse(startProfile.isMature(), aMethod - + " : profiling info is mature in the begging"); + + " : profiling info is mature in the beginning"); - long compileThreshold = (Long) WB.getVMFlag("CompileThreshold"); // make interpreter to profile this method try { Object obj = aMethod.getDeclaringClass().newInstance(); - for (long i = 0; i < compileThreshold; i++) { + for (long i = 0; i < CompilerWhiteBoxTest.THRESHOLD; i++) { aMethod.invoke(obj); } } catch (ReflectiveOperationException e) { @@ -99,10 +96,10 @@ public class ReprofileTest { Asserts.assertNE(startProfile.toString(), compProfile.toString(), String.format("%s : profiling info wasn't changed after " + "%d invocations", - aMethod, compileThreshold)); + aMethod, CompilerWhiteBoxTest.THRESHOLD)); Asserts.assertTrue(compProfile.isMature(), String.format("%s is not mature after %d invocations", - aMethod, compileThreshold)); + aMethod, CompilerWhiteBoxTest.THRESHOLD)); CompilerToVMHelper.reprofile(method); ProfilingInfo reprofiledProfile = method.getProfilingInfo(); diff --git a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java index e4d28c7642b..269113074e4 100644 --- a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java +++ b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java @@ -24,9 +24,7 @@ package compiler.whitebox; import sun.hotspot.WhiteBox; import sun.hotspot.code.NMethod; -import java.lang.reflect.Constructor; import java.lang.reflect.Executable; -import java.lang.reflect.Method; import java.util.Objects; import java.util.concurrent.Callable; import java.util.function.Function; @@ -70,7 +68,7 @@ public abstract class CompilerWhiteBoxTest { protected static final boolean IS_VERBOSE = System.getProperty("verbose") != null; /** invocation count to trigger compilation */ - protected static final int THRESHOLD; + public static final int THRESHOLD; /** invocation count to trigger OSR compilation */ protected static final long BACKEDGE_THRESHOLD; /** Value of {@code java.vm.info} (interpreted|mixed|comp mode) */ From c4ce43c1ac9df4fcbbfea25d15a53a98b491af63 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Wed, 11 Nov 2015 14:40:38 -1000 Subject: [PATCH 026/260] 8141133: [JVMCI] crash during safepoint deopt if rethrow_exception is set Reviewed-by: twisti --- .../cpu/aarch64/vm/sharedRuntime_aarch64.cpp | 13 +++++ hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp | 13 ++++- .../src/cpu/sparc/vm/sharedRuntime_sparc.cpp | 15 +++++- .../src/cpu/x86/vm/sharedRuntime_x86_32.cpp | 24 ++++++--- .../src/cpu/x86/vm/sharedRuntime_x86_64.cpp | 14 +++++ .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 1 + .../src/share/vm/runtime/deoptimization.cpp | 51 +++++++++++-------- .../src/share/vm/runtime/deoptimization.hpp | 15 +++--- hotspot/src/share/vm/runtime/vmStructs.cpp | 1 + hotspot/src/share/vm/shark/sharkRuntime.cpp | 3 +- 10 files changed, 114 insertions(+), 36 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp index ef7cacae7a9..6b872ce54b6 100644 --- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp @@ -2384,6 +2384,7 @@ void SharedRuntime::generate_deopt_blob() { } #endif // ASSERT __ mov(c_rarg0, rthread); + __ mov(c_rarg1, rcpool); __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info))); __ blrt(rscratch1, 1, 0, 1); __ bind(retaddr); @@ -2397,6 +2398,7 @@ void SharedRuntime::generate_deopt_blob() { // Load UnrollBlock* into rdi __ mov(r5, r0); + __ ldrw(rcpool, Address(r5, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes())); Label noException; __ cmpw(rcpool, Deoptimization::Unpack_exception); // Was exception pending? __ br(Assembler::NE, noException); @@ -2609,6 +2611,7 @@ void SharedRuntime::generate_uncommon_trap_blob() { // n.b. 2 gp args, 0 fp args, integral return type __ mov(c_rarg0, rthread); + __ movw(c_rarg2, (unsigned)Deoptimization::Unpack_uncommon_trap); __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); @@ -2628,6 +2631,16 @@ void SharedRuntime::generate_uncommon_trap_blob() { // move UnrollBlock* into r4 __ mov(r4, r0); +#ifdef ASSERT + { Label L; + __ ldrw(rscratch1, Address(r4, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes())); + __ cmpw(rscratch1, (unsigned)Deoptimization::Unpack_uncommon_trap); + __ br(Assembler::EQ, L); + __ stop("SharedRuntime::generate_deopt_blob: last_Java_fp not cleared"); + __ bind(L); + } +#endif + // Pop all the frames we must move/replace. // // Frame picture (youngest to oldest) diff --git a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index e6853776063..eeb0c1a3b43 100644 --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -2802,7 +2802,7 @@ void SharedRuntime::generate_deopt_blob() { __ set_last_Java_frame(R1_SP, noreg); // With EscapeAnalysis turned on, this call may safepoint! - __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info), R16_thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info), R16_thread, exec_mode_reg); address calls_return_pc = __ last_calls_return_pc(); // Set an oopmap for the call site that describes all our saved registers. oop_maps->add_gc_map(calls_return_pc - start, map); @@ -2815,6 +2815,8 @@ void SharedRuntime::generate_deopt_blob() { // by save_volatile_registers(...). RegisterSaver::restore_result_registers(masm, first_frame_size_in_bytes); + // reload the exec mode from the UnrollBlock (it might have changed) + __ lwz(exec_mode_reg, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes(), unroll_block_reg); // In excp_deopt_mode, restore and clear exception oop which we // stored in the thread during exception entry above. The exception // oop will be the return value of this stub. @@ -2945,8 +2947,9 @@ void SharedRuntime::generate_uncommon_trap_blob() { __ set_last_Java_frame(/*sp*/R1_SP, /*pc*/R11_scratch1); __ mr(klass_index_reg, R3); + __ li(R5, Deoptimization::Unpack_exception); __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap), - R16_thread, klass_index_reg); + R16_thread, klass_index_reg, R5); // Set an oopmap for the call site. oop_maps->add_gc_map(gc_map_pc - start, map); @@ -2966,6 +2969,12 @@ void SharedRuntime::generate_uncommon_trap_blob() { // stack: (caller_of_deoptee, ...). +#ifdef ASSERT + __ lwz(R22_tmp2, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes(), unroll_block_reg); + __ cmpdi(CCR0, R22_tmp2, (unsigned)Deoptimization::Unpack_uncommon_trap); + __ asm_assert_eq("SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap", 0); +#endif + // Allocate new interpreter frame(s) and possibly a c2i adapter // frame. push_skeleton_frames(masm, false/*deopt*/, diff --git a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index 449488b94c9..3cfbf2d659c 100644 --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp @@ -3036,6 +3036,7 @@ void SharedRuntime::generate_deopt_blob() { __ mov((int32_t)Deoptimization::Unpack_reexecute, L0deopt_mode); __ mov(G2_thread, O0); + __ mov(L0deopt_mode, O2); __ call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)); __ delayed()->nop(); oop_maps->add_gc_map( __ offset()-start, map->deep_copy()); @@ -3121,6 +3122,7 @@ void SharedRuntime::generate_deopt_blob() { // do the call by hand so we can get the oopmap __ mov(G2_thread, L7_thread_cache); + __ mov(L0deopt_mode, O1); __ call(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info), relocInfo::runtime_call_type); __ delayed()->mov(G2_thread, O0); @@ -3146,6 +3148,7 @@ void SharedRuntime::generate_deopt_blob() { RegisterSaver::restore_result_registers(masm); + __ ld(O2UnrollBlock, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes(), G4deopt_mode); Label noException; __ cmp_and_br_short(G4deopt_mode, Deoptimization::Unpack_exception, Assembler::notEqual, Assembler::pt, noException); @@ -3269,7 +3272,8 @@ void SharedRuntime::generate_uncommon_trap_blob() { __ save_frame(0); __ set_last_Java_frame(SP, noreg); __ mov(I0, O2klass_index); - __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap), G2_thread, O2klass_index); + __ mov(Deoptimization::Unpack_uncommon_trap, O3); // exec mode + __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap), G2_thread, O2klass_index, O3); __ reset_last_Java_frame(); __ mov(O0, O2UnrollBlock->after_save()); __ restore(); @@ -3278,6 +3282,15 @@ void SharedRuntime::generate_uncommon_trap_blob() { __ mov(O2UnrollBlock, O2UnrollBlock->after_save()); __ restore(); +#ifdef ASSERT + { Label L; + __ ld(O2UnrollBlock, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes(), O1); + __ cmp_and_br_short(O1, Deoptimization::Unpack_uncommon_trap, Assembler::equal, Assembler::pt, L); + __ stop("SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap"); + __ bind(L); + } +#endif + // Allocate new interpreter frame(s) and possible c2i adapter frame make_new_frames(masm, false); diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index 708b8b9d441..22fdd1a5da6 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp @@ -2545,7 +2545,8 @@ void SharedRuntime::generate_deopt_blob() { oop_maps->add_gc_map( __ pc()-start, map); - // Discard arg to fetch_unroll_info + // Discard args to fetch_unroll_info + __ pop(rcx); __ pop(rcx); __ get_thread(rcx); @@ -2558,9 +2559,8 @@ void SharedRuntime::generate_deopt_blob() { // we are very short of registers Address unpack_kind(rdi, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes()); - // retrieve the deopt kind from where we left it. - __ pop(rax); - __ movl(unpack_kind, rax); // save the unpack_kind value + // retrieve the deopt kind from the UnrollBlock. + __ movl(rax, unpack_kind); Label noException; __ cmpl(rax, Deoptimization::Unpack_exception); // Was exception pending? @@ -2770,11 +2770,12 @@ void SharedRuntime::generate_uncommon_trap_blob() { enum frame_layout { arg0_off, // thread sp + 0 // Arg location for arg1_off, // unloaded_class_index sp + 1 // calling C + arg2_off, // exec_mode sp + 2 // The frame sender code expects that rbp will be in the "natural" place and // will override any oopMap setting for it. We must therefore force the layout // so that it agrees with the frame sender code. - rbp_off, // callee saved register sp + 2 - return_off, // slot for return address sp + 3 + rbp_off, // callee saved register sp + 3 + return_off, // slot for return address sp + 4 framesize }; @@ -2806,6 +2807,7 @@ void SharedRuntime::generate_uncommon_trap_blob() { __ movptr(Address(rsp, arg0_off*wordSize), rdx); // argument already in ECX __ movl(Address(rsp, arg1_off*wordSize),rcx); + __ movl(Address(rsp, arg2_off*wordSize), Deoptimization::Unpack_uncommon_trap); __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); // Set an oopmap for the call site @@ -2822,6 +2824,16 @@ void SharedRuntime::generate_uncommon_trap_blob() { // Load UnrollBlock into EDI __ movptr(rdi, rax); +#ifdef ASSERT + { Label L; + __ cmpptr(Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes()), + (int32_t)Deoptimization::Unpack_uncommon_trap); + __ jcc(Assembler::equal, L); + __ stop("SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap"); + __ bind(L); + } +#endif + // Pop all the frames we must move/replace. // // Frame picture (youngest to oldest) diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index 68094878b09..b0049ef3c7d 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -2829,6 +2829,7 @@ void SharedRuntime::generate_deopt_blob() { __ movl(r14, (int32_t)Deoptimization::Unpack_reexecute); __ mov(c_rarg0, r15_thread); + __ movl(c_rarg2, r14); // exec mode __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); oop_maps->add_gc_map( __ pc()-start, map->deep_copy()); @@ -2915,6 +2916,7 @@ void SharedRuntime::generate_deopt_blob() { } #endif // ASSERT __ mov(c_rarg0, r15_thread); + __ movl(c_rarg1, r14); // exec_mode __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info))); // Need to have an oopmap that tells fetch_unroll_info where to @@ -2932,6 +2934,7 @@ void SharedRuntime::generate_deopt_blob() { // Load UnrollBlock* into rdi __ mov(rdi, rax); + __ movl(r14, Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes())); Label noException; __ cmpl(r14, Deoptimization::Unpack_exception); // Was exception pending? __ jcc(Assembler::notEqual, noException); @@ -3150,6 +3153,7 @@ void SharedRuntime::generate_uncommon_trap_blob() { // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index); __ mov(c_rarg0, r15_thread); + __ movl(c_rarg2, Deoptimization::Unpack_uncommon_trap); __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); // Set an oopmap for the call site @@ -3165,6 +3169,16 @@ void SharedRuntime::generate_uncommon_trap_blob() { // Load UnrollBlock* into rdi __ mov(rdi, rax); +#ifdef ASSERT + { Label L; + __ cmpptr(Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes()), + (int32_t)Deoptimization::Unpack_uncommon_trap); + __ jcc(Assembler::equal, L); + __ stop("SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap"); + __ bind(L); + } +#endif + // Pop all the frames we must move/replace. // // Frame picture (youngest to oldest) diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 384b0f84594..37123f8dbab 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -1677,6 +1677,7 @@ public class HotSpotVMConfig { @HotSpotVMField(name = "Deoptimization::UnrollBlock::_caller_adjustment", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockCallerAdjustmentOffset; @HotSpotVMField(name = "Deoptimization::UnrollBlock::_number_of_frames", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockNumberOfFramesOffset; @HotSpotVMField(name = "Deoptimization::UnrollBlock::_total_frame_sizes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockTotalFrameSizesOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_unpack_kind", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockUnpackKindOffset; @HotSpotVMField(name = "Deoptimization::UnrollBlock::_frame_sizes", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockFrameSizesOffset; @HotSpotVMField(name = "Deoptimization::UnrollBlock::_frame_pcs", type = "address*", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockFramePcsOffset; @HotSpotVMField(name = "Deoptimization::UnrollBlock::_initial_info", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockInitialInfoOffset; diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index 41cb1f67f5d..4d1883ba221 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -68,7 +68,8 @@ Deoptimization::UnrollBlock::UnrollBlock(int size_of_deoptimized_frame, int number_of_frames, intptr_t* frame_sizes, address* frame_pcs, - BasicType return_type) { + BasicType return_type, + int exec_mode) { _size_of_deoptimized_frame = size_of_deoptimized_frame; _caller_adjustment = caller_adjustment; _caller_actual_parameters = caller_actual_parameters; @@ -80,10 +81,11 @@ Deoptimization::UnrollBlock::UnrollBlock(int size_of_deoptimized_frame, _initial_info = 0; // PD (x86 only) _counter_temp = 0; - _unpack_kind = 0; + _unpack_kind = exec_mode; _sender_sp_temp = 0; _total_frame_sizes = size_of_frames(); + assert(exec_mode >= 0 && exec_mode < Unpack_LIMIT, "Unexpected exec_mode"); } @@ -128,7 +130,7 @@ void Deoptimization::UnrollBlock::print() { // ResetNoHandleMark and HandleMark were removed from it. The actual reallocation // of previously eliminated objects occurs in realloc_objects, which is // called from the method fetch_unroll_info_helper below. -JRT_BLOCK_ENTRY(Deoptimization::UnrollBlock*, Deoptimization::fetch_unroll_info(JavaThread* thread)) +JRT_BLOCK_ENTRY(Deoptimization::UnrollBlock*, Deoptimization::fetch_unroll_info(JavaThread* thread, int exec_mode)) // It is actually ok to allocate handles in a leaf method. It causes no safepoints, // but makes the entry a little slower. There is however a little dance we have to // do in debug mode to get around the NoHandleMark code in the JRT_LEAF macro @@ -142,12 +144,12 @@ JRT_BLOCK_ENTRY(Deoptimization::UnrollBlock*, Deoptimization::fetch_unroll_info( } thread->inc_in_deopt_handler(); - return fetch_unroll_info_helper(thread); + return fetch_unroll_info_helper(thread, exec_mode); JRT_END // This is factored, since it is both called from a JRT_LEAF (deoptimization) and a JRT_ENTRY (uncommon_trap) -Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread* thread) { +Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread* thread, int exec_mode) { // Note: there is a safepoint safety issue here. No matter whether we enter // via vanilla deopt or uncommon trap we MUST NOT stop at a safepoint once @@ -186,6 +188,19 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread assert(vf->is_compiled_frame(), "Wrong frame type"); chunk->push(compiledVFrame::cast(vf)); + ScopeDesc* trap_scope = chunk->at(0)->scope(); + Handle exceptionObject; + if (trap_scope->rethrow_exception()) { + if (PrintDeoptimizationDetails) { + tty->print_cr("Exception to be rethrown in the interpreter for method %s::%s at bci %d", trap_scope->method()->method_holder()->name()->as_C_string(), trap_scope->method()->name()->as_C_string(), trap_scope->bci()); + } + GrowableArray* expressions = trap_scope->expressions(); + guarantee(expressions != NULL && expressions->length() > 0, "must have exception to throw"); + ScopeValue* topOfStack = expressions->top(); + exceptionObject = StackValue::create_stack_value(&deoptee, &map, topOfStack)->get_obj(); + assert(exceptionObject() != NULL, "exception oop can not be null"); + } + bool realloc_failures = false; #if defined(COMPILER2) || INCLUDE_JVMCI @@ -474,13 +489,21 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread assert(CodeCache::find_blob_unsafe(frame_pcs[0]) != NULL, "bad pc"); #endif // SHARK +#ifdef INCLUDE_JVMCI + if (exceptionObject() != NULL) { + thread->set_exception_oop(exceptionObject()); + exec_mode = Unpack_exception; + } +#endif + UnrollBlock* info = new UnrollBlock(array->frame_size() * BytesPerWord, caller_adjustment * BytesPerWord, caller_was_method_handle ? 0 : callee_parameters, number_of_frames, frame_sizes, frame_pcs, - return_type); + return_type, + exec_mode); // On some platforms, we need a way to pass some platform dependent // information to the unpacking code so the skeletal frames come out // correct (initial fp value, unextended sp, ...) @@ -1495,18 +1518,6 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra #endif Bytecodes::Code trap_bc = trap_method->java_code_at(trap_bci); - - if (trap_scope->rethrow_exception()) { - if (PrintDeoptimizationDetails) { - tty->print_cr("Exception to be rethrown in the interpreter for method %s::%s at bci %d", trap_method->method_holder()->name()->as_C_string(), trap_method->name()->as_C_string(), trap_bci); - } - GrowableArray* expressions = trap_scope->expressions(); - guarantee(expressions != NULL, "must have exception to throw"); - ScopeValue* topOfStack = expressions->top(); - Handle topOfStackObj = StackValue::create_stack_value(&fr, ®_map, topOfStack)->get_obj(); - THREAD->set_pending_exception(topOfStackObj(), NULL, 0); - } - // Record this event in the histogram. gather_statistics(reason, action, trap_bc); @@ -1985,7 +1996,7 @@ Deoptimization::update_method_data_from_interpreter(MethodData* trap_mdo, int tr ignore_maybe_prior_recompile); } -Deoptimization::UnrollBlock* Deoptimization::uncommon_trap(JavaThread* thread, jint trap_request) { +Deoptimization::UnrollBlock* Deoptimization::uncommon_trap(JavaThread* thread, jint trap_request, jint exec_mode) { if (TraceDeoptimization) { tty->print("Uncommon trap "); } @@ -1994,7 +2005,7 @@ Deoptimization::UnrollBlock* Deoptimization::uncommon_trap(JavaThread* thread, j // This enters VM and may safepoint uncommon_trap_inner(thread, trap_request); } - return fetch_unroll_info_helper(thread); + return fetch_unroll_info_helper(thread, exec_mode); } // Local derived constants. diff --git a/hotspot/src/share/vm/runtime/deoptimization.hpp b/hotspot/src/share/vm/runtime/deoptimization.hpp index e02836849b6..7aaa7cc02cc 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.hpp +++ b/hotspot/src/share/vm/runtime/deoptimization.hpp @@ -123,7 +123,8 @@ class Deoptimization : AllStatic { Unpack_deopt = 0, // normal deoptimization, use pc computed in unpack_vframe_on_stack Unpack_exception = 1, // exception is pending Unpack_uncommon_trap = 2, // redo last byte code (C2 only) - Unpack_reexecute = 3 // reexecute bytecode (C1 only) + Unpack_reexecute = 3, // reexecute bytecode (C1 only) + Unpack_LIMIT = 4 }; // Checks all compiled methods. Invalid methods are deleted and @@ -179,13 +180,13 @@ JVMCI_ONLY(public:) intptr_t _initial_info; // Platform dependent data for the sender frame (was FP on x86) int _caller_actual_parameters; // The number of actual arguments at the // interpreted caller of the deoptimized frame + int _unpack_kind; // exec_mode that can be changed during fetch_unroll_info // The following fields are used as temps during the unpacking phase // (which is tight on registers, especially on x86). They really ought // to be PD variables but that involves moving this class into its own // file to use the pd include mechanism. Maybe in a later cleanup ... intptr_t _counter_temp; // SHOULD BE PD VARIABLE (x86 frame count temp) - intptr_t _unpack_kind; // SHOULD BE PD VARIABLE (x86 unpack kind) intptr_t _sender_sp_temp; // SHOULD BE PD VARIABLE (x86 sender_sp) public: // Constructor @@ -195,7 +196,8 @@ JVMCI_ONLY(public:) int number_of_frames, intptr_t* frame_sizes, address* frames_pcs, - BasicType return_type); + BasicType return_type, + int unpack_kind); ~UnrollBlock(); // Returns where a register is located. @@ -205,6 +207,7 @@ JVMCI_ONLY(public:) intptr_t* frame_sizes() const { return _frame_sizes; } int number_of_frames() const { return _number_of_frames; } address* frame_pcs() const { return _frame_pcs ; } + int unpack_kind() const { return _unpack_kind; } // Returns the total size of frames int size_of_frames() const; @@ -237,7 +240,7 @@ JVMCI_ONLY(public:) // deoptimized frame. // @argument thread. Thread where stub_frame resides. // @see OptoRuntime::deoptimization_fetch_unroll_info_C - static UnrollBlock* fetch_unroll_info(JavaThread* thread); + static UnrollBlock* fetch_unroll_info(JavaThread* thread, int exec_mode); //** Unpacks vframeArray onto execution stack // Called by assembly stub after execution has returned to @@ -262,7 +265,7 @@ JVMCI_ONLY(public:) //** Performs an uncommon trap for compiled code. // The top most compiler frame is converted into interpreter frames - static UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index); + static UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index, jint exec_mode); // Helper routine that enters the VM and may block static void uncommon_trap_inner(JavaThread* thread, jint unloaded_class_index); @@ -423,7 +426,7 @@ JVMCI_ONLY(public:) static void load_class_by_index(constantPoolHandle constant_pool, int index, TRAPS); static void load_class_by_index(constantPoolHandle constant_pool, int index); - static UnrollBlock* fetch_unroll_info_helper(JavaThread* thread); + static UnrollBlock* fetch_unroll_info_helper(JavaThread* thread, int exec_mode); static DeoptAction _unloaded_action; // == Action_reinterpret; static const char* _trap_reason_name[]; diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index ee9a24d6900..6b3a665742c 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -968,6 +968,7 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(Deoptimization::UnrollBlock, _caller_adjustment, int) \ nonstatic_field(Deoptimization::UnrollBlock, _number_of_frames, int) \ nonstatic_field(Deoptimization::UnrollBlock, _total_frame_sizes, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _unpack_kind, int) \ nonstatic_field(Deoptimization::UnrollBlock, _frame_sizes, intptr_t*) \ nonstatic_field(Deoptimization::UnrollBlock, _frame_pcs, address*) \ nonstatic_field(Deoptimization::UnrollBlock, _register_block, intptr_t*) \ diff --git a/hotspot/src/share/vm/shark/sharkRuntime.cpp b/hotspot/src/share/vm/shark/sharkRuntime.cpp index bf609bce455..c6fd028479b 100644 --- a/hotspot/src/share/vm/shark/sharkRuntime.cpp +++ b/hotspot/src/share/vm/shark/sharkRuntime.cpp @@ -213,8 +213,9 @@ int SharkRuntime::uncommon_trap(JavaThread* thread, int trap_request) { // Initiate the trap thread->set_last_Java_frame(); Deoptimization::UnrollBlock *urb = - Deoptimization::uncommon_trap(thread, trap_request); + Deoptimization::uncommon_trap(thread, trap_request, Deoptimization::Unpack_uncommon_trap); thread->reset_last_Java_frame(); + assert(urb->unpack_kind() == Deoptimization::Unpack_uncommon_trap, "expected Unpack_uncommon_trap"); // Pop our dummy frame and the frame being deoptimized thread->pop_zero_frame(); From 6896030b9620e89546527fbfd19369366b5ad3d5 Mon Sep 17 00:00:00 2001 From: Christian Thalinger Date: Wed, 11 Nov 2015 16:32:17 -1000 Subject: [PATCH 027/260] 8140424: don't prefix developer and notproduct flag variables with CONST_ in product builds Reviewed-by: goetz, stefank --- hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp | 2 +- hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp | 8 +- .../linux_sparc/vm/vm_version_linux_sparc.cpp | 4 +- hotspot/src/share/vm/c1/c1_GraphBuilder.cpp | 4 - hotspot/src/share/vm/code/codeCache.cpp | 2 - hotspot/src/share/vm/code/nmethod.cpp | 8 +- .../share/vm/compiler/compilerDirectives.hpp | 2 +- .../src/share/vm/gc/cms/parNewGeneration.cpp | 2 - .../share/vm/gc/cms/parOopClosures.inline.hpp | 3 - .../vm/gc/parallel/psPromotionManager.cpp | 2 - .../gc/parallel/psPromotionManager.inline.hpp | 6 +- .../vm/gc/parallel/psScavenge.inline.hpp | 2 - .../share/vm/gc/serial/defNewGeneration.cpp | 2 - hotspot/src/share/vm/opto/buildOopMap.cpp | 7 +- hotspot/src/share/vm/opto/compile.cpp | 2 +- hotspot/src/share/vm/opto/doCall.cpp | 12 +-- hotspot/src/share/vm/opto/loopTransform.cpp | 24 +++--- hotspot/src/share/vm/opto/loopUnswitch.cpp | 12 ++- hotspot/src/share/vm/opto/loopnode.cpp | 2 - hotspot/src/share/vm/opto/loopopts.cpp | 16 +--- hotspot/src/share/vm/opto/matcher.cpp | 6 +- hotspot/src/share/vm/opto/movenode.cpp | 4 +- hotspot/src/share/vm/opto/output.cpp | 11 +-- hotspot/src/share/vm/opto/parse1.cpp | 4 - hotspot/src/share/vm/opto/parse2.cpp | 16 ++-- hotspot/src/share/vm/opto/parse3.cpp | 2 - hotspot/src/share/vm/opto/reg_split.cpp | 5 +- hotspot/src/share/vm/opto/split_if.cpp | 6 +- hotspot/src/share/vm/opto/superword.cpp | 62 +++++++------- hotspot/src/share/vm/prims/jni.cpp | 2 +- hotspot/src/share/vm/runtime/arguments.cpp | 2 +- hotspot/src/share/vm/runtime/globals.cpp | 84 +++++++++---------- hotspot/src/share/vm/runtime/globals.hpp | 12 +-- 33 files changed, 138 insertions(+), 200 deletions(-) diff --git a/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp index 3ff878b9328..01597d02026 100644 --- a/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp @@ -2697,7 +2697,7 @@ address CppInterpreterGenerator::generate_normal_entry(bool synchronized) { // Provide a debugger breakpoint in the frame manager if breakpoints // in osr'd methods are requested. #ifdef COMPILER2 - NOT_PRODUCT( if (OptoBreakpointOSR) { __ illtrap(); } ) + if (OptoBreakpointOSR) { __ illtrap(); } #endif // Load callee's pointer to locals array from callee's state. diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index 0438025fed3..e942940d49b 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -358,7 +358,6 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseUnalignedAccesses, false); } -#ifndef PRODUCT if (PrintMiscellaneous && Verbose) { tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size()); tty->print_cr("L2 data cache line size: %u", L2_data_cache_line_size()); @@ -391,7 +390,6 @@ void VM_Version::initialize() { tty->print_cr("ContendedPaddingWidth %d", (int) ContendedPaddingWidth); } } -#endif // PRODUCT } void VM_Version::print_features() { @@ -400,7 +398,7 @@ void VM_Version::print_features() { int VM_Version::determine_features() { if (UseV8InstrsOnly) { - NOT_PRODUCT(if (PrintMiscellaneous && Verbose) tty->print_cr("Version is Forced-V8");) + if (PrintMiscellaneous && Verbose) { tty->print_cr("Version is Forced-V8"); } return generic_v8_m; } @@ -416,12 +414,12 @@ int VM_Version::determine_features() { if (is_T_family(features)) { // Happy to accomodate... } else { - NOT_PRODUCT(if (PrintMiscellaneous && Verbose) tty->print_cr("Version is Forced-Niagara");) + if (PrintMiscellaneous && Verbose) { tty->print_cr("Version is Forced-Niagara"); } features |= T_family_m; } } else { if (is_T_family(features) && !FLAG_IS_DEFAULT(UseNiagaraInstrs)) { - NOT_PRODUCT(if (PrintMiscellaneous && Verbose) tty->print_cr("Version is Forced-Not-Niagara");) + if (PrintMiscellaneous && Verbose) { tty->print_cr("Version is Forced-Not-Niagara"); } features &= ~(T_family_m | T1_model_m); } else { // Happy to accomodate... diff --git a/hotspot/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp b/hotspot/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp index 0b992632b27..f9c596e4d79 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp @@ -66,12 +66,12 @@ int VM_Version::platform_features(int features) { features = generic_v9_m; if (detect_niagara()) { - NOT_PRODUCT(if (PrintMiscellaneous && Verbose) tty->print_cr("Detected Linux on Niagara");) + if (PrintMiscellaneous && Verbose) { tty->print_cr("Detected Linux on Niagara"); } features = niagara1_m | T_family_m; } if (detect_M_family()) { - NOT_PRODUCT(if (PrintMiscellaneous && Verbose) tty->print_cr("Detected Linux on M family");) + if (PrintMiscellaneous && Verbose) { tty->print_cr("Detected Linux on M family"); } features = sun4v_m | generic_v9_m | M_family_m | T_family_m; } diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp index 15a7fb88311..bb32e5f6e90 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp @@ -707,12 +707,10 @@ BlockBegin* GraphBuilder::ScopeData::block_at(int bci) { BlockBegin* block = bci2block()->at(bci); if (block != NULL && block == parent()->bci2block()->at(bci)) { BlockBegin* new_block = new BlockBegin(block->bci()); -#ifndef PRODUCT if (PrintInitialBlockList) { tty->print_cr("CFG: cloned block %d (bci %d) as block %d for jsr", block->block_id(), block->bci(), new_block->block_id()); } -#endif // copy data from cloned blocked new_block->set_depth_first_number(block->depth_first_number()); if (block->is_set(BlockBegin::parser_loop_header_flag)) new_block->set(BlockBegin::parser_loop_header_flag); @@ -3790,12 +3788,10 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode cont = new BlockBegin(next_bci()); // low number so that continuation gets parsed as early as possible cont->set_depth_first_number(0); -#ifndef PRODUCT if (PrintInitialBlockList) { tty->print_cr("CFG: created block %d (bci %d) as continuation for inline at bci %d", cont->block_id(), cont->bci(), bci()); } -#endif continuation_existed = false; } // Record number of predecessors of continuation block before diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index 1114d24a37c..4301f293eb2 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -572,11 +572,9 @@ void CodeCache::scavenge_root_nmethods_do(CodeBlobClosure* f) { assert(cur->on_scavenge_root_list(), "else shouldn't be on this list"); bool is_live = (!cur->is_zombie() && !cur->is_unloaded()); -#ifndef PRODUCT if (TraceScavenge) { cur->print_on(tty, is_live ? "scavenge root" : "dead scavenge root"); tty->cr(); } -#endif //PRODUCT if (is_live) { // Perform cur->oops_do(f), maybe just once per nmethod. f->do_code_blob(cur); diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index c5eda7de5be..10f5623955a 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -2250,7 +2250,7 @@ bool nmethod::test_set_oops_do_mark() { break; } // Mark was clear when we first saw this guy. - NOT_PRODUCT(if (TraceScavenge) print_on(tty, "oops_do, mark")); + if (TraceScavenge) { print_on(tty, "oops_do, mark"); } return false; } } @@ -2259,7 +2259,7 @@ bool nmethod::test_set_oops_do_mark() { } void nmethod::oops_do_marking_prologue() { - NOT_PRODUCT(if (TraceScavenge) tty->print_cr("[oops_do_marking_prologue")); + if (TraceScavenge) { tty->print_cr("[oops_do_marking_prologue"); } assert(_oops_do_mark_nmethods == NULL, "must not call oops_do_marking_prologue twice in a row"); // We use cmpxchg_ptr instead of regular assignment here because the user // may fork a bunch of threads, and we need them all to see the same state. @@ -2275,13 +2275,13 @@ void nmethod::oops_do_marking_epilogue() { nmethod* next = cur->_oops_do_mark_link; cur->_oops_do_mark_link = NULL; cur->verify_oop_relocations(); - NOT_PRODUCT(if (TraceScavenge) cur->print_on(tty, "oops_do, unmark")); + if (TraceScavenge) { cur->print_on(tty, "oops_do, unmark"); } cur = next; } void* required = _oops_do_mark_nmethods; void* observed = Atomic::cmpxchg_ptr(NULL, &_oops_do_mark_nmethods, required); guarantee(observed == required, "no races in this sequential code"); - NOT_PRODUCT(if (TraceScavenge) tty->print_cr("oops_do_marking_epilogue]")); + if (TraceScavenge) { tty->print_cr("oops_do_marking_epilogue]"); } } class DetectScavengeRoot: public OopClosure { diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.hpp b/hotspot/src/share/vm/compiler/compilerDirectives.hpp index f980f769c7f..421012c687e 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.hpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.hpp @@ -67,7 +67,7 @@ cflags(VectorizeDebug, bool, false, VectorizeDebug) \ cflags(CloneMapDebug, bool, false, CloneMapDebug) \ cflags(DoReserveCopyInSuperWordDebug, bool, false, DoReserveCopyInSuperWordDebug) \ - NOT_PRODUCT( cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLevel)) \ + cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLevel) \ cflags(MaxNodeLimit, intx, MaxNodeLimit, MaxNodeLimit) #else #define compilerdirectives_c2_flags(cflags) diff --git a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp index e2ff84ab5f8..3c138b840bf 100644 --- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp @@ -1162,7 +1162,6 @@ oop ParNewGeneration::copy_to_survivor_space(ParScanThreadState* par_scan_state, } assert(new_obj != NULL, "just checking"); -#ifndef PRODUCT // This code must come after the CAS test, or it will print incorrect // information. if (TraceScavenge) { @@ -1170,7 +1169,6 @@ oop ParNewGeneration::copy_to_survivor_space(ParScanThreadState* par_scan_state, is_in_reserved(new_obj) ? "copying" : "tenuring", new_obj->klass()->internal_name(), p2i(old), p2i(new_obj), new_obj->size()); } -#endif if (forward_ptr == NULL) { oop obj_to_push = new_obj; diff --git a/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp b/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp index 171b3581e94..6619cb09225 100644 --- a/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp +++ b/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp @@ -108,14 +108,11 @@ inline void ParScanClosure::do_oop_work(T* p, if (m->is_marked()) { // Contains forwarding pointer. new_obj = ParNewGeneration::real_forwardee(obj); oopDesc::encode_store_heap_oop_not_null(p, new_obj); -#ifndef PRODUCT if (TraceScavenge) { gclog_or_tty->print_cr("{%s %s ( " PTR_FORMAT " ) " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", "forwarded ", new_obj->klass()->internal_name(), p2i(p), p2i((void *)obj), p2i((void *)new_obj), new_obj->size()); } -#endif - } else { size_t obj_sz = obj->size_given_klass(objK); new_obj = _g->copy_to_survivor_space(_par_scan_state, obj, obj_sz, m); diff --git a/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp b/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp index 477b2a15893..6e54c638f22 100644 --- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp +++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp @@ -430,7 +430,6 @@ oop PSPromotionManager::oop_promotion_failed(oop obj, markOop obj_mark) { obj = obj->forwardee(); } -#ifndef PRODUCT if (TraceScavenge) { gclog_or_tty->print_cr("{%s %s " PTR_FORMAT " (%d)}", "promotion-failure", @@ -438,7 +437,6 @@ oop PSPromotionManager::oop_promotion_failed(oop obj, markOop obj_mark) { p2i(obj), obj->size()); } -#endif return obj; } diff --git a/hotspot/src/share/vm/gc/parallel/psPromotionManager.inline.hpp b/hotspot/src/share/vm/gc/parallel/psPromotionManager.inline.hpp index 2e3b4a28b04..ef3aa4732e0 100644 --- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.inline.hpp +++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.inline.hpp @@ -260,7 +260,6 @@ inline oop PSPromotionManager::copy_to_survivor_space(oop o) { new_obj = o->forwardee(); } -#ifndef PRODUCT // This code must come after the CAS test, or it will print incorrect // information. if (TraceScavenge) { @@ -268,7 +267,6 @@ inline oop PSPromotionManager::copy_to_survivor_space(oop o) { should_scavenge(&new_obj) ? "copying" : "tenuring", new_obj->klass()->internal_name(), p2i((void *)o), p2i((void *)new_obj), new_obj->size()); } -#endif return new_obj; } @@ -285,15 +283,13 @@ inline void PSPromotionManager::copy_and_push_safe_barrier(T* p) { ? o->forwardee() : copy_to_survivor_space(o); -#ifndef PRODUCT // This code must come after the CAS test, or it will print incorrect // information. - if (TraceScavenge && o->is_forwarded()) { + if (TraceScavenge && o->is_forwarded()) { gclog_or_tty->print_cr("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}", "forwarding", new_obj->klass()->internal_name(), p2i((void *)o), p2i((void *)new_obj), new_obj->size()); } -#endif oopDesc::encode_store_heap_oop_not_null(p, new_obj); diff --git a/hotspot/src/share/vm/gc/parallel/psScavenge.inline.hpp b/hotspot/src/share/vm/gc/parallel/psScavenge.inline.hpp index 1881e01a342..0a4d2ef94ed 100644 --- a/hotspot/src/share/vm/gc/parallel/psScavenge.inline.hpp +++ b/hotspot/src/share/vm/gc/parallel/psScavenge.inline.hpp @@ -138,7 +138,6 @@ class PSScavengeKlassClosure: public KlassClosure { // If the klass has not been dirtied we know that there's // no references into the young gen and we can skip it. -#ifndef PRODUCT if (TraceScavenge) { ResourceMark rm; gclog_or_tty->print_cr("PSScavengeKlassClosure::do_klass " PTR_FORMAT ", %s, dirty: %s", @@ -146,7 +145,6 @@ class PSScavengeKlassClosure: public KlassClosure { klass->external_name(), klass->has_modified_oops() ? "true" : "false"); } -#endif if (klass->has_modified_oops()) { // Clean the klass since we're going to scavenge all the metadata. diff --git a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp index 29f3aeb65a0..c9810458d3a 100644 --- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp +++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp @@ -134,7 +134,6 @@ void FastScanClosure::do_oop(oop* p) { FastScanClosure::do_oop_work(p); } void FastScanClosure::do_oop(narrowOop* p) { FastScanClosure::do_oop_work(p); } void KlassScanClosure::do_klass(Klass* klass) { -#ifndef PRODUCT if (TraceScavenge) { ResourceMark rm; gclog_or_tty->print_cr("KlassScanClosure::do_klass " PTR_FORMAT ", %s, dirty: %s", @@ -142,7 +141,6 @@ void KlassScanClosure::do_klass(Klass* klass) { klass->external_name(), klass->has_modified_oops() ? "true" : "false"); } -#endif // If the klass has not been dirtied we know that there's // no references into the young gen and we can skip it. diff --git a/hotspot/src/share/vm/opto/buildOopMap.cpp b/hotspot/src/share/vm/opto/buildOopMap.cpp index 3a76492fbe0..6c8981b2fe8 100644 --- a/hotspot/src/share/vm/opto/buildOopMap.cpp +++ b/hotspot/src/share/vm/opto/buildOopMap.cpp @@ -542,10 +542,11 @@ static void do_liveness(PhaseRegAlloc* regalloc, PhaseCFG* cfg, Block_List* work if (i == cfg->number_of_blocks()) { break; // Got 'em all } -#ifndef PRODUCT - if( PrintOpto && Verbose ) + + if (PrintOpto && Verbose) { tty->print_cr("retripping live calc"); -#endif + } + // Force the issue (expensively): recheck everybody for (i = 1; i < cfg->number_of_blocks(); i++) { worklist->push(cfg->get_block(i)); diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 1ad17284915..03598415bc2 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -707,7 +707,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr _replay_inline_data = ciReplay::load_inline_data(method(), entry_bci(), ci_env->comp_level()); } #endif - set_print_inlining(directive->PrintInliningOption NOT_PRODUCT( || PrintOptoInlining)); + set_print_inlining(directive->PrintInliningOption || PrintOptoInlining); set_print_intrinsics(directive->PrintIntrinsicsOption); set_has_irreducible_loop(true); // conservative until build_loop_tree() reset it diff --git a/hotspot/src/share/vm/opto/doCall.cpp b/hotspot/src/share/vm/opto/doCall.cpp index 08801c70994..b8737560b07 100644 --- a/hotspot/src/share/vm/opto/doCall.cpp +++ b/hotspot/src/share/vm/opto/doCall.cpp @@ -45,7 +45,7 @@ void trace_type_profile(Compile* C, ciMethod *method, int depth, int bci, ciMeth if (TraceTypeProfile || C->print_inlining()) { outputStream* out = tty; if (!C->print_inlining()) { - if (NOT_PRODUCT(!PrintOpto &&) !PrintCompilation) { + if (!PrintOpto && !PrintCompilation) { method->print_short_name(); tty->cr(); } @@ -426,12 +426,10 @@ void Parse::do_call() { // uncommon-trap when callee is unloaded, uninitialized or will not link // bailout when too many arguments for register representation if (!will_link || can_not_compile_call_site(orig_callee, klass)) { -#ifndef PRODUCT if (PrintOpto && (Verbose || WizardMode)) { method()->print_name(); tty->print_cr(" can not compile call at bci %d to:", bci()); orig_callee->print_name(); tty->cr(); } -#endif return; } assert(holder_klass->is_loaded(), ""); @@ -634,12 +632,10 @@ void Parse::do_call() { // If the return type of the method is not loaded, assert that the // value we got is a null. Otherwise, we need to recompile. if (!rtype->is_loaded()) { -#ifndef PRODUCT if (PrintOpto && (Verbose || WizardMode)) { method()->print_name(); tty->print_cr(" asserting nullness of result at bci: %d", bci()); cg->method()->print_name(); tty->cr(); } -#endif if (C->log() != NULL) { C->log()->elem("assert_null reason='return' klass='%d'", C->log()->identify(rtype)); @@ -851,11 +847,9 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) { if (remaining == 1) { push_ex_oop(ex_node); // Push exception oop for handler -#ifndef PRODUCT if (PrintOpto && WizardMode) { tty->print_cr(" Catching every inline exception bci:%d -> handler_bci:%d", bci(), handler_bci); } -#endif merge_exception(handler_bci); // jump to handler return; // No more handling to be done here! } @@ -882,13 +876,11 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) { assert(klass->has_subklass() || tinst->klass_is_exact(), "lost exactness"); Node* ex_oop = _gvn.transform(new CheckCastPPNode(control(), ex_node, tinst)); push_ex_oop(ex_oop); // Push exception oop for handler -#ifndef PRODUCT if (PrintOpto && WizardMode) { tty->print(" Catching inline exception bci:%d -> handler_bci:%d -- ", bci(), handler_bci); klass->print_name(); tty->cr(); } -#endif merge_exception(handler_bci); } set_control(not_subtype_ctrl); @@ -1067,13 +1059,11 @@ ciMethod* Compile::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* // such method can be changed when its class is redefined. ciMethod* exact_method = callee->resolve_invoke(calling_klass, actual_receiver); if (exact_method != NULL) { -#ifndef PRODUCT if (PrintOpto) { tty->print(" Calling method via exact type @%d --- ", bci); exact_method->print_name(); tty->cr(); } -#endif return exact_method; } } diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index 692ef9f58c0..41ebaffc838 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -792,8 +792,10 @@ bool IdealLoopTree::policy_unroll(PhaseIdealLoop *phase) { return false; } - if(cl->do_unroll_only()) { - NOT_PRODUCT(if (TraceSuperWordLoopUnrollAnalysis) tty->print_cr("policy_unroll passed vector loop(vlen=%d,factor = %d)\n", slp_max_unroll_factor, future_unroll_ct)); + if (cl->do_unroll_only()) { + if (TraceSuperWordLoopUnrollAnalysis) { + tty->print_cr("policy_unroll passed vector loop(vlen=%d,factor = %d)\n", slp_max_unroll_factor, future_unroll_ct); + } } // Unroll once! (Each trip will soon do double iterations) @@ -818,7 +820,9 @@ void IdealLoopTree::policy_unroll_slp_analysis(CountedLoopNode *cl, PhaseIdealLo if (slp_max_unroll_factor >= future_unroll_ct) { int new_limit = cl->node_count_before_unroll() * slp_max_unroll_factor; if (new_limit > LoopUnrollLimit) { - NOT_PRODUCT(if (TraceSuperWordLoopUnrollAnalysis) tty->print_cr("slp analysis unroll=%d, default limit=%d\n", new_limit, _local_loop_unroll_limit)); + if (TraceSuperWordLoopUnrollAnalysis) { + tty->print_cr("slp analysis unroll=%d, default limit=%d\n", new_limit, _local_loop_unroll_limit); + } _local_loop_unroll_limit = new_limit; } } @@ -2120,10 +2124,9 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { conditional_rc = !loop->dominates_backedge(iff) || RangeLimitCheck; } } else { -#ifndef PRODUCT - if( PrintOpto ) + if (PrintOpto) { tty->print_cr("missed RCE opportunity"); -#endif + } continue; // In release mode, ignore it } } else { // Otherwise work on normal compares @@ -2158,10 +2161,9 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { } break; default: -#ifndef PRODUCT - if( PrintOpto ) + if (PrintOpto) { tty->print_cr("missed RCE opportunity"); -#endif + } continue; // Unhandled case } } @@ -2505,9 +2507,7 @@ bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_ return false; } if (should_peel) { // Should we peel? -#ifndef PRODUCT - if (PrintOpto) tty->print_cr("should_peel"); -#endif + if (PrintOpto) { tty->print_cr("should_peel"); } phase->do_peeling(this,old_new); } else if (should_unswitch) { phase->do_unswitching(this, old_new); diff --git a/hotspot/src/share/vm/opto/loopUnswitch.cpp b/hotspot/src/share/vm/opto/loopUnswitch.cpp index a5976f4c93d..991d339d58c 100644 --- a/hotspot/src/share/vm/opto/loopUnswitch.cpp +++ b/hotspot/src/share/vm/opto/loopUnswitch.cpp @@ -361,16 +361,22 @@ bool CountedLoopReserveKit::create_reserve() { } if(!_lpt->_head->is_CountedLoop()) { - NOT_PRODUCT(if(TraceLoopOpts) {tty->print_cr("CountedLoopReserveKit::create_reserve: %d not counted loop", _lpt->_head->_idx);}) + if (TraceLoopOpts) { + tty->print_cr("CountedLoopReserveKit::create_reserve: %d not counted loop", _lpt->_head->_idx); + } return false; } CountedLoopNode *cl = _lpt->_head->as_CountedLoop(); if (!cl->is_valid_counted_loop()) { - NOT_PRODUCT(if(TraceLoopOpts) {tty->print_cr("CountedLoopReserveKit::create_reserve: %d not valid counted loop", cl->_idx);}) + if (TraceLoopOpts) { + tty->print_cr("CountedLoopReserveKit::create_reserve: %d not valid counted loop", cl->_idx); + } return false; // skip malformed counted loop } if (!cl->is_main_loop()) { - NOT_PRODUCT(if(TraceLoopOpts) {tty->print_cr("CountedLoopReserveKit::create_reserve: %d not main loop", cl->_idx);}) + if (TraceLoopOpts) { + tty->print_cr("CountedLoopReserveKit::create_reserve: %d not main loop", cl->_idx); + } return false; // skip normal, pre, and post loops } diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp index eb09d62d23a..78f54006d91 100644 --- a/hotspot/src/share/vm/opto/loopnode.cpp +++ b/hotspot/src/share/vm/opto/loopnode.cpp @@ -2397,11 +2397,9 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool skip_loop_opts) // After that switch predicates off and do more loop optimizations. if (!C->major_progress() && (C->predicate_count() > 0)) { C->cleanup_loop_predicates(_igvn); -#ifndef PRODUCT if (TraceLoopOpts) { tty->print_cr("PredicatesOff"); } -#endif C->set_major_progress(); } diff --git a/hotspot/src/share/vm/opto/loopopts.cpp b/hotspot/src/share/vm/opto/loopopts.cpp index ecdf1d7f8e9..9be560add6a 100644 --- a/hotspot/src/share/vm/opto/loopopts.cpp +++ b/hotspot/src/share/vm/opto/loopopts.cpp @@ -199,10 +199,7 @@ Node *PhaseIdealLoop::split_thru_phi( Node *n, Node *region, int policy ) { // IGVN worklist for later cleanup. Move control-dependent data Nodes on the // live path up to the dominating control. void PhaseIdealLoop::dominated_by( Node *prevdom, Node *iff, bool flip, bool exclude_loop_predicate ) { -#ifndef PRODUCT - if (VerifyLoopOptimizations && PrintOpto) tty->print_cr("dominating test"); -#endif - + if (VerifyLoopOptimizations && PrintOpto) { tty->print_cr("dominating test"); } // prevdom is the dominating projection of the dominating test. assert( iff->is_If(), "" ); @@ -617,9 +614,7 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) { } } if (phi == NULL) break; -#ifndef PRODUCT - if (PrintOpto && VerifyLoopOptimizations) tty->print_cr("CMOV"); -#endif + if (PrintOpto && VerifyLoopOptimizations) { tty->print_cr("CMOV"); } // Move speculative ops for (uint j = 1; j < region->req(); j++) { Node *proj = region->in(j); @@ -963,10 +958,9 @@ static bool merge_point_too_heavy(Compile* C, Node* region) { } int nodes_left = C->max_node_limit() - C->live_nodes(); if (weight * 8 > nodes_left) { -#ifndef PRODUCT - if (PrintOpto) + if (PrintOpto) { tty->print_cr("*** Split-if bails out: %d nodes, region weight %d", C->unique(), weight); -#endif + } return true; } else { return false; @@ -1490,14 +1484,12 @@ void PhaseIdealLoop::sink_use( Node *use, Node *post_loop ) { void PhaseIdealLoop::clone_loop( IdealLoopTree *loop, Node_List &old_new, int dd, Node* side_by_side_idom) { -#ifndef PRODUCT if (C->do_vector_loop() && PrintOpto) { const char* mname = C->method()->name()->as_quoted_ascii(); if (mname != NULL) { tty->print("PhaseIdealLoop::clone_loop: for vectorize method %s\n", mname); } } -#endif CloneMap& cm = C->clone_map(); Dict* dict = cm.dict(); diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index 117dd765ac8..acf3f32ece0 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -1569,13 +1569,11 @@ Node *Matcher::Label_Root( const Node *n, State *svec, Node *control, const Node // Can NOT include the match of a subtree when its memory state // is used by any of the other subtrees (input_mem == NodeSentinel) ) { -#ifndef PRODUCT // Print when we exclude matching due to different memory states at input-loads - if( PrintOpto && (Verbose && WizardMode) && (input_mem == NodeSentinel) - && !((mem!=(Node*)1) && m->is_Load() && m->in(MemNode::Memory) != mem) ) { + if (PrintOpto && (Verbose && WizardMode) && (input_mem == NodeSentinel) + && !((mem!=(Node*)1) && m->is_Load() && m->in(MemNode::Memory) != mem)) { tty->print_cr("invalid input_mem"); } -#endif // Switch to a register-only opcode; this value must be in a register // and cannot be subsumed as part of a larger instruction. s->DFA( m->ideal_reg(), m ); diff --git a/hotspot/src/share/vm/opto/movenode.cpp b/hotspot/src/share/vm/opto/movenode.cpp index 8fe9b0233be..ee797cf5d28 100644 --- a/hotspot/src/share/vm/opto/movenode.cpp +++ b/hotspot/src/share/vm/opto/movenode.cpp @@ -230,9 +230,7 @@ Node *CMoveINode::Ideal(PhaseGVN *phase, bool can_reshape) { // Convert to a bool (flipped) // Build int->bool conversion -#ifndef PRODUCT - if( PrintOpto ) tty->print_cr("CMOV to I2B"); -#endif + if (PrintOpto) { tty->print_cr("CMOV to I2B"); } Node *n = new Conv2BNode( cmp->in(1) ); if( flip ) n = new XorINode( phase->transform(n), phase->intcon(1) ); diff --git a/hotspot/src/share/vm/opto/output.cpp b/hotspot/src/share/vm/opto/output.cpp index 7b0c074f686..7d90d638ed4 100644 --- a/hotspot/src/share/vm/opto/output.cpp +++ b/hotspot/src/share/vm/opto/output.cpp @@ -91,13 +91,10 @@ void Compile::Output() { } // Break before main entry point - if( (_method && C->directive()->BreakAtExecuteOption) -#ifndef PRODUCT - ||(OptoBreakpoint && is_method_compilation()) - ||(OptoBreakpointOSR && is_osr_compilation()) - ||(OptoBreakpointC2R && !_method) -#endif - ) { + if ((_method && C->directive()->BreakAtExecuteOption) || + (OptoBreakpoint && is_method_compilation()) || + (OptoBreakpointOSR && is_osr_compilation()) || + (OptoBreakpointC2R && !_method) ) { // checking for _method means that OptoBreakpoint does not apply to // runtime stubs or frame converters _cfg->insert( entry, 1, new MachBreakpointNode() ); diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index 3a07d9f707c..58f74096bf2 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -958,12 +958,10 @@ void Parse::do_exits() { PPC64_ONLY(wrote_volatile() ||) (AlwaysSafeConstructors && wrote_fields()))) { _exits.insert_mem_bar(Op_MemBarRelease, alloc_with_final()); -#ifndef PRODUCT if (PrintOpto && (Verbose || WizardMode)) { method()->print_name(); tty->print_cr(" writes finals and needs a memory barrier"); } -#endif } // Any method can write a @Stable field; insert memory barriers after @@ -971,12 +969,10 @@ void Parse::do_exits() { // barrier there. if (wrote_stable()) { _exits.insert_mem_bar(Op_MemBarRelease, alloc_with_final()); -#ifndef PRODUCT if (PrintOpto && (Verbose || WizardMode)) { method()->print_name(); tty->print_cr(" writes @Stable and needs a memory barrier"); } -#endif } for (MergeMemStream mms(_exits.merged_memory()); mms.next_non_empty(); ) { diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp index eced1be6b92..f6adb5d6241 100644 --- a/hotspot/src/share/vm/opto/parse2.cpp +++ b/hotspot/src/share/vm/opto/parse2.cpp @@ -948,13 +948,11 @@ bool Parse::seems_stable_comparison() const { //-------------------------------repush_if_args-------------------------------- // Push arguments of an "if" bytecode back onto the stack by adjusting _sp. inline int Parse::repush_if_args() { -#ifndef PRODUCT if (PrintOpto && WizardMode) { tty->print("defending against excessive implicit null exceptions on %s @%d in ", Bytecodes::name(iter().cur_bc()), iter().cur_bci()); method()->print_name(); tty->cr(); } -#endif int bc_depth = - Bytecodes::depth(iter().cur_bc()); assert(bc_depth == 1 || bc_depth == 2, "only two kinds of branches"); DEBUG_ONLY(sync_jvms()); // argument(n) requires a synced jvms @@ -975,10 +973,9 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { float prob = branch_prediction(cnt, btest, target_bci, c); if (prob == PROB_UNKNOWN) { // (An earlier version of do_ifnull omitted this trap for OSR methods.) -#ifndef PRODUCT - if (PrintOpto && Verbose) - tty->print_cr("Never-taken edge stops compilation at bci %d",bci()); -#endif + if (PrintOpto && Verbose) { + tty->print_cr("Never-taken edge stops compilation at bci %d", bci()); + } repush_if_args(); // to gather stats on loop // We need to mark this branch as taken so that if we recompile we will // see that it is possible. In the tiered system the interpreter doesn't @@ -1057,10 +1054,9 @@ void Parse::do_if(BoolTest::mask btest, Node* c) { float untaken_prob = 1.0 - prob; if (prob == PROB_UNKNOWN) { -#ifndef PRODUCT - if (PrintOpto && Verbose) - tty->print_cr("Never-taken edge stops compilation at bci %d",bci()); -#endif + if (PrintOpto && Verbose) { + tty->print_cr("Never-taken edge stops compilation at bci %d", bci()); + } repush_if_args(); // to gather stats on loop // We need to mark this branch as taken so that if we recompile we will // see that it is possible. In the tiered system the interpreter doesn't diff --git a/hotspot/src/share/vm/opto/parse3.cpp b/hotspot/src/share/vm/opto/parse3.cpp index f37e31e9458..57b4718da38 100644 --- a/hotspot/src/share/vm/opto/parse3.cpp +++ b/hotspot/src/share/vm/opto/parse3.cpp @@ -213,11 +213,9 @@ void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) { // not need to mention the class index, since the class will // already have been loaded if we ever see a non-null value.) // uncommon_trap(iter().get_field_signature_index()); -#ifndef PRODUCT if (PrintOpto && (Verbose || WizardMode)) { method()->print_name(); tty->print_cr(" asserting nullness of field at bci: %d", bci()); } -#endif if (C->log() != NULL) { C->log()->elem("assert_null reason='field' klass='%d'", C->log()->identify(field->type())); diff --git a/hotspot/src/share/vm/opto/reg_split.cpp b/hotspot/src/share/vm/opto/reg_split.cpp index 6eae4e574ad..1a0d241bde0 100644 --- a/hotspot/src/share/vm/opto/reg_split.cpp +++ b/hotspot/src/share/vm/opto/reg_split.cpp @@ -506,10 +506,9 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) { // Initialize the split counts to zero splits.append(0); #endif -#ifndef PRODUCT - if( PrintOpto && WizardMode && lrgs(bidx)._was_spilled1 ) + if (PrintOpto && WizardMode && lrgs(bidx)._was_spilled1) { tty->print_cr("Warning, 2nd spill of L%d",bidx); -#endif + } } } diff --git a/hotspot/src/share/vm/opto/split_if.cpp b/hotspot/src/share/vm/opto/split_if.cpp index 40a762b03a3..71ad2f13481 100644 --- a/hotspot/src/share/vm/opto/split_if.cpp +++ b/hotspot/src/share/vm/opto/split_if.cpp @@ -390,13 +390,13 @@ void PhaseIdealLoop::handle_use( Node *use, Node *def, small_cache *cache, Node // Found an If getting its condition-code input from a Phi in the same block. // Split thru the Region. void PhaseIdealLoop::do_split_if( Node *iff ) { -#ifndef PRODUCT - if( PrintOpto && VerifyLoopOptimizations ) + if (PrintOpto && VerifyLoopOptimizations) { tty->print_cr("Split-if"); + } if (TraceLoopOpts) { tty->print_cr("SplitIf"); } -#endif + C->set_major_progress(); Node *region = iff->in(0); Node *region_dom = idom(region); diff --git a/hotspot/src/share/vm/opto/superword.cpp b/hotspot/src/share/vm/opto/superword.cpp index 2d1e2a4a0c3..5079b5ce979 100644 --- a/hotspot/src/share/vm/opto/superword.cpp +++ b/hotspot/src/share/vm/opto/superword.cpp @@ -276,7 +276,9 @@ void SuperWord::unrolling_analysis(int &local_loop_unroll_factor) { // stop looking, we already have the max vector to map to. if (cur_max_vector < local_loop_unroll_factor) { is_slp = false; - NOT_PRODUCT(if (TraceSuperWordLoopUnrollAnalysis) tty->print_cr("slp analysis fails: unroll limit greater than max vector\n")); + if (TraceSuperWordLoopUnrollAnalysis) { + tty->print_cr("slp analysis fails: unroll limit greater than max vector\n"); + } break; } @@ -389,11 +391,9 @@ void SuperWord::SLP_extract() { if (_do_vector_loop) { if (_packset.length() == 0) { -#ifndef PRODUCT if (TraceSuperWord) { tty->print_cr("\nSuperWord::_do_vector_loop DFA could not build packset, now trying to build anyway"); } -#endif pack_parallel(); } } @@ -560,7 +560,9 @@ void SuperWord::find_adjacent_refs() { } best_align_to_mem_ref = find_align_to_ref(memops); if (best_align_to_mem_ref == NULL) { - NOT_PRODUCT(if (TraceSuperWord) tty->print_cr("SuperWord::find_adjacent_refs(): best_align_to_mem_ref == NULL");) + if (TraceSuperWord) { + tty->print_cr("SuperWord::find_adjacent_refs(): best_align_to_mem_ref == NULL"); + } break; } best_iv_adjustment = get_iv_adjustment(best_align_to_mem_ref); @@ -582,12 +584,10 @@ void SuperWord::find_adjacent_refs() { } // while (memops.size() != 0 set_align_to_ref(best_align_to_mem_ref); -#ifndef PRODUCT if (TraceSuperWord) { tty->print_cr("\nAfter find_adjacent_refs"); print_packset(); } -#endif } #ifndef PRODUCT @@ -874,7 +874,7 @@ void SuperWord::dependence_graph() { _dg.make_edge(s1, slice_sink); } } -#ifndef PRODUCT + if (TraceSuperWord) { tty->print_cr("\nDependence graph for slice: %d", n->_idx); for (int q = 0; q < _nlist.length(); q++) { @@ -882,11 +882,10 @@ void SuperWord::dependence_graph() { } tty->cr(); } -#endif + _nlist.clear(); } -#ifndef PRODUCT if (TraceSuperWord) { tty->print_cr("\ndisjoint_ptrs: %s", _disjoint_ptrs.length() > 0 ? "" : "NONE"); for (int r = 0; r < _disjoint_ptrs.length(); r++) { @@ -895,7 +894,7 @@ void SuperWord::dependence_graph() { } tty->cr(); } -#endif + } //---------------------------mem_slice_preds--------------------------- @@ -912,7 +911,9 @@ void SuperWord::mem_slice_preds(Node* start, Node* stop, GrowableArray &p if (out->is_Load()) { if (in_bb(out)) { preds.push(out); - NOT_PRODUCT(if (TraceSuperWord && Verbose) tty->print_cr("SuperWord::mem_slice_preds: added pred(%d)", out->_idx);) + if (TraceSuperWord && Verbose) { + tty->print_cr("SuperWord::mem_slice_preds: added pred(%d)", out->_idx); + } } } else { // FIXME @@ -931,7 +932,9 @@ void SuperWord::mem_slice_preds(Node* start, Node* stop, GrowableArray &p }//for if (n == stop) break; preds.push(n); - NOT_PRODUCT(if (TraceSuperWord && Verbose) tty->print_cr("SuperWord::mem_slice_preds: added pred(%d)", n->_idx);) + if (TraceSuperWord && Verbose) { + tty->print_cr("SuperWord::mem_slice_preds: added pred(%d)", n->_idx); + } prev = n; assert(n->is_Mem(), "unexpected node %s", n->Name()); n = n->in(MemNode::Memory); @@ -1123,12 +1126,10 @@ void SuperWord::extend_packlist() { } } -#ifndef PRODUCT if (TraceSuperWord) { tty->print_cr("\nAfter extend_packlist"); print_packset(); } -#endif } //------------------------------follow_use_defs--------------------------- @@ -1412,12 +1413,10 @@ void SuperWord::combine_packs() { } } -#ifndef PRODUCT if (TraceSuperWord) { tty->print_cr("\nAfter combine_packs"); print_packset(); } -#endif } //-----------------------------construct_my_pack_map-------------------------- @@ -2244,7 +2243,9 @@ void SuperWord::output() { if (cl->has_passed_slp()) { uint slp_max_unroll_factor = cl->slp_max_unroll(); if (slp_max_unroll_factor == max_vlen) { - NOT_PRODUCT(if (TraceSuperWordLoopUnrollAnalysis) tty->print_cr("vector loop(unroll=%d, len=%d)\n", max_vlen, max_vlen_in_bytes*BitsPerByte)); + if (TraceSuperWordLoopUnrollAnalysis) { + tty->print_cr("vector loop(unroll=%d, len=%d)\n", max_vlen, max_vlen_in_bytes*BitsPerByte); + } // For atomic unrolled loops which are vector mapped, instigate more unrolling. cl->set_notpassed_slp(); // if vector resources are limited, do not allow additional unrolling @@ -2653,10 +2654,10 @@ void SuperWord::compute_max_depth() { } ct++; } while (again); -#ifndef PRODUCT - if (TraceSuperWord && Verbose) + + if (TraceSuperWord && Verbose) { tty->print_cr("compute_max_depth iterated: %d times", ct); -#endif + } } //-------------------------compute_vector_element_type----------------------- @@ -2667,10 +2668,9 @@ void SuperWord::compute_max_depth() { // Normally the type of the add is integer, but for packed character // operations the type of the add needs to be char. void SuperWord::compute_vector_element_type() { -#ifndef PRODUCT - if (TraceSuperWord && Verbose) + if (TraceSuperWord && Verbose) { tty->print_cr("\ncompute_velt_type:"); -#endif + } // Initial type for (int i = 0; i < _block.length(); i++) { @@ -2761,7 +2761,9 @@ int SuperWord::memory_alignment(MemNode* s, int iv_adjust) { offset += iv_adjust*p.memory_size(); int off_rem = offset % vw; int off_mod = off_rem >= 0 ? off_rem : off_rem + vw; - NOT_PRODUCT(if(TraceSuperWord && Verbose) tty->print_cr("SWPointer::memory_alignment: off_rem = %d, off_mod = %d", off_rem, off_mod);) + if (TraceSuperWord && Verbose) { + tty->print_cr("SWPointer::memory_alignment: off_rem = %d, off_mod = %d", off_rem, off_mod); + } return off_mod; } @@ -4049,11 +4051,9 @@ int SuperWord::mark_generations() { }//for (int i... if (_ii_first == -1 || _ii_last == -1) { -#ifndef PRODUCT if (TraceSuperWord && Verbose) { tty->print_cr("SuperWord::mark_generations unknown error, something vent wrong"); } -#endif return -1; // something vent wrong } // collect nodes in the first and last generations @@ -4086,11 +4086,9 @@ int SuperWord::mark_generations() { }//for if (found == false) { -#ifndef PRODUCT if (TraceSuperWord && Verbose) { tty->print_cr("SuperWord::mark_generations: Cannot build order of iterations - no dependent Store for %d", nd->_idx); } -#endif _ii_order.clear(); return -1; } @@ -4156,11 +4154,10 @@ bool SuperWord::fix_commutative_inputs(Node* gold, Node* fix) { return true; } -#ifndef PRODUCT if (TraceSuperWord && Verbose) { tty->print_cr("SuperWord::fix_commutative_inputs: cannot fix node %d", fix->_idx); } -#endif + return false; } @@ -4227,11 +4224,9 @@ bool SuperWord::hoist_loads_in_graph() { for (int i = 0; i < _mem_slice_head.length(); i++) { Node* n = _mem_slice_head.at(i); if ( !in_bb(n) || !n->is_Phi() || n->bottom_type() != Type::MEMORY) { -#ifndef PRODUCT if (TraceSuperWord && Verbose) { tty->print_cr("SuperWord::hoist_loads_in_graph: skipping unexpected node n=%d", n->_idx); } -#endif continue; } @@ -4278,11 +4273,10 @@ bool SuperWord::hoist_loads_in_graph() { restart(); // invalidate all basic structures, since we rebuilt the graph -#ifndef PRODUCT if (TraceSuperWord && Verbose) { tty->print_cr("\nSuperWord::hoist_loads_in_graph() the graph was rebuilt, all structures invalidated and need rebuild"); } -#endif + return true; } diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 4a8a5a47165..52c6f20afed 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -3899,7 +3899,7 @@ void TestG1BiasedArray_test(); void TestBufferingOopClosure_test(); void TestCodeCacheRemSet_test(); void FreeRegionList_test(); -void test_memset_with_concurrent_readers(); +void test_memset_with_concurrent_readers() NOT_DEBUG_RETURN; void TestPredictions_test(); #endif diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 3339c01f404..b77b7a76ee4 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -456,7 +456,7 @@ const char* Arguments::real_flag_name(const char *flag_name) { return flag_name; } -#ifndef PRODUCT +#ifdef ASSERT static bool lookup_special_flag(const char *flag_name, size_t skip_index) { for (size_t i = 0; special_jvm_flags[i].name != NULL; i++) { if ((i != skip_index) && (strcmp(special_jvm_flags[i].name, flag_name) == 0)) { diff --git a/hotspot/src/share/vm/runtime/globals.cpp b/hotspot/src/share/vm/runtime/globals.cpp index 3357fcfc323..01bbee0dbd4 100644 --- a/hotspot/src/share/vm/runtime/globals.cpp +++ b/hotspot/src/share/vm/runtime/globals.cpp @@ -538,59 +538,57 @@ const char* Flag::flag_error_str(Flag::Error error) { // 4991491 do not "optimize out" the was_set false values: omitting them // tickles a Microsoft compiler bug causing flagTable to be malformed -#define NAME(name) NOT_PRODUCT(&name) PRODUCT_ONLY(&CONST_##name) +#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_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 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_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), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DEVELOP) }, -#define RUNTIME_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(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), NAME(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_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(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), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DEVELOP | 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_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_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | 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_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) }, +#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_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(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), NAME(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), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C1 | Flag::KIND_NOT_PRODUCT) }, +#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_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_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), NAME(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), NAME(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), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_C2 | 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_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), NAME(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), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | 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) }, -#define SHARK_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_PRODUCT) }, -#define SHARK_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, -#define SHARK_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DIAGNOSTIC) }, -#define SHARK_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DEVELOP) }, -#define SHARK_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, -#define SHARK_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_NOT_PRODUCT) }, +#define SHARK_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_PRODUCT) }, +#define SHARK_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define SHARK_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DIAGNOSTIC) }, +#define SHARK_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DEVELOP) }, +#define SHARK_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define SHARK_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_NOT_PRODUCT) }, static Flag flagTable[] = { RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \ diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index da8c3427707..146efac6069 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -4293,9 +4293,9 @@ public: #define DECLARE_MANAGEABLE_FLAG(type, name, value, doc) extern "C" type name; #define DECLARE_PRODUCT_RW_FLAG(type, name, value, doc) extern "C" type name; #ifdef PRODUCT -#define DECLARE_DEVELOPER_FLAG(type, name, value, doc) extern "C" type CONST_##name; const type name = value; -#define DECLARE_PD_DEVELOPER_FLAG(type, name, doc) extern "C" type CONST_##name; const type name = pd_##name; -#define DECLARE_NOTPRODUCT_FLAG(type, name, value, doc) extern "C" type CONST_##name; +#define DECLARE_DEVELOPER_FLAG(type, name, value, doc) const type name = value; +#define DECLARE_PD_DEVELOPER_FLAG(type, name, doc) const type name = pd_##name; +#define DECLARE_NOTPRODUCT_FLAG(type, name, value, doc) const type name = value; #else #define DECLARE_DEVELOPER_FLAG(type, name, value, doc) extern "C" type name; #define DECLARE_PD_DEVELOPER_FLAG(type, name, doc) extern "C" type name; @@ -4316,9 +4316,9 @@ public: #define MATERIALIZE_MANAGEABLE_FLAG(type, name, value, doc) type name = value; #define MATERIALIZE_PRODUCT_RW_FLAG(type, name, value, doc) type name = value; #ifdef PRODUCT -#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc) type CONST_##name = value; -#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc) type CONST_##name = pd_##name; -#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc) type CONST_##name = value; +#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc) +#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc) +#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc) #else #define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc) type name = value; #define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc) type name = pd_##name; From eee22b283d697d1876c0b1666f33c11e8165bd27 Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Thu, 12 Nov 2015 13:30:35 +0100 Subject: [PATCH 028/260] 8142387: Various JVMCI tests fail on unexpected exception Reviewed-by: iignatyev, twisti --- .../jvmci/errors/CodeInstallerTest.java | 6 +++ .../errors/TestInvalidCompilationResult.java | 40 +++++++++---------- .../jvmci/errors/TestInvalidDebugInfo.java | 4 +- .../jvmci/errors/TestInvalidOopMap.java | 4 +- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/hotspot/test/compiler/jvmci/errors/CodeInstallerTest.java b/hotspot/test/compiler/jvmci/errors/CodeInstallerTest.java index aae95940098..56b32cd10c6 100644 --- a/hotspot/test/compiler/jvmci/errors/CodeInstallerTest.java +++ b/hotspot/test/compiler/jvmci/errors/CodeInstallerTest.java @@ -71,6 +71,12 @@ public class CodeInstallerTest { codeCache.addCode(dummyMethod, result, null, null); } + protected CompilationResult createEmptyCompilationResult() { + CompilationResult ret = new CompilationResult(); + ret.setTotalFrameSize(0); + return ret; + } + protected Register getRegister(PlatformKind kind, int index) { Register[] allRegs = arch.getAvailableValueRegisters(); for (int i = 0; i < allRegs.length; i++) { diff --git a/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java b/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java index 5e9ab133ffd..89d6114cccd 100644 --- a/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java +++ b/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java @@ -25,7 +25,7 @@ * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" * @compile CodeInstallerTest.java - * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.errors.TestInvalidCompilationResult + * @run junit/othervm -da:jdk.vm.ci... -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.errors.TestInvalidCompilationResult */ package compiler.jvmci.errors; @@ -82,21 +82,21 @@ public class TestInvalidCompilationResult extends CodeInstallerTest { @Test(expected = JVMCIError.class) public void testInvalidAssumption() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); result.setAssumptions(new Assumption[]{new InvalidAssumption()}); installCode(result); } @Test(expected = JVMCIError.class) public void testInvalidAlignment() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); result.getDataSection().insertData(new Data(7, 1, DataBuilder.zero(1))); installCode(result); } @Test(expected = NullPointerException.class) public void testNullDataPatchInDataSection() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); Data data = new Data(1, 1, (buffer, patch) -> { patch.accept(null); buffer.put((byte) 0); @@ -107,7 +107,7 @@ public class TestInvalidCompilationResult extends CodeInstallerTest { @Test(expected = NullPointerException.class) public void testNullReferenceInDataSection() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); Data data = new Data(1, 1, (buffer, patch) -> { patch.accept(new DataPatch(buffer.position(), null)); buffer.put((byte) 0); @@ -118,7 +118,7 @@ public class TestInvalidCompilationResult extends CodeInstallerTest { @Test(expected = JVMCIError.class) public void testInvalidDataSectionReference() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); DataSectionReference ref = result.getDataSection().insertData(new Data(1, 1, DataBuilder.zero(1))); Data data = new Data(1, 1, (buffer, patch) -> { patch.accept(new DataPatch(buffer.position(), ref)); @@ -130,7 +130,7 @@ public class TestInvalidCompilationResult extends CodeInstallerTest { @Test(expected = JVMCIError.class) public void testInvalidNarrowMethodInDataSection() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); HotSpotConstant c = (HotSpotConstant) dummyMethod.getEncoding(); Data data = new Data(4, 4, (buffer, patch) -> { patch.accept(new DataPatch(buffer.position(), new ConstantReference((VMConstant) c.compress()))); @@ -142,7 +142,7 @@ public class TestInvalidCompilationResult extends CodeInstallerTest { @Test(expected = NullPointerException.class) public void testNullConstantInDataSection() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); Data data = new Data(1, 1, (buffer, patch) -> { patch.accept(new DataPatch(buffer.position(), new ConstantReference(null))); }); @@ -152,7 +152,7 @@ public class TestInvalidCompilationResult extends CodeInstallerTest { @Test(expected = JVMCIError.class) public void testInvalidConstantInDataSection() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); Data data = new Data(1, 1, (buffer, patch) -> { patch.accept(new DataPatch(buffer.position(), new ConstantReference(new InvalidVMConstant()))); }); @@ -162,35 +162,35 @@ public class TestInvalidCompilationResult extends CodeInstallerTest { @Test(expected = NullPointerException.class) public void testNullReferenceInCode() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); result.recordDataPatch(0, null); installCode(result); } @Test(expected = NullPointerException.class) public void testNullConstantInCode() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); result.recordDataPatch(0, new ConstantReference(null)); installCode(result); } @Test(expected = JVMCIError.class) public void testInvalidConstantInCode() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); result.recordDataPatch(0, new ConstantReference(new InvalidVMConstant())); installCode(result); } @Test(expected = JVMCIError.class) public void testInvalidReference() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); result.recordDataPatch(0, new InvalidReference()); installCode(result); } @Test(expected = JVMCIError.class) public void testOutOfBoundsDataSectionReference() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); DataSectionReference ref = new DataSectionReference(); ref.setOffset(0x1000); result.recordDataPatch(0, ref); @@ -199,42 +199,42 @@ public class TestInvalidCompilationResult extends CodeInstallerTest { @Test(expected = JVMCIError.class) public void testInvalidMark() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); result.recordMark(0, new Object()); installCode(result); } @Test(expected = JVMCIError.class) public void testInvalidMarkInt() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); result.recordMark(0, -1); installCode(result); } @Test(expected = NullPointerException.class) public void testNullInfopoint() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); result.addInfopoint(null); installCode(result); } @Test(expected = JVMCIError.class) public void testUnknownInfopointReason() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); result.addInfopoint(new Infopoint(0, null, InfopointReason.UNKNOWN)); installCode(result); } @Test(expected = JVMCIError.class) public void testInfopointMissingDebugInfo() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); result.addInfopoint(new Infopoint(0, null, InfopointReason.METHOD_START)); installCode(result); } @Test(expected = JVMCIError.class) public void testSafepointMissingDebugInfo() { - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); result.addInfopoint(new Infopoint(0, null, InfopointReason.SAFEPOINT)); installCode(result); } diff --git a/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java b/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java index e8a0d1f536d..cc387ed195f 100644 --- a/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java +++ b/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java @@ -25,7 +25,7 @@ * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" * @compile CodeInstallerTest.java - * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.errors.TestInvalidDebugInfo + * @run junit/othervm -da:jdk.vm.ci... -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.errors.TestInvalidDebugInfo */ package compiler.jvmci.errors; @@ -68,7 +68,7 @@ public class TestInvalidDebugInfo extends CodeInstallerTest { DebugInfo info = new DebugInfo(frame, vobj); info.setReferenceMap(new HotSpotReferenceMap(new Location[0], new Location[0], new int[0], 8)); - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); result.addInfopoint(new Infopoint(0, info, InfopointReason.SAFEPOINT)); installCode(result); } diff --git a/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java b/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java index 133d659f622..6291c06a7c2 100644 --- a/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java +++ b/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java @@ -25,7 +25,7 @@ * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" * @compile CodeInstallerTest.java - * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.errors.TestInvalidOopMap + * @run junit/othervm -da:jdk.vm.ci... -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.errors.TestInvalidOopMap */ package compiler.jvmci.errors; @@ -61,7 +61,7 @@ public class TestInvalidOopMap extends CodeInstallerTest { DebugInfo info = new DebugInfo(pos); info.setReferenceMap(refMap); - CompilationResult result = new CompilationResult(); + CompilationResult result = createEmptyCompilationResult(); result.addInfopoint(new Infopoint(0, info, InfopointReason.SAFEPOINT)); installCode(result); } From 5ea0e0d06679627b053c53da42933cb5951dff12 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Fri, 13 Nov 2015 10:08:44 +0100 Subject: [PATCH 029/260] 8141585: CompilerDirectivesDCMDTest intermittently SEGVs in MethodMatcher::matcher Missing methodHandle and read before lock Reviewed-by: twisti --- hotspot/src/share/vm/compiler/compileBroker.cpp | 16 +++++++++------- .../src/share/vm/compiler/compilerDirectives.cpp | 6 ++++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 503b848ce70..ff97e33dbcc 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -1676,13 +1676,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { bool should_break = false; int task_level = task->comp_level(); - // Look up matching directives - DirectiveSet* directive = DirectivesStack::getMatchingDirective(task->method(), compiler(task_level)); - - should_break = directive->BreakAtExecuteOption || task->check_break_at_flags(); - if (should_log && !directive->LogOption) { - should_log = false; - } + DirectiveSet* directive; { // create the handle inside it's own block so it can't // accidentally be referenced once the thread transitions to @@ -1691,12 +1685,20 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { methodHandle method(thread, task->method()); assert(!method->is_native(), "no longer compile natives"); + // Look up matching directives + directive = DirectivesStack::getMatchingDirective(method, compiler(task_level)); + // Save information about this method in case of failure. set_last_compile(thread, method, is_osr, task_level); DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, compiler_name(task_level)); } + should_break = directive->BreakAtExecuteOption || task->check_break_at_flags(); + if (should_log && !directive->LogOption) { + should_log = false; + } + // Allocate a new set of JNI handles. push_jni_handle_block(); Method* target_handle = task->method(); diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.cpp b/hotspot/src/share/vm/compiler/compilerDirectives.cpp index 20696ff0aa1..4d10aec5307 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.cpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.cpp @@ -527,12 +527,14 @@ void DirectivesStack::release(CompilerDirectives* dir) { DirectiveSet* DirectivesStack::getMatchingDirective(methodHandle method, AbstractCompiler *comp) { assert(_depth > 0, "Must never be empty"); - CompilerDirectives* dir = _top; - assert(dir != NULL, "Must be initialized"); DirectiveSet* match = NULL; { MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag); + + CompilerDirectives* dir = _top; + assert(dir != NULL, "Must be initialized"); + while (dir != NULL) { if (dir->is_default_directive() || dir->match(method)) { match = dir->get_for(comp); From 6de50f10f5b6c339e848f3c9f9d3be3191fe165d Mon Sep 17 00:00:00 2001 From: Konstantin Shefov Date: Fri, 13 Nov 2015 18:14:41 +0300 Subject: [PATCH 030/260] 8131778: java disables UseAES flag when using VIS=2 on sparc Reviewed-by: iignatyev, kvn --- hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp | 44 +++++++++---------- hotspot/src/cpu/x86/vm/vm_version_x86.cpp | 44 ++++++++++++------- 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index e942940d49b..1c42f501bd5 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -229,35 +229,35 @@ void VM_Version::initialize() { // SPARC T4 and above should have support for AES instructions if (has_aes()) { - if (UseVIS > 2) { // AES intrinsics use MOVxTOd/MOVdTOx which are VIS3 - if (FLAG_IS_DEFAULT(UseAES)) { - FLAG_SET_DEFAULT(UseAES, true); + if (FLAG_IS_DEFAULT(UseAES)) { + FLAG_SET_DEFAULT(UseAES, true); + } + if (!UseAES) { + if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { + warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled."); } - if (FLAG_IS_DEFAULT(UseAESIntrinsics)) { - FLAG_SET_DEFAULT(UseAESIntrinsics, true); - } - // we disable both the AES flags if either of them is disabled on the command line - if (!UseAES || !UseAESIntrinsics) { - FLAG_SET_DEFAULT(UseAES, false); + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + } else { + // The AES intrinsic stubs require AES instruction support (of course) + // but also require VIS3 mode or higher for instructions it use. + if (UseVIS > 2) { + if (FLAG_IS_DEFAULT(UseAESIntrinsics)) { + FLAG_SET_DEFAULT(UseAESIntrinsics, true); + } + } else { + if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { + warning("SPARC AES intrinsics require VIS3 instructions. Intrinsics will be disabled."); + } FLAG_SET_DEFAULT(UseAESIntrinsics, false); } - } else { - if (UseAES || UseAESIntrinsics) { - warning("SPARC AES intrinsics require VIS3 instruction support. Intrinsics will be disabled."); - if (UseAES) { - FLAG_SET_DEFAULT(UseAES, false); - } - if (UseAESIntrinsics) { - FLAG_SET_DEFAULT(UseAESIntrinsics, false); - } - } } } else if (UseAES || UseAESIntrinsics) { - warning("AES instructions are not available on this CPU"); - if (UseAES) { + if (UseAES && !FLAG_IS_DEFAULT(UseAES)) { + warning("AES instructions are not available on this CPU"); FLAG_SET_DEFAULT(UseAES, false); } - if (UseAESIntrinsics) { + if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { + warning("AES intrinsics are not available on this CPU"); FLAG_SET_DEFAULT(UseAESIntrinsics, false); } } diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index e66fcc51153..e9d8c257de5 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -632,12 +632,36 @@ void VM_Version::get_processor_features() { // Use AES instructions if available. if (supports_aes()) { if (FLAG_IS_DEFAULT(UseAES)) { - UseAES = true; + FLAG_SET_DEFAULT(UseAES, true); } - } else if (UseAES) { - if (!FLAG_IS_DEFAULT(UseAES)) + if (!UseAES) { + if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { + warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled."); + } + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + } else { + if (UseSSE > 2) { + if (FLAG_IS_DEFAULT(UseAESIntrinsics)) { + FLAG_SET_DEFAULT(UseAESIntrinsics, true); + } + } else { + // The AES intrinsic stubs require AES instruction support (of course) + // but also require sse3 mode or higher for instructions it use. + if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { + warning("X86 AES intrinsics require SSE3 instructions or higher. Intrinsics will be disabled."); + } + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + } + } + } else if (UseAES || UseAESIntrinsics) { + if (UseAES && !FLAG_IS_DEFAULT(UseAES)) { warning("AES instructions are not available on this CPU"); - FLAG_SET_DEFAULT(UseAES, false); + FLAG_SET_DEFAULT(UseAES, false); + } + if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { + warning("AES intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + } } // Use CLMUL instructions if available. @@ -673,18 +697,6 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); } - // The AES intrinsic stubs require AES instruction support (of course) - // but also require sse3 mode for instructions it use. - if (UseAES && (UseSSE > 2)) { - if (FLAG_IS_DEFAULT(UseAESIntrinsics)) { - UseAESIntrinsics = true; - } - } else if (UseAESIntrinsics) { - if (!FLAG_IS_DEFAULT(UseAESIntrinsics)) - warning("AES intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseAESIntrinsics, false); - } - // GHASH/GCM intrinsics if (UseCLMUL && (UseSSE > 2)) { if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { From c9b5f58d7f5f3e63d7cc072d2d2f27671faa753c Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 16 Nov 2015 08:03:24 +0100 Subject: [PATCH 031/260] 8142500: missing null checks in IfNode::has_only_uncommon_traps IfNode::has_only_uncommon_traps needs to null-check the callers. Reviewed-by: kvn, roland, rbackman --- hotspot/src/share/vm/opto/ifnode.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/opto/ifnode.cpp b/hotspot/src/share/vm/opto/ifnode.cpp index b43b35f1610..c4ee72f5c1d 100644 --- a/hotspot/src/share/vm/opto/ifnode.cpp +++ b/hotspot/src/share/vm/opto/ifnode.cpp @@ -806,7 +806,11 @@ bool IfNode::has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNod // that the call stacks are equal for both JVMStates. JVMState* dom_caller = dom_unc->jvms()->caller(); JVMState* caller = unc->jvms()->caller(); - if (!dom_caller->same_calls_as(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 From 5c32c8d2ab5316f74667f9d21ed6495cd93962dd Mon Sep 17 00:00:00 2001 From: Zoltan Majo Date: Mon, 16 Nov 2015 09:42:20 +0100 Subject: [PATCH 032/260] 8140327: segfault on solaris-amd64 with "-XX:CompilerThreadStackSize=1" option Update range for the CompilerThreadStackSize flag. Remove flag from testing. Reviewed-by: kvn --- hotspot/src/share/vm/runtime/globals.hpp | 2 +- .../OptionsValidation/TestOptionsWithRanges.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 146efac6069..c492a0c81a1 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3563,7 +3563,7 @@ public: \ product_pd(intx, CompilerThreadStackSize, \ "Compiler Thread Stack Size (in Kbytes)") \ - range(0, max_intx) \ + range(0, max_intx /(1 * K)) \ \ develop_pd(size_t, JVMInvokeMethodSlack, \ "Stack space (bytes) required for JVM_InvokeMethod to complete") \ diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java index 38b3239eb14..31b878d8734 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java @@ -58,6 +58,13 @@ public class TestOptionsWithRanges { */ allOptionsAsMap.remove("ThreadStackSize"); + /* + * Remove the flag controlling the size of the stack because the + * flag has direct influence on the physical memory usage of + * the VM. + */ + allOptionsAsMap.remove("CompilerThreadStackSize"); + /* * Exclude MallocMaxTestWords as it is expected to exit VM at small values (>=0) */ From baaa8f79ed93d4dc1444fed81599ab0f7c2dd395 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Mon, 16 Nov 2015 09:55:25 +0100 Subject: [PATCH 033/260] 8042997: Make intrinsic some or all check index/range methods Objects.checkIndex() intrinsic Reviewed-by: vlivanov, shade --- hotspot/src/share/vm/classfile/vmSymbols.hpp | 4 ++ hotspot/src/share/vm/opto/c2compiler.cpp | 1 + hotspot/src/share/vm/opto/ifnode.cpp | 6 +-- hotspot/src/share/vm/opto/library_call.cpp | 50 ++++++++++++++++++++ hotspot/src/share/vm/opto/loopPredicate.cpp | 2 +- hotspot/src/share/vm/opto/loopnode.cpp | 6 +++ 6 files changed, 65 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index f0c8c30cdb8..1328c90763d 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -109,6 +109,7 @@ template(java_io_ByteArrayInputStream, "java/io/ByteArrayInputStream") \ template(java_io_Serializable, "java/io/Serializable") \ template(java_util_Arrays, "java/util/Arrays") \ + template(java_util_Objects, "java/util/Objects") \ template(java_util_Properties, "java/util/Properties") \ template(java_util_Vector, "java/util/Vector") \ template(java_util_AbstractList, "java/util/AbstractList") \ @@ -883,6 +884,9 @@ do_intrinsic(_equalsL, java_lang_StringLatin1,equals_name, equalsB_signature, F_S) \ do_intrinsic(_equalsU, java_lang_StringUTF16, equals_name, equalsB_signature, F_S) \ \ + do_intrinsic(_Objects_checkIndex, java_util_Objects, checkIndex_name, Objects_checkIndex_signature, F_S) \ + do_signature(Objects_checkIndex_signature, "(IILjava/util/function/BiFunction;)I") \ + \ do_class(java_nio_Buffer, "java/nio/Buffer") \ do_intrinsic(_checkIndex, java_nio_Buffer, checkIndex_name, int_int_signature, F_R) \ do_name( checkIndex_name, "checkIndex") \ diff --git a/hotspot/src/share/vm/opto/c2compiler.cpp b/hotspot/src/share/vm/opto/c2compiler.cpp index 7b4dbd93cf0..7c5c38e09e4 100644 --- a/hotspot/src/share/vm/opto/c2compiler.cpp +++ b/hotspot/src/share/vm/opto/c2compiler.cpp @@ -451,6 +451,7 @@ bool C2Compiler::is_intrinsic_supported(methodHandle method, bool is_virtual) { case vmIntrinsics::_updateByteBufferAdler32: case vmIntrinsics::_profileBoolean: case vmIntrinsics::_isCompileConstant: + case vmIntrinsics::_Objects_checkIndex: break; default: return false; diff --git a/hotspot/src/share/vm/opto/ifnode.cpp b/hotspot/src/share/vm/opto/ifnode.cpp index b43b35f1610..8c35cc8e68e 100644 --- a/hotspot/src/share/vm/opto/ifnode.cpp +++ b/hotspot/src/share/vm/opto/ifnode.cpp @@ -485,7 +485,7 @@ ProjNode* IfNode::range_check_trap_proj(int& flip_test, Node*& l, Node*& r) { return NULL; } if (l->is_top()) return NULL; // Top input means dead test - if (r->Opcode() != Op_LoadRange) return NULL; + if (r->Opcode() != Op_LoadRange && !is_RangeCheck()) return NULL; // We have recognized one of these forms: // Flip 1: If (Bool[<] CmpU(l, LoadRange)) ... @@ -525,9 +525,9 @@ int RangeCheckNode::is_range_check(Node* &range, Node* &index, jint &offset) { return 0; } else if (l->Opcode() == Op_AddI) { if ((off = l->in(1)->find_int_con(0)) != 0) { - ind = l->in(2); + ind = l->in(2)->uncast(); } else if ((off = l->in(2)->find_int_con(0)) != 0) { - ind = l->in(1); + ind = l->in(1)->uncast(); } } else if ((off = l->find_int_con(-1)) >= 0) { // constant offset with no variable index diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index ffec41c9ff7..dd753e6bbbf 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -256,6 +256,7 @@ class LibraryCallKit : public GraphKit { bool inline_native_getLength(); bool inline_array_copyOf(bool is_copyOfRange); bool inline_array_equals(StrIntrinsicNode::ArgEnc ae); + bool inline_objects_checkIndex(); void copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, bool is_array, bool card_mark); bool inline_native_clone(bool is_virtual); bool inline_native_Reflection_getCallerClass(); @@ -647,6 +648,7 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_copyOfRange: return inline_array_copyOf(true); case vmIntrinsics::_equalsB: return inline_array_equals(StrIntrinsicNode::LL); case vmIntrinsics::_equalsC: return inline_array_equals(StrIntrinsicNode::UU); + case vmIntrinsics::_Objects_checkIndex: return inline_objects_checkIndex(); case vmIntrinsics::_clone: return inline_native_clone(intrinsic()->is_virtual()); case vmIntrinsics::_isAssignableFrom: return inline_native_subtype_check(); @@ -1045,6 +1047,54 @@ bool LibraryCallKit::inline_hasNegatives() { return true; } +bool LibraryCallKit::inline_objects_checkIndex() { + Node* index = argument(0); + Node* length = argument(1); + if (too_many_traps(Deoptimization::Reason_intrinsic) || too_many_traps(Deoptimization::Reason_range_check)) { + return false; + } + + Node* len_pos_cmp = _gvn.transform(new CmpINode(length, intcon(0))); + Node* len_pos_bol = _gvn.transform(new BoolNode(len_pos_cmp, BoolTest::ge)); + + { + BuildCutout unless(this, len_pos_bol, PROB_MAX); + uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_make_not_entrant); + } + + if (stopped()) { + return false; + } + + Node* rc_cmp = _gvn.transform(new CmpUNode(index, length)); + BoolTest::mask btest = BoolTest::lt; + Node* rc_bool = _gvn.transform(new BoolNode(rc_cmp, btest)); + RangeCheckNode* rc = new RangeCheckNode(control(), rc_bool, PROB_MAX, COUNT_UNKNOWN); + _gvn.set_type(rc, rc->Value(&_gvn)); + if (!rc_bool->is_Con()) { + record_for_igvn(rc); + } + set_control(_gvn.transform(new IfTrueNode(rc))); + { + PreserveJVMState pjvms(this); + set_control(_gvn.transform(new IfFalseNode(rc))); + uncommon_trap(Deoptimization::Reason_range_check, + Deoptimization::Action_make_not_entrant); + } + + if (stopped()) { + return false; + } + + Node* result = new CastIINode(index, TypeInt::make(0, _gvn.type(length)->is_int()->_hi, Type::WidenMax)); + result->set_req(0, control()); + result = _gvn.transform(result); + set_result(result); + replace_in_map(index, result); + return true; +} + //------------------------------inline_string_indexOf------------------------ bool LibraryCallKit::inline_string_indexOf(StrIntrinsicNode::ArgEnc ae) { if (!Matcher::has_match_rule(Op_StrIndexOf) || !UseSSE42Intrinsics) { diff --git a/hotspot/src/share/vm/opto/loopPredicate.cpp b/hotspot/src/share/vm/opto/loopPredicate.cpp index 6ed9e9f5006..9cc6961931e 100644 --- a/hotspot/src/share/vm/opto/loopPredicate.cpp +++ b/hotspot/src/share/vm/opto/loopPredicate.cpp @@ -569,7 +569,7 @@ bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invari return false; } Node* range = cmp->in(2); - if (range->Opcode() != Op_LoadRange) { + if (range->Opcode() != Op_LoadRange && !iff->is_RangeCheck()) { const TypeInt* tint = phase->_igvn.type(range)->isa_int(); if (tint == NULL || tint->empty() || tint->_lo < 0) { // Allow predication on positive values that aren't LoadRanges. diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp index 78f54006d91..953364397ab 100644 --- a/hotspot/src/share/vm/opto/loopnode.cpp +++ b/hotspot/src/share/vm/opto/loopnode.cpp @@ -329,6 +329,9 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { Node* phi_incr = NULL; // Trip-counter increment must be commutative & associative. + if (incr->Opcode() == Op_CastII) { + incr = incr->in(1); + } if (incr->is_Phi()) { if (incr->as_Phi()->region() != x || incr->req() != 3) return false; // Not simple trip counter expression @@ -356,6 +359,9 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { xphi = stride; stride = tmp; } + if (xphi->Opcode() == Op_CastII) { + xphi = xphi->in(1); + } // Stride must be constant int stride_con = stride->get_int(); if (stride_con == 0) From 8ac86c17f800295ac87b41441c84feebbab33d75 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 16 Nov 2015 15:35:43 +0100 Subject: [PATCH 034/260] 8061436: Processing of options related to segmented code cache should be enhanced Allow user to set code heap sizes individually and enhance checking of code cache flags. Reviewed-by: kvn, roland --- hotspot/src/share/vm/code/codeCache.cpp | 134 ++++++++++++++++----- hotspot/src/share/vm/code/codeCache.hpp | 2 + hotspot/src/share/vm/runtime/arguments.cpp | 27 +---- 3 files changed, 108 insertions(+), 55 deletions(-) diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index 4301f293eb2..bd1957eff2c 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -140,7 +140,40 @@ nmethod* CodeCache::_scavenge_root_nmethods = NULL; // Initialize array of CodeHeaps GrowableArray* CodeCache::_heaps = new(ResourceObj::C_HEAP, mtCode) GrowableArray (CodeBlobType::All, true); +void CodeCache::check_heap_sizes(size_t non_nmethod_size, size_t profiled_size, size_t non_profiled_size, size_t cache_size, bool all_set) { + size_t total_size = non_nmethod_size + profiled_size + non_profiled_size; + // Prepare error message + const char* error = "Invalid code heap sizes"; + err_msg message("NonNMethodCodeHeapSize (%zuK) + ProfiledCodeHeapSize (%zuK) + NonProfiledCodeHeapSize (%zuK) = %zuK", + non_nmethod_size/K, profiled_size/K, non_profiled_size/K, total_size/K); + + if (total_size > cache_size) { + // Some code heap sizes were explicitly set: total_size must be <= cache_size + message.append(" is greater than ReservedCodeCacheSize (%zuK).", cache_size/K); + vm_exit_during_initialization(error, message); + } else if (all_set && total_size != cache_size) { + // All code heap sizes were explicitly set: total_size must equal cache_size + message.append(" is not equal to ReservedCodeCacheSize (%zuK).", cache_size/K); + vm_exit_during_initialization(error, message); + } +} + void CodeCache::initialize_heaps() { + bool non_nmethod_set = FLAG_IS_CMDLINE(NonNMethodCodeHeapSize); + bool profiled_set = FLAG_IS_CMDLINE(ProfiledCodeHeapSize); + bool non_profiled_set = FLAG_IS_CMDLINE(NonProfiledCodeHeapSize); + size_t min_size = os::vm_page_size(); + size_t cache_size = ReservedCodeCacheSize; + size_t non_nmethod_size = NonNMethodCodeHeapSize; + size_t profiled_size = ProfiledCodeHeapSize; + size_t non_profiled_size = NonProfiledCodeHeapSize; + // Check if total size set via command line flags exceeds the reserved size + check_heap_sizes((non_nmethod_set ? non_nmethod_size : min_size), + (profiled_set ? profiled_size : min_size), + (non_profiled_set ? non_profiled_size : min_size), + cache_size, + non_nmethod_set && profiled_set && non_profiled_set); + // Determine size of compiler buffers size_t code_buffers_size = 0; #ifdef COMPILER1 @@ -155,51 +188,94 @@ void CodeCache::initialize_heaps() { code_buffers_size += c2_count * C2Compiler::initial_code_buffer_size(); #endif + // Increase default non_nmethod_size to account for compiler buffers + if (!non_nmethod_set) { + non_nmethod_size += code_buffers_size; + } // Calculate default CodeHeap sizes if not set by user - if (!FLAG_IS_CMDLINE(NonNMethodCodeHeapSize) && !FLAG_IS_CMDLINE(ProfiledCodeHeapSize) - && !FLAG_IS_CMDLINE(NonProfiledCodeHeapSize)) { - // Increase default NonNMethodCodeHeapSize to account for compiler buffers - FLAG_SET_ERGO(uintx, NonNMethodCodeHeapSize, NonNMethodCodeHeapSize + code_buffers_size); - + if (!non_nmethod_set && !profiled_set && !non_profiled_set) { // Check if we have enough space for the non-nmethod code heap - if (ReservedCodeCacheSize > NonNMethodCodeHeapSize) { - // Use the default value for NonNMethodCodeHeapSize and one half of the - // remaining size for non-profiled methods and one half for profiled methods - size_t remaining_size = ReservedCodeCacheSize - NonNMethodCodeHeapSize; - size_t profiled_size = remaining_size / 2; - size_t non_profiled_size = remaining_size - profiled_size; - FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, profiled_size); - FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, non_profiled_size); + if (cache_size > non_nmethod_size) { + // Use the default value for non_nmethod_size and one half of the + // remaining size for non-profiled and one half for profiled methods + size_t remaining_size = cache_size - non_nmethod_size; + profiled_size = remaining_size / 2; + non_profiled_size = remaining_size - profiled_size; } else { // Use all space for the non-nmethod heap and set other heaps to minimal size - FLAG_SET_ERGO(uintx, NonNMethodCodeHeapSize, ReservedCodeCacheSize - os::vm_page_size() * 2); - FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, os::vm_page_size()); - FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, os::vm_page_size()); + non_nmethod_size = cache_size - 2 * min_size; + profiled_size = min_size; + non_profiled_size = min_size; + } + } else if (!non_nmethod_set || !profiled_set || !non_profiled_set) { + // The user explicitly set some code heap sizes. Increase or decrease the (default) + // sizes of the other code heaps accordingly. First adapt non-profiled and profiled + // code heap sizes and then only change non-nmethod code heap size if still necessary. + intx diff_size = cache_size - (non_nmethod_size + profiled_size + non_profiled_size); + if (non_profiled_set) { + if (!profiled_set) { + // Adapt size of profiled code heap + if (diff_size < 0 && ((intx)profiled_size + diff_size) <= 0) { + // Not enough space available, set to minimum size + diff_size += profiled_size - min_size; + profiled_size = min_size; + } else { + profiled_size += diff_size; + diff_size = 0; + } + } + } else if (profiled_set) { + // Adapt size of non-profiled code heap + if (diff_size < 0 && ((intx)non_profiled_size + diff_size) <= 0) { + // Not enough space available, set to minimum size + diff_size += non_profiled_size - min_size; + non_profiled_size = min_size; + } else { + non_profiled_size += diff_size; + diff_size = 0; + } + } else if (non_nmethod_set) { + // Distribute remaining size between profiled and non-profiled code heaps + diff_size = cache_size - non_nmethod_size; + profiled_size = diff_size / 2; + non_profiled_size = diff_size - profiled_size; + diff_size = 0; + } + if (diff_size != 0) { + // Use non-nmethod code heap for remaining space requirements + assert(!non_nmethod_set && ((intx)non_nmethod_size + diff_size) > 0, "sanity"); + non_nmethod_size += diff_size; } } // We do not need the profiled CodeHeap, use all space for the non-profiled CodeHeap if(!heap_available(CodeBlobType::MethodProfiled)) { - FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, NonProfiledCodeHeapSize + ProfiledCodeHeapSize); - FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, 0); + non_profiled_size += profiled_size; + profiled_size = 0; } // We do not need the non-profiled CodeHeap, use all space for the non-nmethod CodeHeap if(!heap_available(CodeBlobType::MethodNonProfiled)) { - FLAG_SET_ERGO(uintx, NonNMethodCodeHeapSize, NonNMethodCodeHeapSize + NonProfiledCodeHeapSize); - FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, 0); + non_nmethod_size += non_profiled_size; + non_profiled_size = 0; } - // Make sure we have enough space for VM internal code uint min_code_cache_size = CodeCacheMinimumUseSpace DEBUG_ONLY(* 3); - if (NonNMethodCodeHeapSize < (min_code_cache_size + code_buffers_size)) { - vm_exit_during_initialization("Not enough space in non-nmethod code heap to run VM."); + if (non_nmethod_size < (min_code_cache_size + code_buffers_size)) { + vm_exit_during_initialization(err_msg( + "Not enough space in non-nmethod code heap to run VM: %zuK < %zuK", + non_nmethod_size/K, (min_code_cache_size + code_buffers_size)/K)); } - guarantee(NonProfiledCodeHeapSize + ProfiledCodeHeapSize + NonNMethodCodeHeapSize <= ReservedCodeCacheSize, "Size check"); + + // Verify sizes and update flag values + assert(non_profiled_size + profiled_size + non_nmethod_size == cache_size, "Invalid code heap sizes"); + FLAG_SET_ERGO(uintx, NonNMethodCodeHeapSize, non_nmethod_size); + FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, profiled_size); + FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, non_profiled_size); // Align CodeHeaps size_t alignment = heap_alignment(); - size_t non_method_size = align_size_up(NonNMethodCodeHeapSize, alignment); - size_t profiled_size = align_size_down(ProfiledCodeHeapSize, alignment); + non_nmethod_size = align_size_up(non_nmethod_size, alignment); + profiled_size = align_size_down(profiled_size, alignment); // Reserve one continuous chunk of memory for CodeHeaps and split it into // parts for the individual heaps. The memory layout looks like this: @@ -208,9 +284,9 @@ void CodeCache::initialize_heaps() { // Profiled nmethods // Non-nmethods // ---------- low ------------ - ReservedCodeSpace rs = reserve_heap_memory(ReservedCodeCacheSize); - ReservedSpace non_method_space = rs.first_part(non_method_size); - ReservedSpace rest = rs.last_part(non_method_size); + ReservedCodeSpace rs = reserve_heap_memory(cache_size); + ReservedSpace non_method_space = rs.first_part(non_nmethod_size); + ReservedSpace rest = rs.last_part(non_nmethod_size); ReservedSpace profiled_space = rest.first_part(profiled_size); ReservedSpace non_profiled_space = rest.last_part(profiled_size); diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp index 30900e948ea..88594bd80a7 100644 --- a/hotspot/src/share/vm/code/codeCache.hpp +++ b/hotspot/src/share/vm/code/codeCache.hpp @@ -94,6 +94,8 @@ class CodeCache : AllStatic { // CodeHeap management static void initialize_heaps(); // Initializes the CodeHeaps + // Check the code heap sizes set by the user via command line + static void check_heap_sizes(size_t non_nmethod_size, size_t profiled_size, size_t non_profiled_size, size_t cache_size, bool all_set); // Creates a new heap with the given name and size, containing CodeBlobs of the given type static void add_heap(ReservedSpace rs, const char* name, int code_blob_type); static CodeHeap* get_code_heap(const CodeBlob* cb); // Returns the CodeHeap for the given CodeBlob diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index b77b7a76ee4..eded26ef0c5 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1453,24 +1453,6 @@ void Arguments::set_tiered_flags() { // Enable SegmentedCodeCache if TieredCompilation is enabled and ReservedCodeCacheSize >= 240M if (FLAG_IS_DEFAULT(SegmentedCodeCache) && ReservedCodeCacheSize >= 240*M) { FLAG_SET_ERGO(bool, SegmentedCodeCache, true); - - if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) { - // Multiply sizes by 5 but fix NonNMethodCodeHeapSize (distribute among non-profiled and profiled code heap) - if (FLAG_IS_DEFAULT(ProfiledCodeHeapSize)) { - FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, ProfiledCodeHeapSize * 5 + NonNMethodCodeHeapSize * 2); - } - if (FLAG_IS_DEFAULT(NonProfiledCodeHeapSize)) { - FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, NonProfiledCodeHeapSize * 5 + NonNMethodCodeHeapSize * 2); - } - // Check consistency of code heap sizes - if ((NonNMethodCodeHeapSize + NonProfiledCodeHeapSize + ProfiledCodeHeapSize) != ReservedCodeCacheSize) { - jio_fprintf(defaultStream::error_stream(), - "Invalid code heap sizes: NonNMethodCodeHeapSize(%dK) + ProfiledCodeHeapSize(%dK) + NonProfiledCodeHeapSize(%dK) = %dK. Must be equal to ReservedCodeCacheSize = %uK.\n", - NonNMethodCodeHeapSize/K, ProfiledCodeHeapSize/K, NonProfiledCodeHeapSize/K, - (NonNMethodCodeHeapSize + ProfiledCodeHeapSize + NonProfiledCodeHeapSize)/K, ReservedCodeCacheSize/K); - vm_exit(1); - } - } } if (!UseInterpreter) { // -Xcomp Tier3InvokeNotifyFreqLog = 0; @@ -2530,18 +2512,11 @@ bool Arguments::check_vm_args_consistency() { "Invalid ReservedCodeCacheSize=%dM. Must be at most %uM.\n", ReservedCodeCacheSize/M, CODE_CACHE_SIZE_LIMIT/M); status = false; - } else if (NonNMethodCodeHeapSize < min_code_cache_size){ + } else if (NonNMethodCodeHeapSize < min_code_cache_size) { jio_fprintf(defaultStream::error_stream(), "Invalid NonNMethodCodeHeapSize=%dK. Must be at least %uK.\n", NonNMethodCodeHeapSize/K, min_code_cache_size/K); status = false; - } else if ((!FLAG_IS_DEFAULT(NonNMethodCodeHeapSize) || !FLAG_IS_DEFAULT(ProfiledCodeHeapSize) || !FLAG_IS_DEFAULT(NonProfiledCodeHeapSize)) - && (NonNMethodCodeHeapSize + NonProfiledCodeHeapSize + ProfiledCodeHeapSize) != ReservedCodeCacheSize) { - jio_fprintf(defaultStream::error_stream(), - "Invalid code heap sizes: NonNMethodCodeHeapSize(%dK) + ProfiledCodeHeapSize(%dK) + NonProfiledCodeHeapSize(%dK) = %dK. Must be equal to ReservedCodeCacheSize = %uK.\n", - NonNMethodCodeHeapSize/K, ProfiledCodeHeapSize/K, NonProfiledCodeHeapSize/K, - (NonNMethodCodeHeapSize + ProfiledCodeHeapSize + NonProfiledCodeHeapSize)/K, ReservedCodeCacheSize/K); - status = false; } if (!FLAG_IS_DEFAULT(CICompilerCount) && !FLAG_IS_DEFAULT(CICompilerCountPerCPU) && CICompilerCountPerCPU) { From 854b8d1ff1166d7db14b27cd49016ab81fbed2fb Mon Sep 17 00:00:00 2001 From: Hui Shi Date: Mon, 16 Nov 2015 16:14:15 +0100 Subject: [PATCH 035/260] 8139758: [REDO] Elide more final field's write memory barrier with escape analysis result Membar for all final field initializations eliminated if possible Reviewed-by: roland, vlivanov --- hotspot/src/share/vm/opto/parse1.cpp | 9 +- hotspot/src/share/vm/opto/parse3.cpp | 5 +- .../stable/TestStableMemoryBarrier.java | 91 +++++++++++++++++++ 3 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 hotspot/test/compiler/stable/TestStableMemoryBarrier.java diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index 58f74096bf2..a82b02e8e45 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -964,11 +964,12 @@ void Parse::do_exits() { } } - // Any method can write a @Stable field; insert memory barriers after - // those also. If there is a predecessor allocation node, bind the - // barrier there. + // Any method can write a @Stable field; insert memory barriers + // after those also. Can't bind predecessor allocation node (if any) + // with barrier because allocation doesn't always dominate + // MemBarRelease. if (wrote_stable()) { - _exits.insert_mem_bar(Op_MemBarRelease, alloc_with_final()); + _exits.insert_mem_bar(Op_MemBarRelease); if (PrintOpto && (Verbose || WizardMode)) { method()->print_name(); tty->print_cr(" writes @Stable and needs a memory barrier"); diff --git a/hotspot/src/share/vm/opto/parse3.cpp b/hotspot/src/share/vm/opto/parse3.cpp index 57b4718da38..d9ad4ced928 100644 --- a/hotspot/src/share/vm/opto/parse3.cpp +++ b/hotspot/src/share/vm/opto/parse3.cpp @@ -311,9 +311,8 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) { // Preserve allocation ptr to create precedent edge to it in membar // generated on exit from constructor. - if (C->eliminate_boxing() && - adr_type->isa_oopptr() && adr_type->is_oopptr()->is_ptr_to_boxed_value() && - AllocateNode::Ideal_allocation(obj, &_gvn) != NULL) { + // Can't bind stable with its allocation, only record allocation for final field. + if (field->is_final() && AllocateNode::Ideal_allocation(obj, &_gvn) != NULL) { set_alloc_with_final(obj); } } diff --git a/hotspot/test/compiler/stable/TestStableMemoryBarrier.java b/hotspot/test/compiler/stable/TestStableMemoryBarrier.java new file mode 100644 index 00000000000..6a1e1f6d149 --- /dev/null +++ b/hotspot/test/compiler/stable/TestStableMemoryBarrier.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 TestStableMemoryBarrier + * @bug 8139758 + * @summary tests memory barrier correctly inserted for stable fields + * @library /testlibrary /../../test/lib + * + * @run main/bootclasspath -Xcomp -XX:CompileOnly=::testCompile + * java.lang.invoke.TestStableMemoryBarrier + * + * @author hui.shi@linaro.org + */ +package java.lang.invoke; + +import java.lang.reflect.InvocationTargetException; + +public class TestStableMemoryBarrier { + + public static void main(String[] args) throws Exception { + run(NotDominate.class); + + } + + /* ==================================================== + * Stable field initialized in method, but its allocation + * doesn't dominate MemBar Release at the end of method. + */ + + static class NotDominate{ + public @Stable int v; + public static int[] array = new int[100]; + public static NotDominate testCompile(int n) { + if ((n % 2) == 0) return null; + // add a loop here, trigger PhaseIdealLoop::verify_dominance + for (int i = 0; i < 100; i++) { + array[i] = n; + } + NotDominate nm = new NotDominate(); + nm.v = n; + return nm; + } + + public static void test() throws Exception { + for (int i = 0; i < 1000000; i++) + testCompile(i); + } + } + + public static void run(Class test) { + Throwable ex = null; + System.out.print(test.getName()+": "); + try { + test.getMethod("test").invoke(null); + } catch (InvocationTargetException e) { + ex = e.getCause(); + } catch (Throwable e) { + ex = e; + } finally { + if (ex == null) { + System.out.println("PASSED"); + } else { + System.out.println("FAILED"); + ex.printStackTrace(System.out); + } + } + } +} From 36d1144c832f3f0c7540d051c0ba78091338e5bd Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Mon, 16 Nov 2015 20:57:49 +0100 Subject: [PATCH 036/260] 8143059: TestUnsafeUnalignedMismatchedAccesses doens't build after 8139891 Use new Unsafe import path Reviewed-by: roland, thartmann, shade --- .../unsafe/TestUnsafeUnalignedMismatchedAccesses.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeUnalignedMismatchedAccesses.java b/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeUnalignedMismatchedAccesses.java index 464c13cba56..b6a64e13a67 100644 --- a/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeUnalignedMismatchedAccesses.java +++ b/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeUnalignedMismatchedAccesses.java @@ -32,7 +32,7 @@ */ import java.lang.reflect.*; -import sun.misc.Unsafe; +import jdk.internal.misc.Unsafe; public class TestUnsafeUnalignedMismatchedAccesses { From 1d58a73e8c6a7f8a8b09624ad07a51fa22829559 Mon Sep 17 00:00:00 2001 From: Alexander Smundak Date: Tue, 17 Nov 2015 08:59:21 +0100 Subject: [PATCH 037/260] 8139258: PPC64LE: argument passing problem when passing 15 floats in native call Reviewed-by: mdoerr, goetz --- hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp | 8 ++++++++ hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp | 19 +++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp index 08e4a4fc54f..0fbf97085ca 100644 --- a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp @@ -297,8 +297,16 @@ address AbstractInterpreterGenerator::generate_slow_signature_handler() { __ bind(do_float); __ lfs(floatSlot, 0, arg_java); #if defined(LINUX) + // Linux uses ELF ABI. Both original ELF and ELFv2 ABIs have float + // in the least significant word of an argument slot. +#if defined(VM_LITTLE_ENDIAN) + __ stfs(floatSlot, 0, arg_c); +#else __ stfs(floatSlot, 4, arg_c); +#endif #elif defined(AIX) + // Although AIX runs on big endian CPU, float is in most significant + // word of an argument slot. __ stfs(floatSlot, 0, arg_c); #else #error "unknown OS" diff --git a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index d52ea6a0c56..d78395f0a35 100644 --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -753,6 +753,21 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt, // in farg_reg[j] if argument i is the j-th float argument of this call. // case T_FLOAT: +#if defined(LINUX) + // Linux uses ELF ABI. Both original ELF and ELFv2 ABIs have float + // in the least significant word of an argument slot. +#if defined(VM_LITTLE_ENDIAN) +#define FLOAT_WORD_OFFSET_IN_SLOT 0 +#else +#define FLOAT_WORD_OFFSET_IN_SLOT 1 +#endif +#elif defined(AIX) + // Although AIX runs on big endian CPU, float is in the most + // significant word of an argument slot. +#define FLOAT_WORD_OFFSET_IN_SLOT 0 +#else +#error "unknown OS" +#endif if (freg < Argument::n_float_register_parameters_c) { // Put float in register ... reg = farg_reg[freg]; @@ -766,14 +781,14 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt, if (arg >= Argument::n_regs_not_on_stack_c) { // ... and on the stack. guarantee(regs2 != NULL, "must pass float in register and stack slot"); - VMReg reg2 = VMRegImpl::stack2reg(stk LINUX_ONLY(+1)); + VMReg reg2 = VMRegImpl::stack2reg(stk + FLOAT_WORD_OFFSET_IN_SLOT); regs2[i].set1(reg2); stk += inc_stk_for_intfloat; } } else { // Put float on stack. - reg = VMRegImpl::stack2reg(stk LINUX_ONLY(+1)); + reg = VMRegImpl::stack2reg(stk + FLOAT_WORD_OFFSET_IN_SLOT); stk += inc_stk_for_intfloat; } regs[i].set1(reg); From c18a26c573a398c252485a57c297cfd9ef177b12 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 17 Nov 2015 12:00:16 +0100 Subject: [PATCH 038/260] 8142386: Octane crashes with assert(is_Load()) Unsafe access to an array is wrongly marked as mismatched Reviewed-by: vlivanov, thartmann --- hotspot/src/share/vm/opto/graphKit.cpp | 12 +--- hotspot/src/share/vm/opto/library_call.cpp | 4 ++ hotspot/src/share/vm/opto/memnode.cpp | 67 +++++++++++++------ hotspot/src/share/vm/opto/memnode.hpp | 13 ++-- .../TestUnsafeMismatchedArrayFieldAccess.java | 65 ++++++++++++++++++ 5 files changed, 128 insertions(+), 33 deletions(-) create mode 100644 hotspot/test/compiler/intrinsics/unsafe/TestUnsafeMismatchedArrayFieldAccess.java diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index 4d8896dadb7..54ff117bcc8 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -1468,17 +1468,11 @@ Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, Node* mem = memory(adr_idx); Node* ld; if (require_atomic_access && bt == T_LONG) { - ld = LoadLNode::make_atomic(ctl, mem, adr, adr_type, t, mo, control_dependency); + ld = LoadLNode::make_atomic(ctl, mem, adr, adr_type, t, mo, control_dependency, unaligned, mismatched); } else if (require_atomic_access && bt == T_DOUBLE) { - ld = LoadDNode::make_atomic(ctl, mem, adr, adr_type, t, mo, control_dependency); + ld = LoadDNode::make_atomic(ctl, mem, adr, adr_type, t, mo, control_dependency, unaligned, mismatched); } else { - ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency); - } - if (unaligned) { - ld->as_Load()->set_unaligned_access(); - } - if (mismatched) { - ld->as_Load()->set_mismatched_access(); + ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency, unaligned, mismatched); } ld = _gvn.transform(ld); if ((bt == T_OBJECT) && C->do_escape_analysis() || C->eliminate_boxing()) { diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 1b8713c291d..f8c503da26c 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -2588,6 +2588,10 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas } else { bt = alias_type->field()->type()->basic_type(); } + if (bt == T_ARRAY) { + // accessing an array field with getObject is not a mismatch + bt = T_OBJECT; + } if (bt != type) { mismatched = true; } diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 863255dabdb..2995b7dfade 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -761,7 +761,8 @@ bool LoadNode::is_immutable_value(Node* adr) { //----------------------------LoadNode::make----------------------------------- // Polymorphic factory method: -Node *LoadNode::make(PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const TypePtr* adr_type, const Type *rt, BasicType bt, MemOrd mo, ControlDependency control_dependency) { +Node *LoadNode::make(PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const TypePtr* adr_type, const Type *rt, BasicType bt, MemOrd mo, + ControlDependency control_dependency, bool unaligned, bool mismatched) { Compile* C = gvn.C; // sanity check the alias category against the created node type @@ -776,40 +777,68 @@ Node *LoadNode::make(PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const TypeP // oop will be recorded in oop map if load crosses safepoint rt->isa_oopptr() || is_immutable_value(adr), "raw memory operations should have control edge"); + LoadNode* load = NULL; switch (bt) { - case T_BOOLEAN: return new LoadUBNode(ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); - case T_BYTE: return new LoadBNode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); - case T_INT: return new LoadINode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); - case T_CHAR: return new LoadUSNode(ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); - case T_SHORT: return new LoadSNode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); - case T_LONG: return new LoadLNode (ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency); - case T_FLOAT: return new LoadFNode (ctl, mem, adr, adr_type, rt, mo, control_dependency); - case T_DOUBLE: return new LoadDNode (ctl, mem, adr, adr_type, rt, mo, control_dependency); - case T_ADDRESS: return new LoadPNode (ctl, mem, adr, adr_type, rt->is_ptr(), mo, control_dependency); + case T_BOOLEAN: load = new LoadUBNode(ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); break; + case T_BYTE: load = new LoadBNode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); break; + case T_INT: load = new LoadINode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); break; + case T_CHAR: load = new LoadUSNode(ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); break; + case T_SHORT: load = new LoadSNode (ctl, mem, adr, adr_type, rt->is_int(), mo, control_dependency); break; + case T_LONG: load = new LoadLNode (ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency); break; + case T_FLOAT: load = new LoadFNode (ctl, mem, adr, adr_type, rt, mo, control_dependency); break; + case T_DOUBLE: load = new LoadDNode (ctl, mem, adr, adr_type, rt, mo, control_dependency); break; + case T_ADDRESS: load = new LoadPNode (ctl, mem, adr, adr_type, rt->is_ptr(), mo, control_dependency); break; case T_OBJECT: #ifdef _LP64 if (adr->bottom_type()->is_ptr_to_narrowoop()) { - Node* load = gvn.transform(new LoadNNode(ctl, mem, adr, adr_type, rt->make_narrowoop(), mo, control_dependency)); - return new DecodeNNode(load, load->bottom_type()->make_ptr()); + load = new LoadNNode(ctl, mem, adr, adr_type, rt->make_narrowoop(), mo, control_dependency); } else #endif { assert(!adr->bottom_type()->is_ptr_to_narrowoop() && !adr->bottom_type()->is_ptr_to_narrowklass(), "should have got back a narrow oop"); - return new LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr(), mo, control_dependency); + load = new LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr(), mo, control_dependency); } + break; } - ShouldNotReachHere(); - return (LoadNode*)NULL; + assert(load != NULL, "LoadNode should have been created"); + if (unaligned) { + load->set_unaligned_access(); + } + if (mismatched) { + load->set_mismatched_access(); + } + if (load->Opcode() == Op_LoadN) { + Node* ld = gvn.transform(load); + return new DecodeNNode(ld, ld->bottom_type()->make_ptr()); + } + + return load; } -LoadLNode* LoadLNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo, ControlDependency control_dependency) { +LoadLNode* LoadLNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo, + ControlDependency control_dependency, bool unaligned, bool mismatched) { bool require_atomic = true; - return new LoadLNode(ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency, require_atomic); + LoadLNode* load = new LoadLNode(ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency, require_atomic); + if (unaligned) { + load->set_unaligned_access(); + } + if (mismatched) { + load->set_mismatched_access(); + } + return load; } -LoadDNode* LoadDNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo, ControlDependency control_dependency) { +LoadDNode* LoadDNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo, + ControlDependency control_dependency, bool unaligned, bool mismatched) { bool require_atomic = true; - return new LoadDNode(ctl, mem, adr, adr_type, rt, mo, control_dependency, require_atomic); + LoadDNode* load = new LoadDNode(ctl, mem, adr, adr_type, rt, mo, control_dependency, require_atomic); + if (unaligned) { + load->set_unaligned_access(); + } + if (mismatched) { + load->set_mismatched_access(); + } + return load; } diff --git a/hotspot/src/share/vm/opto/memnode.hpp b/hotspot/src/share/vm/opto/memnode.hpp index d049c1ff2b4..cab41bcdf0d 100644 --- a/hotspot/src/share/vm/opto/memnode.hpp +++ b/hotspot/src/share/vm/opto/memnode.hpp @@ -198,9 +198,10 @@ public: } // Polymorphic factory method: - static Node* make(PhaseGVN& gvn, Node *c, Node *mem, Node *adr, - const TypePtr* at, const Type *rt, BasicType bt, - MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest); + static Node* make(PhaseGVN& gvn, Node *c, Node *mem, Node *adr, + const TypePtr* at, const Type *rt, BasicType bt, + MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest, + bool unaligned = false, bool mismatched = false); virtual uint hash() const; // Check the type @@ -375,7 +376,8 @@ public: virtual BasicType memory_type() const { return T_LONG; } bool require_atomic_access() const { return _require_atomic_access; } static LoadLNode* make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, - const Type* rt, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest); + const Type* rt, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest, + bool unaligned = false, bool mismatched = false); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const { LoadNode::dump_spec(st); @@ -426,7 +428,8 @@ public: virtual BasicType memory_type() const { return T_DOUBLE; } bool require_atomic_access() const { return _require_atomic_access; } static LoadDNode* make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, - const Type* rt, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest); + const Type* rt, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest, + bool unaligned = false, bool mismatched = false); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const { LoadNode::dump_spec(st); diff --git a/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeMismatchedArrayFieldAccess.java b/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeMismatchedArrayFieldAccess.java new file mode 100644 index 00000000000..2c60a719827 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeMismatchedArrayFieldAccess.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8142386 + * @library /testlibrary /test/lib + * @summary Unsafe access to an array is wrongly marked as mismatched + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:-TieredCompilation TestUnsafeMismatchedArrayFieldAccess + * + */ + +import java.lang.reflect.*; +import jdk.test.lib.Utils; +import sun.misc.Unsafe; + +public class TestUnsafeMismatchedArrayFieldAccess { + + private static final Unsafe UNSAFE = Utils.getUnsafe(); + + static { + try { + array_offset = UNSAFE.objectFieldOffset(TestUnsafeMismatchedArrayFieldAccess.class.getDeclaredField("array")); + } + catch (Exception e) { + throw new AssertionError(e); + } + } + + int[] array; + static final long array_offset; + + void m() { + UNSAFE.getObject(this, array_offset); + } + + static public void main(String[] args) { + TestUnsafeMismatchedArrayFieldAccess test = new TestUnsafeMismatchedArrayFieldAccess(); + + for (int i = 0; i < 20000; i++) { + test.m(); + } + } +} From 9d87b3e725d3050ccb667893f68301f9f1b0696d Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 17 Nov 2015 11:29:23 -1000 Subject: [PATCH 039/260] 8142511: [JVMCI] must eagerly initialize classes with static fields accessed by JVMCI native code Reviewed-by: twisti --- hotspot/src/share/vm/jvmci/jvmciJavaClasses.cpp | 11 ++++++++--- hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp | 6 +++--- hotspot/src/share/vm/jvmci/jvmciRuntime.cpp | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/hotspot/src/share/vm/jvmci/jvmciJavaClasses.cpp b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.cpp index 190aaf419f1..3972a6c2e55 100644 --- a/hotspot/src/share/vm/jvmci/jvmciJavaClasses.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.cpp @@ -30,7 +30,7 @@ // This function is similar to javaClasses.cpp, it computes the field offset of a (static or instance) field. // It looks up the name and signature symbols without creating new ones, all the symbols of these classes need to be already loaded. -void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field) { +void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field, TRAPS) { InstanceKlass* ik = InstanceKlass::cast(klass); Symbol* name_symbol = SymbolTable::probe(name, (int)strlen(name)); Symbol* signature_symbol = SymbolTable::probe(signature, (int)strlen(signature)); @@ -49,6 +49,11 @@ void compute_offset(int &dest_offset, Klass* klass, const char* name, const char guarantee(fd.is_static() == static_field, "static/instance mismatch"); dest_offset = fd.offset(); assert(dest_offset != 0, "must be valid offset"); + if (static_field) { + // Must ensure classes for static fields are initialized as the + // accessor itself does not include a class initialization check. + ik->initialize(CHECK); + } } // This piece of macro magic creates the contents of the jvmci_compute_offsets method that initializes the field indices of all the access classes. @@ -57,7 +62,7 @@ void compute_offset(int &dest_offset, Klass* klass, const char* name, const char #define END_CLASS } -#define FIELD(klass, name, signature, static_field) compute_offset(klass::_##name##_offset, k, #name, signature, static_field); +#define FIELD(klass, name, signature, static_field) compute_offset(klass::_##name##_offset, k, #name, signature, static_field, CHECK); #define CHAR_FIELD(klass, name) FIELD(klass, name, "C", false) #define INT_FIELD(klass, name) FIELD(klass, name, "I", false) #define BOOLEAN_FIELD(klass, name) FIELD(klass, name, "Z", false) @@ -69,7 +74,7 @@ void compute_offset(int &dest_offset, Klass* klass, const char* name, const char #define STATIC_BOOLEAN_FIELD(klass, name) FIELD(klass, name, "Z", true) -void JVMCIJavaClasses::compute_offsets() { +void JVMCIJavaClasses::compute_offsets(TRAPS) { COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, OOP_FIELD, OOP_FIELD, STATIC_OOP_FIELD, STATIC_OOP_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD) } diff --git a/hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp index 2f4fd5f4ea0..cf26827be8f 100644 --- a/hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp @@ -29,7 +29,7 @@ class JVMCIJavaClasses : AllStatic { public: - static void compute_offsets(); + static void compute_offsets(TRAPS); }; /* This macro defines the structure of the CompilationResult - classes. @@ -306,7 +306,7 @@ class name : AllStatic { assert(obj->is_a(SystemDictionary::name##_klass()), "wrong class, " #name " expected, found %s", obj->klass()->external_name()); \ assert(offset != 0, "must be valid offset"); \ } \ - static void compute_offsets(); \ + static void compute_offsets(TRAPS); \ public: \ static InstanceKlass* klass() { return SystemDictionary::name##_klass(); } @@ -392,6 +392,6 @@ COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD #undef STATIC_BOOLEAN_FIELD #undef EMPTY_CAST -void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field); +void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field, TRAPS); #endif // SHARE_VM_JVMCI_JVMCIJAVACLASSES_HPP diff --git a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp index 9a26312563c..afcbdf27f82 100644 --- a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp @@ -720,7 +720,7 @@ void JVMCIRuntime::initialize_well_known_classes(TRAPS) { if (JVMCIRuntime::_well_known_classes_initialized == false) { SystemDictionary::WKID scan = SystemDictionary::FIRST_JVMCI_WKID; SystemDictionary::initialize_wk_klasses_through(SystemDictionary::LAST_JVMCI_WKID, scan, CHECK); - JVMCIJavaClasses::compute_offsets(); + JVMCIJavaClasses::compute_offsets(CHECK); JVMCIRuntime::_well_known_classes_initialized = true; } } From f0c12f35cb67dc27014e68cc584a10d37c874623 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Mon, 2 Nov 2015 15:52:37 +0100 Subject: [PATCH 040/260] 8141137: C2 fails rematerializing nodes using flag registers Don't rem. if input stretches several live ranges. If rem., don't add SpillCopy on RegFlags edge. Reviewed-by: kvn, vlivanov --- hotspot/src/share/vm/opto/machnode.cpp | 45 ++++++++++++++++--------- hotspot/src/share/vm/opto/machnode.hpp | 8 +++-- hotspot/src/share/vm/opto/reg_split.cpp | 45 ++++++++++++++++++------- 3 files changed, 68 insertions(+), 30 deletions(-) diff --git a/hotspot/src/share/vm/opto/machnode.cpp b/hotspot/src/share/vm/opto/machnode.cpp index 514a9b5912e..c780d3f5340 100644 --- a/hotspot/src/share/vm/opto/machnode.cpp +++ b/hotspot/src/share/vm/opto/machnode.cpp @@ -433,36 +433,49 @@ bool MachNode::rematerialize() const { if (is_MachTemp()) return true; uint r = rule(); // Match rule - if( r < Matcher::_begin_rematerialize || - r >= Matcher::_end_rematerialize ) + if (r < Matcher::_begin_rematerialize || + r >= Matcher::_end_rematerialize) { return false; - - // For 2-address instructions, the input live range is also the output - // live range. Remateralizing does not make progress on the that live range. - if( two_adr() ) return false; - - // Check for rematerializing float constants, or not - if( !Matcher::rematerialize_float_constants ) { - int op = ideal_Opcode(); - if( op == Op_ConF || op == Op_ConD ) - return false; } - // Defining flags - can't spill these! Must remateralize. - if( ideal_reg() == Op_RegFlags ) + // For 2-address instructions, the input live range is also the output + // live range. Remateralizing does not make progress on the that live range. + if (two_adr()) return false; + + // Check for rematerializing float constants, or not + if (!Matcher::rematerialize_float_constants) { + int op = ideal_Opcode(); + if (op == Op_ConF || op == Op_ConD) { + return false; + } + } + + // Defining flags - can't spill these! Must remateralize. + if (ideal_reg() == Op_RegFlags) { return true; + } // Stretching lots of inputs - don't do it. - if( req() > 2 ) + if (req() > 2) { return false; + } + + if (req() == 2 && in(1) && in(1)->ideal_reg() == Op_RegFlags) { + // In(1) will be rematerialized, too. + // Stretching lots of inputs - don't do it. + if (in(1)->req() > 2) { + return false; + } + } // Don't remateralize somebody with bound inputs - it stretches a // fixed register lifetime. uint idx = oper_input_base(); if (req() > idx) { const RegMask &rm = in_RegMask(idx); - if (rm.is_bound(ideal_reg())) + if (rm.is_bound(ideal_reg())) { return false; + } } return true; diff --git a/hotspot/src/share/vm/opto/machnode.hpp b/hotspot/src/share/vm/opto/machnode.hpp index e30e23406c6..ca2ad70c264 100644 --- a/hotspot/src/share/vm/opto/machnode.hpp +++ b/hotspot/src/share/vm/opto/machnode.hpp @@ -578,8 +578,8 @@ public: #ifndef PRODUCT - virtual const char *Name() const { - switch (_spill_type) { + static const char *spill_type(SpillType st) { + switch (st) { case TwoAddress: return "TwoAddressSpillCopy"; case PhiInput: @@ -612,6 +612,10 @@ public: } } + virtual const char *Name() const { + return spill_type(_spill_type); + } + virtual void format( PhaseRegAlloc *, outputStream *st ) const; #endif }; diff --git a/hotspot/src/share/vm/opto/reg_split.cpp b/hotspot/src/share/vm/opto/reg_split.cpp index 1a0d241bde0..5e14b9d5abc 100644 --- a/hotspot/src/share/vm/opto/reg_split.cpp +++ b/hotspot/src/share/vm/opto/reg_split.cpp @@ -55,13 +55,15 @@ static const char out_of_nodes[] = "out of nodes during split"; // Get a SpillCopy node with wide-enough masks. Use the 'wide-mask', the // wide ideal-register spill-mask if possible. If the 'wide-mask' does // not cover the input (or output), use the input (or output) mask instead. -Node *PhaseChaitin::get_spillcopy_wide(MachSpillCopyNode::SpillType spill_type, Node *def, Node *use, uint uidx ) { +Node *PhaseChaitin::get_spillcopy_wide(MachSpillCopyNode::SpillType spill_type, Node *def, Node *use, uint uidx) { // If ideal reg doesn't exist we've got a bad schedule happening // that is forcing us to spill something that isn't spillable. // Bail rather than abort int ireg = def->ideal_reg(); - if( ireg == 0 || ireg == Op_RegFlags ) { - assert(false, "attempted to spill a non-spillable item"); + if (ireg == 0 || ireg == Op_RegFlags) { + assert(false, "attempted to spill a non-spillable item: %d: %s <- %d: %s, ireg = %d, spill_type: %s", + def->_idx, def->Name(), use->_idx, use->Name(), ireg, + MachSpillCopyNode::spill_type(spill_type)); C->record_method_not_compilable("attempted to spill a non-spillable item"); return NULL; } @@ -308,14 +310,16 @@ Node* clone_node(Node* def, Block *b, Compile* C) { //------------------------------split_Rematerialize---------------------------- // Clone a local copy of the def. -Node *PhaseChaitin::split_Rematerialize( Node *def, Block *b, uint insidx, uint &maxlrg, GrowableArray splits, int slidx, uint *lrg2reach, Node **Reachblock, bool walkThru ) { +Node *PhaseChaitin::split_Rematerialize(Node *def, Block *b, uint insidx, uint &maxlrg, + GrowableArray splits, int slidx, uint *lrg2reach, + Node **Reachblock, bool walkThru) { // The input live ranges will be stretched to the site of the new // instruction. They might be stretched past a def and will thus // have the old and new values of the same live range alive at the // same time - a definite no-no. Split out private copies of // the inputs. - if( def->req() > 1 ) { - for( uint i = 1; i < def->req(); i++ ) { + if (def->req() > 1) { + for (uint i = 1; i < def->req(); i++) { Node *in = def->in(i); uint lidx = _lrg_map.live_range_id(in); // We do not need this for live ranges that are only defined once. @@ -327,12 +331,29 @@ Node *PhaseChaitin::split_Rematerialize( Node *def, Block *b, uint insidx, uint Block *b_def = _cfg.get_block_for_node(def); int idx_def = b_def->find_node(def); - Node *in_spill = get_spillcopy_wide(MachSpillCopyNode::InputToRematerialization, in, def, i ); - if( !in_spill ) return 0; // Bailed out - insert_proj(b_def,idx_def,in_spill,maxlrg++); - if( b_def == b ) - insidx++; - def->set_req(i,in_spill); + // Cannot spill Op_RegFlags. + Node *in_spill; + if (in->ideal_reg() != Op_RegFlags) { + in_spill = get_spillcopy_wide(MachSpillCopyNode::InputToRematerialization, in, def, i); + if (!in_spill) { return 0; } // Bailed out + insert_proj(b_def, idx_def, in_spill, maxlrg++); + if (b_def == b) { + insidx++; + } + def->set_req(i, in_spill); + } else { + // The 'in' defines a flag register. Flag registers can not be spilled. + // Register allocation handles live ranges with flag registers + // by rematerializing the def (in this case 'in'). Thus, this is not + // critical if the input can be rematerialized, too. + if (!in->rematerialize()) { + assert(false, "Can not rematerialize %d: %s. Prolongs RegFlags live" + " range and defining node %d: %s may not be rematerialized.", + def->_idx, def->Name(), in->_idx, in->Name()); + C->record_method_not_compilable("attempted to spill a non-spillable item with RegFlags input"); + return 0; // Bailed out + } + } } } From 1cfbe2dec56fe610e6a8f43436cbdc8bb737204d Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Wed, 18 Nov 2015 03:03:43 +0300 Subject: [PATCH 041/260] 8139595: MethodHandles::remove_dependent_nmethod is not MT safe Reviewed-by: jrose, coleenp --- .../src/share/vm/classfile/javaClasses.cpp | 17 +- .../src/share/vm/classfile/javaClasses.hpp | 5 +- .../src/share/vm/code/dependencyContext.cpp | 347 +++++++++++++++ .../src/share/vm/code/dependencyContext.hpp | 152 +++++++ .../src/share/vm/compiler/compileBroker.cpp | 2 +- hotspot/src/share/vm/oops/instanceKlass.cpp | 403 +----------------- hotspot/src/share/vm/oops/instanceKlass.hpp | 62 +-- hotspot/src/share/vm/prims/jni.cpp | 4 +- hotspot/src/share/vm/prims/methodHandles.cpp | 64 ++- hotspot/src/share/vm/runtime/init.cpp | 3 + hotspot/src/share/vm/runtime/perfData.hpp | 1 + hotspot/src/share/vm/runtime/vmStructs.cpp | 5 - 12 files changed, 574 insertions(+), 491 deletions(-) create mode 100644 hotspot/src/share/vm/code/dependencyContext.cpp create mode 100644 hotspot/src/share/vm/code/dependencyContext.hpp diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index a9f7c4616c6..07e90977e3f 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -28,6 +28,7 @@ #include "classfile/stringTable.hpp" #include "classfile/vmSymbols.hpp" #include "code/debugInfo.hpp" +#include "code/dependencyContext.hpp" #include "code/pcDesc.hpp" #include "interpreter/interpreter.hpp" #include "memory/oopFactory.hpp" @@ -3216,14 +3217,16 @@ void java_lang_invoke_MethodHandleNatives_CallSiteContext::compute_offsets() { } } -nmethodBucket* java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(oop call_site) { +DependencyContext java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(oop call_site) { assert(java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(call_site), ""); - return (nmethodBucket*) (address) call_site->long_field(_vmdependencies_offset); -} - -void java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(oop call_site, nmethodBucket* context) { - assert(java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(call_site), ""); - call_site->long_field_put(_vmdependencies_offset, (jlong) (address) context); + intptr_t* vmdeps_addr = (intptr_t*)call_site->address_field_addr(_vmdependencies_offset); +#ifndef ASSERT + DependencyContext dep_ctx(vmdeps_addr); +#else + // Verify that call_site isn't moved during DependencyContext lifetime. + DependencyContext dep_ctx(vmdeps_addr, Handle(call_site)); +#endif // ASSERT + return dep_ctx; } // Support for java_security_AccessControlContext diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 403e33e9ee3..27f471e63be 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -1212,6 +1212,8 @@ public: #define CALLSITECONTEXT_INJECTED_FIELDS(macro) \ macro(java_lang_invoke_MethodHandleNatives_CallSiteContext, vmdependencies, intptr_signature, false) +class DependencyContext; + class java_lang_invoke_MethodHandleNatives_CallSiteContext : AllStatic { friend class JavaClasses; @@ -1222,8 +1224,7 @@ private: public: // Accessors - static nmethodBucket* vmdependencies(oop context); - static void set_vmdependencies(oop context, nmethodBucket* bucket); + static DependencyContext vmdependencies(oop context); // Testers static bool is_subclass(Klass* klass) { diff --git a/hotspot/src/share/vm/code/dependencyContext.cpp b/hotspot/src/share/vm/code/dependencyContext.cpp new file mode 100644 index 00000000000..50e6dead019 --- /dev/null +++ b/hotspot/src/share/vm/code/dependencyContext.cpp @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "code/nmethod.hpp" +#include "code/dependencies.hpp" +#include "code/dependencyContext.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/atomic.hpp" +#include "runtime/perfData.hpp" +#include "utilities/exceptions.hpp" + +PerfCounter* DependencyContext::_perf_total_buckets_allocated_count = NULL; +PerfCounter* DependencyContext::_perf_total_buckets_deallocated_count = NULL; +PerfCounter* DependencyContext::_perf_total_buckets_stale_count = NULL; +PerfCounter* DependencyContext::_perf_total_buckets_stale_acc_count = NULL; + +void dependencyContext_init() { + DependencyContext::init(); +} + +void DependencyContext::init() { + if (UsePerfData) { + EXCEPTION_MARK; + _perf_total_buckets_allocated_count = + PerfDataManager::create_counter(SUN_CI, "nmethodBucketsAllocated", PerfData::U_Events, CHECK); + _perf_total_buckets_deallocated_count = + PerfDataManager::create_counter(SUN_CI, "nmethodBucketsDeallocated", PerfData::U_Events, CHECK); + _perf_total_buckets_stale_count = + PerfDataManager::create_counter(SUN_CI, "nmethodBucketsStale", PerfData::U_Events, CHECK); + _perf_total_buckets_stale_acc_count = + PerfDataManager::create_counter(SUN_CI, "nmethodBucketsStaleAccumulated", PerfData::U_Events, CHECK); + } +} + +// +// Walk the list of dependent nmethods searching for nmethods which +// are dependent on the changes that were passed in and mark them for +// deoptimization. Returns the number of nmethods found. +// +int DependencyContext::mark_dependent_nmethods(DepChange& changes) { + int found = 0; + for (nmethodBucket* b = dependencies(); b != NULL; b = b->next()) { + nmethod* nm = b->get_nmethod(); + // since dependencies aren't removed until an nmethod becomes a zombie, + // the dependency list may contain nmethods which aren't alive. + if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization() && nm->check_dependency_on(changes)) { + if (TraceDependencies) { + ResourceMark rm; + tty->print_cr("Marked for deoptimization"); + changes.print(); + nm->print(); + nm->print_dependencies(); + } + nm->mark_for_deoptimization(); + found++; + } + } + return found; +} + +// +// Add an nmethod to the dependency context. +// It's possible that an nmethod has multiple dependencies on a klass +// so a count is kept for each bucket to guarantee that creation and +// deletion of dependencies is consistent. +// +void DependencyContext::add_dependent_nmethod(nmethod* nm, bool expunge) { + assert_lock_strong(CodeCache_lock); + for (nmethodBucket* b = dependencies(); b != NULL; b = b->next()) { + if (nm == b->get_nmethod()) { + b->increment(); + return; + } + } + set_dependencies(new nmethodBucket(nm, dependencies())); + if (UsePerfData) { + _perf_total_buckets_allocated_count->inc(); + } + if (expunge) { + // Remove stale entries from the list. + expunge_stale_entries(); + } +} + +// +// Remove an nmethod dependency from the context. +// Decrement count of the nmethod in the dependency list and, optionally, remove +// the bucket completely when the count goes to 0. This method must find +// a corresponding bucket otherwise there's a bug in the recording of dependencies. +// Can be called concurrently by parallel GC threads. +// +void DependencyContext::remove_dependent_nmethod(nmethod* nm, bool expunge) { + assert_locked_or_safepoint(CodeCache_lock); + nmethodBucket* first = dependencies(); + nmethodBucket* last = NULL; + for (nmethodBucket* b = first; b != NULL; b = b->next()) { + if (nm == b->get_nmethod()) { + int val = b->decrement(); + guarantee(val >= 0, "Underflow: %d", val); + if (val == 0) { + if (expunge) { + if (last == NULL) { + set_dependencies(b->next()); + } else { + last->set_next(b->next()); + } + delete b; + if (UsePerfData) { + _perf_total_buckets_deallocated_count->inc(); + } + } else { + // Mark the context as having stale entries, since it is not safe to + // expunge the list right now. + set_has_stale_entries(true); + if (UsePerfData) { + _perf_total_buckets_stale_count->inc(); + _perf_total_buckets_stale_acc_count->inc(); + } + } + } + if (expunge) { + // Remove stale entries from the list. + expunge_stale_entries(); + } + return; + } + last = b; + } +#ifdef ASSERT + tty->print_raw_cr("### can't find dependent nmethod"); + nm->print(); +#endif // ASSERT + ShouldNotReachHere(); +} + +// +// Reclaim all unused buckets. +// +void DependencyContext::expunge_stale_entries() { + assert_locked_or_safepoint(CodeCache_lock); + if (!has_stale_entries()) { + assert(!find_stale_entries(), "inconsistent info"); + return; + } + nmethodBucket* first = dependencies(); + nmethodBucket* last = NULL; + int removed = 0; + for (nmethodBucket* b = first; b != NULL;) { + assert(b->count() >= 0, "bucket count: %d", b->count()); + nmethodBucket* next = b->next(); + if (b->count() == 0) { + if (last == NULL) { + first = next; + } else { + last->set_next(next); + } + removed++; + delete b; + // last stays the same. + } else { + last = b; + } + b = next; + } + set_dependencies(first); + set_has_stale_entries(false); + if (UsePerfData && removed > 0) { + _perf_total_buckets_deallocated_count->inc(removed); + _perf_total_buckets_stale_count->dec(removed); + } +} + +// +// Invalidate all dependencies in the context +int DependencyContext::remove_all_dependents() { + assert_locked_or_safepoint(CodeCache_lock); + nmethodBucket* b = dependencies(); + set_dependencies(NULL); + int marked = 0; + int removed = 0; + while (b != NULL) { + nmethod* nm = b->get_nmethod(); + if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization()) { + nm->mark_for_deoptimization(); + marked++; + } + nmethodBucket* next = b->next(); + removed++; + delete b; + b = next; + } + set_has_stale_entries(false); + if (UsePerfData && removed > 0) { + _perf_total_buckets_deallocated_count->inc(removed); + } + return marked; +} + +#ifndef PRODUCT +void DependencyContext::print_dependent_nmethods(bool verbose) { + int idx = 0; + for (nmethodBucket* b = dependencies(); b != NULL; b = b->next()) { + nmethod* nm = b->get_nmethod(); + tty->print("[%d] count=%d { ", idx++, b->count()); + if (!verbose) { + nm->print_on(tty, "nmethod"); + tty->print_cr(" } "); + } else { + nm->print(); + nm->print_dependencies(); + tty->print_cr("--- } "); + } + } +} + +bool DependencyContext::is_dependent_nmethod(nmethod* nm) { + for (nmethodBucket* b = dependencies(); b != NULL; b = b->next()) { + if (nm == b->get_nmethod()) { +#ifdef ASSERT + int count = b->count(); + assert(count >= 0, "count shouldn't be negative: %d", count); +#endif + return true; + } + } + return false; +} + +bool DependencyContext::find_stale_entries() { + for (nmethodBucket* b = dependencies(); b != NULL; b = b->next()) { + if (b->count() == 0) return true; + } + return false; +} + +#endif //PRODUCT + +int nmethodBucket::decrement() { + return Atomic::add(-1, (volatile int *)&_count); +} + +/////////////// Unit tests /////////////// + +#ifndef PRODUCT + +class TestDependencyContext { + public: + nmethod* _nmethods[3]; + + intptr_t _dependency_context; + + TestDependencyContext() : _dependency_context(DependencyContext::EMPTY) { + CodeCache_lock->lock_without_safepoint_check(); + + DependencyContext depContext(&_dependency_context); + + _nmethods[0] = reinterpret_cast(0x8 * 0); + _nmethods[1] = reinterpret_cast(0x8 * 1); + _nmethods[2] = reinterpret_cast(0x8 * 2); + + depContext.add_dependent_nmethod(_nmethods[2]); + depContext.add_dependent_nmethod(_nmethods[1]); + depContext.add_dependent_nmethod(_nmethods[0]); + } + + ~TestDependencyContext() { + wipe(); + CodeCache_lock->unlock(); + } + + static void testRemoveDependentNmethod(int id, bool delete_immediately) { + TestDependencyContext c; + DependencyContext depContext(&c._dependency_context); + assert(!has_stale_entries(depContext), "check"); + + nmethod* nm = c._nmethods[id]; + depContext.remove_dependent_nmethod(nm, delete_immediately); + + if (!delete_immediately) { + assert(has_stale_entries(depContext), "check"); + assert(depContext.is_dependent_nmethod(nm), "check"); + depContext.expunge_stale_entries(); + } + + assert(!has_stale_entries(depContext), "check"); + assert(!depContext.is_dependent_nmethod(nm), "check"); + } + + static void testRemoveDependentNmethod() { + testRemoveDependentNmethod(0, false); + testRemoveDependentNmethod(1, false); + testRemoveDependentNmethod(2, false); + + testRemoveDependentNmethod(0, true); + testRemoveDependentNmethod(1, true); + testRemoveDependentNmethod(2, true); + } + + static void test() { + testRemoveDependentNmethod(); + } + + static bool has_stale_entries(DependencyContext ctx) { + assert(ctx.has_stale_entries() == ctx.find_stale_entries(), "check"); + return ctx.has_stale_entries(); + } + + void wipe() { + DependencyContext ctx(&_dependency_context); + nmethodBucket* b = ctx.dependencies(); + ctx.set_dependencies(NULL); + ctx.set_has_stale_entries(false); + while (b != NULL) { + nmethodBucket* next = b->next(); + delete b; + b = next; + } + } +}; + +void TestDependencyContext_test() { + TestDependencyContext::test(); +} + +#endif // PRODUCT diff --git a/hotspot/src/share/vm/code/dependencyContext.hpp b/hotspot/src/share/vm/code/dependencyContext.hpp new file mode 100644 index 00000000000..2daa26d81ee --- /dev/null +++ b/hotspot/src/share/vm/code/dependencyContext.hpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_CODE_DEPENDENCYCONTEXT_HPP +#define SHARE_VM_CODE_DEPENDENCYCONTEXT_HPP + +#include "memory/allocation.hpp" +#include "oops/oop.hpp" +#include "runtime/handles.hpp" +#include "runtime/perfData.hpp" + +class nmethod; +class DepChange; + +// +// nmethodBucket is used to record dependent nmethods for +// deoptimization. nmethod dependencies are actually +// pairs but we really only care about the klass part for purposes of +// finding nmethods which might need to be deoptimized. Instead of +// recording the method, a count of how many times a particular nmethod +// was recorded is kept. This ensures that any recording errors are +// noticed since an nmethod should be removed as many times are it's +// added. +// +class nmethodBucket: public CHeapObj { + friend class VMStructs; + private: + nmethod* _nmethod; + int _count; + nmethodBucket* _next; + + public: + nmethodBucket(nmethod* nmethod, nmethodBucket* next) : + _nmethod(nmethod), _next(next), _count(1) {} + + int count() { return _count; } + int increment() { _count += 1; return _count; } + int decrement(); + nmethodBucket* next() { return _next; } + void set_next(nmethodBucket* b) { _next = b; } + nmethod* get_nmethod() { return _nmethod; } +}; + +// +// Utility class to manipulate nmethod dependency context. +// The context consists of nmethodBucket* (a head of a linked list) +// and a boolean flag (does the list contains stale entries). The structure is +// encoded as an intptr_t: lower bit is used for the flag. It is possible since +// nmethodBucket* is aligned - the structure is malloc'ed in C heap. +// Dependency context can be attached either to an InstanceKlass (_dep_context field) +// or CallSiteContext oop for call_site_target dependencies (see javaClasses.hpp). +// DependencyContext class operates on some location which holds a intptr_t value. +// +class DependencyContext : public StackObj { + friend class VMStructs; + friend class TestDependencyContext; + private: + enum TagBits { _has_stale_entries_bit = 1, _has_stale_entries_mask = 1 }; + + intptr_t* _dependency_context_addr; + + void set_dependencies(nmethodBucket* b) { + assert((intptr_t(b) & _has_stale_entries_mask) == 0, "should be aligned"); + if (has_stale_entries()) { + *_dependency_context_addr = intptr_t(b) | _has_stale_entries_mask; + } else { + *_dependency_context_addr = intptr_t(b); + } + } + + void set_has_stale_entries(bool x) { + if (x) { + *_dependency_context_addr |= _has_stale_entries_mask; + } else { + *_dependency_context_addr &= ~_has_stale_entries_mask; + } + } + + nmethodBucket* dependencies() { + intptr_t value = *_dependency_context_addr; + return (nmethodBucket*) (value & ~_has_stale_entries_mask); + } + + bool has_stale_entries() const { + intptr_t value = *_dependency_context_addr; + return (value & _has_stale_entries_mask) != 0; + } + + static PerfCounter* _perf_total_buckets_allocated_count; + static PerfCounter* _perf_total_buckets_deallocated_count; + static PerfCounter* _perf_total_buckets_stale_count; + static PerfCounter* _perf_total_buckets_stale_acc_count; + + public: +#ifdef ASSERT + // Verification for dependency contexts rooted at Java objects. + Handle _base; // non-NULL if dependency context resides in an oop (e.g. CallSite). + oop _base_oop; + + DependencyContext(intptr_t* addr, Handle base = Handle()) + : _dependency_context_addr(addr), _base(base) + { + _base_oop = _base(); + } + + ~DependencyContext() { + // Base oop relocation invalidates _dependency_context_addr. + assert(_base_oop == _base(), "base oop relocation is forbidden"); + } +#else + DependencyContext(intptr_t* addr) : _dependency_context_addr(addr) {} +#endif // ASSERT + + static const intptr_t EMPTY = 0; // dependencies = NULL, has_stale_entries = false + + static void init(); + + int mark_dependent_nmethods(DepChange& changes); + void add_dependent_nmethod(nmethod* nm, bool expunge_stale_entries = false); + void remove_dependent_nmethod(nmethod* nm, bool expunge_stale_entries = false); + int remove_all_dependents(); + + void expunge_stale_entries(); + +#ifndef PRODUCT + void print_dependent_nmethods(bool verbose); + bool is_dependent_nmethod(nmethod* nm); + bool find_stale_entries(); +#endif //PRODUCT +}; +#endif // SHARE_VM_CODE_DEPENDENCYCONTEXT_HPP diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index ff97e33dbcc..01fa05d633e 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -26,6 +26,7 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" +#include "code/dependencyContext.hpp" #include "compiler/compileBroker.hpp" #include "compiler/compileLog.hpp" #include "compiler/compilerOracle.hpp" @@ -547,7 +548,6 @@ void CompileBroker::compilation_init() { PerfData::U_Ticks, CHECK); } - if (UsePerfData) { EXCEPTION_MARK; diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 03584ee0320..fb9e2ab6d6f 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -27,6 +27,7 @@ #include "classfile/systemDictionary.hpp" #include "classfile/verifier.hpp" #include "classfile/vmSymbols.hpp" +#include "code/dependencyContext.hpp" #include "compiler/compileBroker.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/specialized_oop_closures.hpp" @@ -203,7 +204,6 @@ InstanceKlass::InstanceKlass(int vtable_len, int iksize = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size, access_flags.is_interface(), is_anonymous); - set_vtable_length(vtable_len); set_itable_length(itable_len); set_static_field_size(static_field_size); @@ -232,7 +232,7 @@ InstanceKlass::InstanceKlass(int vtable_len, set_static_oop_field_count(0); set_nonstatic_field_size(0); set_is_marked_dependent(false); - set_has_unloaded_dependent(false); + _dep_context = DependencyContext::EMPTY; set_init_state(InstanceKlass::allocated); set_init_thread(NULL); set_reference_type(rt); @@ -246,7 +246,6 @@ InstanceKlass::InstanceKlass(int vtable_len, set_annotations(NULL); set_jvmti_cached_class_field_map(NULL); set_initial_method_idnum(0); - _dependencies = NULL; set_jvmti_cached_class_field_map(NULL); set_cached_class_file(NULL); set_initial_method_idnum(0); @@ -1854,200 +1853,30 @@ jmethodID InstanceKlass::jmethod_id_or_null(Method* method) { return id; } -int nmethodBucket::decrement() { - return Atomic::add(-1, (volatile int *)&_count); +inline DependencyContext InstanceKlass::dependencies() { + DependencyContext dep_context(&_dep_context); + return dep_context; } -// -// Walk the list of dependent nmethods searching for nmethods which -// are dependent on the changes that were passed in and mark them for -// deoptimization. Returns the number of nmethods found. -// -int nmethodBucket::mark_dependent_nmethods(nmethodBucket* deps, DepChange& changes) { - assert_locked_or_safepoint(CodeCache_lock); - int found = 0; - for (nmethodBucket* b = deps; b != NULL; b = b->next()) { - nmethod* nm = b->get_nmethod(); - // since dependencies aren't removed until an nmethod becomes a zombie, - // the dependency list may contain nmethods which aren't alive. - if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization() && nm->check_dependency_on(changes)) { - if (TraceDependencies) { - ResourceMark rm; - tty->print_cr("Marked for deoptimization"); - changes.print(); - nm->print(); - nm->print_dependencies(); - } - nm->mark_for_deoptimization(); - found++; - } - } - return found; -} - -// -// Add an nmethodBucket to the list of dependencies for this nmethod. -// It's possible that an nmethod has multiple dependencies on this klass -// so a count is kept for each bucket to guarantee that creation and -// deletion of dependencies is consistent. Returns new head of the list. -// -nmethodBucket* nmethodBucket::add_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { - assert_locked_or_safepoint(CodeCache_lock); - for (nmethodBucket* b = deps; b != NULL; b = b->next()) { - if (nm == b->get_nmethod()) { - b->increment(); - return deps; - } - } - return new nmethodBucket(nm, deps); -} - -// -// Decrement count of the nmethod in the dependency list and remove -// the bucket completely when the count goes to 0. This method must -// find a corresponding bucket otherwise there's a bug in the -// recording of dependencies. Returns true if the bucket was deleted, -// or marked ready for reclaimation. -bool nmethodBucket::remove_dependent_nmethod(nmethodBucket** deps, nmethod* nm, bool delete_immediately) { - assert_locked_or_safepoint(CodeCache_lock); - - nmethodBucket* first = *deps; - nmethodBucket* last = NULL; - - for (nmethodBucket* b = first; b != NULL; b = b->next()) { - if (nm == b->get_nmethod()) { - int val = b->decrement(); - guarantee(val >= 0, "Underflow: %d", val); - if (val == 0) { - if (delete_immediately) { - if (last == NULL) { - *deps = b->next(); - } else { - last->set_next(b->next()); - } - delete b; - } - } - return true; - } - last = b; - } - -#ifdef ASSERT - tty->print_raw_cr("### can't find dependent nmethod"); - nm->print(); -#endif // ASSERT - ShouldNotReachHere(); - return false; -} - -// Convenience overload, for callers that don't want to delete the nmethodBucket entry. -bool nmethodBucket::remove_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { - nmethodBucket** deps_addr = &deps; - return remove_dependent_nmethod(deps_addr, nm, false /* Don't delete */); -} - -// -// Reclaim all unused buckets. Returns new head of the list. -// -nmethodBucket* nmethodBucket::clean_dependent_nmethods(nmethodBucket* deps) { - nmethodBucket* first = deps; - nmethodBucket* last = NULL; - nmethodBucket* b = first; - - while (b != NULL) { - assert(b->count() >= 0, "bucket count: %d", b->count()); - nmethodBucket* next = b->next(); - if (b->count() == 0) { - if (last == NULL) { - first = next; - } else { - last->set_next(next); - } - delete b; - // last stays the same. - } else { - last = b; - } - b = next; - } - return first; -} - -#ifndef PRODUCT -void nmethodBucket::print_dependent_nmethods(nmethodBucket* deps, bool verbose) { - int idx = 0; - for (nmethodBucket* b = deps; b != NULL; b = b->next()) { - nmethod* nm = b->get_nmethod(); - tty->print("[%d] count=%d { ", idx++, b->count()); - if (!verbose) { - nm->print_on(tty, "nmethod"); - tty->print_cr(" } "); - } else { - nm->print(); - nm->print_dependencies(); - tty->print_cr("--- } "); - } - } -} - -bool nmethodBucket::is_dependent_nmethod(nmethodBucket* deps, nmethod* nm) { - for (nmethodBucket* b = deps; b != NULL; b = b->next()) { - if (nm == b->get_nmethod()) { -#ifdef ASSERT - int count = b->count(); - assert(count >= 0, "count shouldn't be negative: %d", count); -#endif - return true; - } - } - return false; -} -#endif //PRODUCT - int InstanceKlass::mark_dependent_nmethods(DepChange& changes) { - assert_locked_or_safepoint(CodeCache_lock); - return nmethodBucket::mark_dependent_nmethods(_dependencies, changes); -} - -void InstanceKlass::clean_dependent_nmethods() { - assert_locked_or_safepoint(CodeCache_lock); - - if (has_unloaded_dependent()) { - _dependencies = nmethodBucket::clean_dependent_nmethods(_dependencies); - set_has_unloaded_dependent(false); - } -#ifdef ASSERT - else { - // Verification - for (nmethodBucket* b = _dependencies; b != NULL; b = b->next()) { - assert(b->count() >= 0, "bucket count: %d", b->count()); - assert(b->count() != 0, "empty buckets need to be cleaned"); - } - } -#endif + return dependencies().mark_dependent_nmethods(changes); } void InstanceKlass::add_dependent_nmethod(nmethod* nm) { - assert_locked_or_safepoint(CodeCache_lock); - _dependencies = nmethodBucket::add_dependent_nmethod(_dependencies, nm); + dependencies().add_dependent_nmethod(nm); } void InstanceKlass::remove_dependent_nmethod(nmethod* nm, bool delete_immediately) { - assert_locked_or_safepoint(CodeCache_lock); - - if (nmethodBucket::remove_dependent_nmethod(&_dependencies, nm, delete_immediately)) { - set_has_unloaded_dependent(true); - } + dependencies().remove_dependent_nmethod(nm, delete_immediately); } #ifndef PRODUCT void InstanceKlass::print_dependent_nmethods(bool verbose) { - nmethodBucket::print_dependent_nmethods(_dependencies, verbose); + dependencies().print_dependent_nmethods(verbose); } bool InstanceKlass::is_dependent_nmethod(nmethod* nm) { - return nmethodBucket::is_dependent_nmethod(_dependencies, nm); + return dependencies().is_dependent_nmethod(nm); } #endif //PRODUCT @@ -2055,7 +1884,9 @@ void InstanceKlass::clean_weak_instanceklass_links(BoolObjectClosure* is_alive) clean_implementors_list(is_alive); clean_method_data(is_alive); - clean_dependent_nmethods(); + // Since GC iterates InstanceKlasses sequentially, it is safe to remove stale entries here. + DependencyContext dep_context(&_dep_context); + dep_context.expunge_stale_entries(); } void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) { @@ -2102,6 +1933,8 @@ void InstanceKlass::remove_unshareable_info() { constants()->remove_unshareable_info(); + assert(_dep_context == DependencyContext::EMPTY, "dependency context is not shareable"); + for (int i = 0; i < methods()->length(); i++) { Method* m = methods()->at(i); m->remove_unshareable_info(); @@ -2231,12 +2064,10 @@ void InstanceKlass::release_C_heap_structures() { } // release dependencies - nmethodBucket* b = _dependencies; - _dependencies = NULL; - while (b != NULL) { - nmethodBucket* next = b->next(); - delete b; - b = next; + { + DependencyContext ctx(&_dep_context); + int marked = ctx.remove_all_dependents(); + assert(marked == 0, "all dependencies should be already invalidated"); } // Deallocate breakpoint records @@ -3558,199 +3389,3 @@ jint InstanceKlass::get_cached_class_file_len() { unsigned char * InstanceKlass::get_cached_class_file_bytes() { return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file); } - - -/////////////// Unit tests /////////////// - -#ifndef PRODUCT - -class TestNmethodBucketContext { - public: - nmethod* _nmethodLast; - nmethod* _nmethodMiddle; - nmethod* _nmethodFirst; - - nmethodBucket* _bucketLast; - nmethodBucket* _bucketMiddle; - nmethodBucket* _bucketFirst; - - nmethodBucket* _bucketList; - - TestNmethodBucketContext() { - CodeCache_lock->lock_without_safepoint_check(); - - _nmethodLast = reinterpret_cast(0x8 * 0); - _nmethodMiddle = reinterpret_cast(0x8 * 1); - _nmethodFirst = reinterpret_cast(0x8 * 2); - - _bucketLast = new nmethodBucket(_nmethodLast, NULL); - _bucketMiddle = new nmethodBucket(_nmethodMiddle, _bucketLast); - _bucketFirst = new nmethodBucket(_nmethodFirst, _bucketMiddle); - - _bucketList = _bucketFirst; - } - - ~TestNmethodBucketContext() { - delete _bucketLast; - delete _bucketMiddle; - delete _bucketFirst; - - CodeCache_lock->unlock(); - } -}; - -class TestNmethodBucket { - public: - static void testRemoveDependentNmethodFirstDeleteImmediately() { - TestNmethodBucketContext c; - - nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodFirst, true /* delete */); - - assert(c._bucketList == c._bucketMiddle, "check"); - assert(c._bucketList->next() == c._bucketLast, "check"); - assert(c._bucketList->next()->next() == NULL, "check"); - - // Cleanup before context is deleted. - c._bucketFirst = NULL; - } - - static void testRemoveDependentNmethodMiddleDeleteImmediately() { - TestNmethodBucketContext c; - - nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodMiddle, true /* delete */); - - assert(c._bucketList == c._bucketFirst, "check"); - assert(c._bucketList->next() == c._bucketLast, "check"); - assert(c._bucketList->next()->next() == NULL, "check"); - - // Cleanup before context is deleted. - c._bucketMiddle = NULL; - } - - static void testRemoveDependentNmethodLastDeleteImmediately() { - TestNmethodBucketContext c; - - nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodLast, true /* delete */); - - assert(c._bucketList == c._bucketFirst, "check"); - assert(c._bucketList->next() == c._bucketMiddle, "check"); - assert(c._bucketList->next()->next() == NULL, "check"); - - // Cleanup before context is deleted. - c._bucketLast = NULL; - } - - static void testRemoveDependentNmethodFirstDeleteDeferred() { - TestNmethodBucketContext c; - - nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodFirst, false /* delete */); - - assert(c._bucketList == c._bucketFirst, "check"); - assert(c._bucketList->next() == c._bucketMiddle, "check"); - assert(c._bucketList->next()->next() == c._bucketLast, "check"); - assert(c._bucketList->next()->next()->next() == NULL, "check"); - - assert(c._bucketFirst->count() == 0, "check"); - assert(c._bucketMiddle->count() == 1, "check"); - assert(c._bucketLast->count() == 1, "check"); - } - - static void testRemoveDependentNmethodMiddleDeleteDeferred() { - TestNmethodBucketContext c; - - nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodMiddle, false /* delete */); - - assert(c._bucketList == c._bucketFirst, "check"); - assert(c._bucketList->next() == c._bucketMiddle, "check"); - assert(c._bucketList->next()->next() == c._bucketLast, "check"); - assert(c._bucketList->next()->next()->next() == NULL, "check"); - - assert(c._bucketFirst->count() == 1, "check"); - assert(c._bucketMiddle->count() == 0, "check"); - assert(c._bucketLast->count() == 1, "check"); - } - - static void testRemoveDependentNmethodLastDeleteDeferred() { - TestNmethodBucketContext c; - - nmethodBucket::remove_dependent_nmethod(&c._bucketList, c._nmethodLast, false /* delete */); - - assert(c._bucketList == c._bucketFirst, "check"); - assert(c._bucketList->next() == c._bucketMiddle, "check"); - assert(c._bucketList->next()->next() == c._bucketLast, "check"); - assert(c._bucketList->next()->next()->next() == NULL, "check"); - - assert(c._bucketFirst->count() == 1, "check"); - assert(c._bucketMiddle->count() == 1, "check"); - assert(c._bucketLast->count() == 0, "check"); - } - - static void testRemoveDependentNmethodConvenienceFirst() { - TestNmethodBucketContext c; - - nmethodBucket::remove_dependent_nmethod(c._bucketList, c._nmethodFirst); - - assert(c._bucketList == c._bucketFirst, "check"); - assert(c._bucketList->next() == c._bucketMiddle, "check"); - assert(c._bucketList->next()->next() == c._bucketLast, "check"); - assert(c._bucketList->next()->next()->next() == NULL, "check"); - - assert(c._bucketFirst->count() == 0, "check"); - assert(c._bucketMiddle->count() == 1, "check"); - assert(c._bucketLast->count() == 1, "check"); - } - - static void testRemoveDependentNmethodConvenienceMiddle() { - TestNmethodBucketContext c; - - nmethodBucket::remove_dependent_nmethod(c._bucketList, c._nmethodMiddle); - - assert(c._bucketList == c._bucketFirst, "check"); - assert(c._bucketList->next() == c._bucketMiddle, "check"); - assert(c._bucketList->next()->next() == c._bucketLast, "check"); - assert(c._bucketList->next()->next()->next() == NULL, "check"); - - assert(c._bucketFirst->count() == 1, "check"); - assert(c._bucketMiddle->count() == 0, "check"); - assert(c._bucketLast->count() == 1, "check"); - } - - static void testRemoveDependentNmethodConvenienceLast() { - TestNmethodBucketContext c; - - nmethodBucket::remove_dependent_nmethod(c._bucketList, c._nmethodLast); - - assert(c._bucketList == c._bucketFirst, "check"); - assert(c._bucketList->next() == c._bucketMiddle, "check"); - assert(c._bucketList->next()->next() == c._bucketLast, "check"); - assert(c._bucketList->next()->next()->next() == NULL, "check"); - - assert(c._bucketFirst->count() == 1, "check"); - assert(c._bucketMiddle->count() == 1, "check"); - assert(c._bucketLast->count() == 0, "check"); - } - - static void testRemoveDependentNmethod() { - testRemoveDependentNmethodFirstDeleteImmediately(); - testRemoveDependentNmethodMiddleDeleteImmediately(); - testRemoveDependentNmethodLastDeleteImmediately(); - - testRemoveDependentNmethodFirstDeleteDeferred(); - testRemoveDependentNmethodMiddleDeleteDeferred(); - testRemoveDependentNmethodLastDeleteDeferred(); - - testRemoveDependentNmethodConvenienceFirst(); - testRemoveDependentNmethodConvenienceMiddle(); - testRemoveDependentNmethodConvenienceLast(); - } - - static void test() { - testRemoveDependentNmethod(); - } -}; - -void TestNmethodBucket_test() { - TestNmethodBucket::test(); -} - -#endif diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index 9eebfcb7010..ca5262346a1 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -53,15 +53,15 @@ // forward declaration for class -- see below for definition -class SuperTypeClosure; -class JNIid; -class jniIdMapBase; class BreakpointInfo; -class fieldDescriptor; class DepChange; -class nmethodBucket; +class DependencyContext; +class fieldDescriptor; +class jniIdMapBase; +class JNIid; class JvmtiCachedClassFieldMap; class MemberNameTable; +class SuperTypeClosure; // This is used in iterators below. class FieldClosure: public StackObj { @@ -198,7 +198,6 @@ class InstanceKlass: public Klass { // _is_marked_dependent can be set concurrently, thus cannot be part of the // _misc_flags. bool _is_marked_dependent; // used for marking during flushing and deoptimization - bool _has_unloaded_dependent; // The low two bits of _misc_flags contains the kind field. // This can be used to quickly discriminate among the four kinds of @@ -235,7 +234,7 @@ class InstanceKlass: public Klass { MemberNameTable* _member_names; // Member names JNIid* _jni_ids; // First JNI identifier for static fields in this class jmethodID* _methods_jmethod_ids; // jmethodIDs corresponding to method_idnum, or NULL if none - nmethodBucket* _dependencies; // list of dependent nmethods + intptr_t _dep_context; // packed DependencyContext structure nmethod* _osr_nmethods_head; // Head of list of on-stack replacement nmethods for this class BreakpointInfo* _breakpoints; // bpt lists, managed by Method* // Linked instanceKlasses of previous versions @@ -468,9 +467,6 @@ class InstanceKlass: public Klass { bool is_marked_dependent() const { return _is_marked_dependent; } void set_is_marked_dependent(bool value) { _is_marked_dependent = value; } - bool has_unloaded_dependent() const { return _has_unloaded_dependent; } - void set_has_unloaded_dependent(bool value) { _has_unloaded_dependent = value; } - // initialization (virtuals from Klass) bool should_be_initialized() const; // means that initialize should be called void initialize(TRAPS); @@ -835,7 +831,8 @@ public: JNIid* jni_id_for(int offset); // maintenance of deoptimization dependencies - int mark_dependent_nmethods(DepChange& changes); + inline DependencyContext dependencies(); + int mark_dependent_nmethods(DepChange& changes); void add_dependent_nmethod(nmethod* nm); void remove_dependent_nmethod(nmethod* nm, bool delete_immediately); @@ -1027,7 +1024,6 @@ public: void clean_weak_instanceklass_links(BoolObjectClosure* is_alive); void clean_implementors_list(BoolObjectClosure* is_alive); void clean_method_data(BoolObjectClosure* is_alive); - void clean_dependent_nmethods(); // Explicit metaspace deallocation of fields // For RedefineClasses and class file parsing errors, we need to deallocate @@ -1320,48 +1316,6 @@ class JNIid: public CHeapObj { void verify(Klass* holder); }; - -// -// nmethodBucket is used to record dependent nmethods for -// deoptimization. nmethod dependencies are actually -// pairs but we really only care about the klass part for purposes of -// finding nmethods which might need to be deoptimized. Instead of -// recording the method, a count of how many times a particular nmethod -// was recorded is kept. This ensures that any recording errors are -// noticed since an nmethod should be removed as many times are it's -// added. -// -class nmethodBucket: public CHeapObj { - friend class VMStructs; - private: - nmethod* _nmethod; - int _count; - nmethodBucket* _next; - - public: - nmethodBucket(nmethod* nmethod, nmethodBucket* next) { - _nmethod = nmethod; - _next = next; - _count = 1; - } - int count() { return _count; } - int increment() { _count += 1; return _count; } - int decrement(); - nmethodBucket* next() { return _next; } - void set_next(nmethodBucket* b) { _next = b; } - nmethod* get_nmethod() { return _nmethod; } - - static int mark_dependent_nmethods(nmethodBucket* deps, DepChange& changes); - static nmethodBucket* add_dependent_nmethod(nmethodBucket* deps, nmethod* nm); - static bool remove_dependent_nmethod(nmethodBucket** deps, nmethod* nm, bool delete_immediately); - static bool remove_dependent_nmethod(nmethodBucket* deps, nmethod* nm); - static nmethodBucket* clean_dependent_nmethods(nmethodBucket* deps); -#ifndef PRODUCT - static void print_dependent_nmethods(nmethodBucket* deps, bool verbose); - static bool is_dependent_nmethod(nmethodBucket* deps, nmethod* nm); -#endif //PRODUCT -}; - // An iterator that's used to access the inner classes indices in the // InstanceKlass::_inner_classes array. class InnerClassesIterator : public StackObj { diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index fe1e939fd4f..f5ec37919ff 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -3878,7 +3878,7 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args_) { unit_test_function_call // Forward declaration -void TestNmethodBucket_test(); +void TestDependencyContext_test(); void test_semaphore(); void TestOS_test(); void TestReservedSpace_test(); @@ -3910,7 +3910,7 @@ void WorkerDataArray_test(); void execute_internal_vm_tests() { if (ExecuteInternalVMTests) { tty->print_cr("Running internal VM tests"); - run_unit_test(TestNmethodBucket_test()); + run_unit_test(TestDependencyContext_test()); run_unit_test(test_semaphore()); run_unit_test(TestOS_test()); run_unit_test(TestReservedSpace_test()); diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index 0f58dde7063..99e8a785f10 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -27,6 +27,7 @@ #include "classfile/stringTable.hpp" #include "code/codeCache.hpp" #include "code/codeCacheExtensions.hpp" +#include "code/dependencyContext.hpp" #include "compiler/compileBroker.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/oopMapCache.hpp" @@ -945,30 +946,33 @@ int MethodHandles::find_MemberNames(KlassHandle k, return rfill + overflow; } +// Is it safe to remove stale entries from a dependency list? +static bool safe_to_expunge() { + // Since parallel GC threads can concurrently iterate over a dependency + // list during safepoint, it is safe to remove entries only when + // CodeCache lock is held. + return CodeCache_lock->owned_by_self(); +} + void MethodHandles::add_dependent_nmethod(oop call_site, nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); oop context = java_lang_invoke_CallSite::context(call_site); - nmethodBucket* deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); - - nmethodBucket* new_deps = nmethodBucket::add_dependent_nmethod(deps, nm); - if (deps != new_deps) { - java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(context, new_deps); - } + DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); + // Try to purge stale entries on updates. + // Since GC doesn't clean dependency contexts rooted at CallSiteContext objects, + // in order to avoid memory leak, stale entries are purged whenever a dependency list + // is changed (both on addition and removal). Though memory reclamation is delayed, + // it avoids indefinite memory usage growth. + deps.add_dependent_nmethod(nm, /*expunge_stale_entries=*/safe_to_expunge()); } void MethodHandles::remove_dependent_nmethod(oop call_site, nmethod* nm) { assert_locked_or_safepoint(CodeCache_lock); oop context = java_lang_invoke_CallSite::context(call_site); - nmethodBucket* deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); - - if (nmethodBucket::remove_dependent_nmethod(deps, nm)) { - nmethodBucket* new_deps = nmethodBucket::clean_dependent_nmethods(deps); - if (deps != new_deps) { - java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(context, new_deps); - } - } + DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); + deps.remove_dependent_nmethod(nm, /*expunge_stale_entries=*/safe_to_expunge()); } void MethodHandles::flush_dependent_nmethods(Handle call_site, Handle target) { @@ -977,21 +981,15 @@ void MethodHandles::flush_dependent_nmethods(Handle call_site, Handle target) { int marked = 0; CallSiteDepChange changes(call_site(), target()); { + No_Safepoint_Verifier nsv; MutexLockerEx mu2(CodeCache_lock, Mutex::_no_safepoint_check_flag); oop context = java_lang_invoke_CallSite::context(call_site()); - nmethodBucket* deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); - - marked = nmethodBucket::mark_dependent_nmethods(deps, changes); - if (marked > 0) { - nmethodBucket* new_deps = nmethodBucket::clean_dependent_nmethods(deps); - if (deps != new_deps) { - java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(context, new_deps); - } - } + DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context); + marked = deps.mark_dependent_nmethods(changes); } if (marked > 0) { - // At least one nmethod has been marked for deoptimization + // At least one nmethod has been marked for deoptimization. VM_Deoptimize op; VMThread::execute(&op); } @@ -1331,6 +1329,8 @@ JVM_ENTRY(void, MHN_setCallSiteTargetVolatile(JNIEnv* env, jobject igcls, jobjec } JVM_END +// It is called by a Cleaner object which ensures that dropped CallSites properly +// deallocate their dependency information. JVM_ENTRY(void, MHN_clearCallSiteContext(JNIEnv* env, jobject igcls, jobject context_jh)) { Handle context(THREAD, JNIHandles::resolve_non_null(context_jh)); { @@ -1339,19 +1339,11 @@ JVM_ENTRY(void, MHN_clearCallSiteContext(JNIEnv* env, jobject igcls, jobject con int marked = 0; { + No_Safepoint_Verifier nsv; MutexLockerEx mu2(CodeCache_lock, Mutex::_no_safepoint_check_flag); - nmethodBucket* b = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context()); - while(b != NULL) { - nmethod* nm = b->get_nmethod(); - if (b->count() > 0 && nm->is_alive() && !nm->is_marked_for_deoptimization()) { - nm->mark_for_deoptimization(); - marked++; - } - nmethodBucket* next = b->next(); - delete b; - b = next; - } - java_lang_invoke_MethodHandleNatives_CallSiteContext::set_vmdependencies(context(), NULL); // reset context + assert(safe_to_expunge(), "removal is not safe"); + DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context()); + marked = deps.remove_all_dependents(); } if (marked > 0) { // At least one nmethod has been marked for deoptimization diff --git a/hotspot/src/share/vm/runtime/init.cpp b/hotspot/src/share/vm/runtime/init.cpp index e4d8fe241ac..616d18dfb78 100644 --- a/hotspot/src/share/vm/runtime/init.cpp +++ b/hotspot/src/share/vm/runtime/init.cpp @@ -72,6 +72,7 @@ void vtableStubs_init(); void InlineCacheBuffer_init(); void compilerOracle_init(); bool compileBroker_init(); +void dependencyContext_init(); // Initialization after compiler initialization bool universe_post_init(); // must happen after compiler_init @@ -131,6 +132,8 @@ jint init_globals() { vtableStubs_init(); InlineCacheBuffer_init(); compilerOracle_init(); + dependencyContext_init(); + if (!compileBroker_init()) { return JNI_EINVAL; } diff --git a/hotspot/src/share/vm/runtime/perfData.hpp b/hotspot/src/share/vm/runtime/perfData.hpp index 9fc89caa722..1887c524113 100644 --- a/hotspot/src/share/vm/runtime/perfData.hpp +++ b/hotspot/src/share/vm/runtime/perfData.hpp @@ -424,6 +424,7 @@ class PerfLongVariant : public PerfLong { public: inline void inc() { (*(jlong*)_valuep)++; } inline void inc(jlong val) { (*(jlong*)_valuep) += val; } + inline void dec(jlong val) { inc(-val); } inline void add(jlong val) { (*(jlong*)_valuep) += val; } void clear_sample_helper() { _sample_helper = NULL; } }; diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index c49e56ff226..13c7b35ac78 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -343,10 +343,6 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(InstanceKlass, _methods_jmethod_ids, jmethodID*) \ volatile_nonstatic_field(InstanceKlass, _idnum_allocated_count, u2) \ nonstatic_field(InstanceKlass, _annotations, Annotations*) \ - nonstatic_field(InstanceKlass, _dependencies, nmethodBucket*) \ - nonstatic_field(nmethodBucket, _nmethod, nmethod*) \ - nonstatic_field(nmethodBucket, _count, int) \ - nonstatic_field(nmethodBucket, _next, nmethodBucket*) \ nonstatic_field(InstanceKlass, _method_ordering, Array*) \ nonstatic_field(InstanceKlass, _default_vtable_indices, Array*) \ nonstatic_field(Klass, _super_check_offset, juint) \ @@ -1555,7 +1551,6 @@ typedef CompactHashtable SymbolCompactHashTable; declare_toplevel_type(volatile Metadata*) \ \ declare_toplevel_type(DataLayout) \ - declare_toplevel_type(nmethodBucket) \ \ /********/ \ /* Oops */ \ From 09c6215e3e85cb565b9c79d5b9e13f4453f6a49d Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Wed, 18 Nov 2015 09:43:31 -1000 Subject: [PATCH 042/260] 8141330: [JVMCI] avoid deadlock between application thread and JVMCI compiler thread under -Xbatch Reviewed-by: twisti --- .../src/share/vm/compiler/compileBroker.cpp | 75 ++++++++++++++----- hotspot/src/share/vm/compiler/compileTask.cpp | 1 + hotspot/src/share/vm/compiler/compileTask.hpp | 7 ++ 3 files changed, 65 insertions(+), 18 deletions(-) diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 01fa05d633e..e5eac46910c 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -238,10 +238,27 @@ CompileTaskWrapper::~CompileTaskWrapper() { task->set_code_handle(NULL); thread->set_env(NULL); if (task->is_blocking()) { - MutexLocker notifier(task->lock(), thread); - task->mark_complete(); - // Notify the waiting thread that the compilation has completed. - task->lock()->notify_all(); + bool free_task = false; + { + MutexLocker notifier(task->lock(), thread); + task->mark_complete(); +#if INCLUDE_JVMCI + if (CompileBroker::compiler(task->comp_level())->is_jvmci() && + !task->has_waiter()) { + // The waiting thread timed out and thus did not free the task. + free_task = true; + } +#endif + if (!free_task) { + // Notify the waiting thread that the compilation has completed + // so that it can free the task. + task->lock()->notify_all(); + } + } + if (free_task) { + // The task can only be freed once the task lock is released. + CompileTask::free(task); + } } else { task->mark_complete(); @@ -1302,6 +1319,11 @@ CompileTask* CompileBroker::create_compile_task(CompileQueue* queue, return new_task; } +// 1 second should be long enough to complete most JVMCI compilations +// and not too long to stall a blocking JVMCI compilation that +// is trying to acquire a lock held by the app thread that submitted the +// compilation. +static const long BLOCKING_JVMCI_COMPILATION_TIMEOUT = 1000; /** * Wait for the compilation task to complete. @@ -1318,30 +1340,47 @@ void CompileBroker::wait_for_completion(CompileTask* task) { thread->set_blocked_on_compilation(true); methodHandle method(thread, task->method()); + bool free_task; +#if INCLUDE_JVMCI + if (compiler(task->comp_level())->is_jvmci()) { + MutexLocker waiter(task->lock(), thread); + // No need to check if compilation has completed - just + // rely on the time out. The JVMCI compiler thread will + // recycle the CompileTask. + task->lock()->wait(!Mutex::_no_safepoint_check_flag, BLOCKING_JVMCI_COMPILATION_TIMEOUT); + // If the compilation completes while has_waiter is true then + // this thread is responsible for freeing the task. Otherwise + // the compiler thread will free the task. + task->clear_waiter(); + free_task = task->is_complete(); + } else +#endif { MutexLocker waiter(task->lock(), thread); - + free_task = true; while (!task->is_complete() && !is_compilation_disabled_forever()) { task->lock()->wait(); } } thread->set_blocked_on_compilation(false); - if (is_compilation_disabled_forever()) { + if (free_task) { + if (is_compilation_disabled_forever()) { + CompileTask::free(task); + return; + } + + // It is harmless to check this status without the lock, because + // completion is a stable property (until the task object is recycled). + assert(task->is_complete(), "Compilation should have completed"); + assert(task->code_handle() == NULL, "must be reset"); + + // By convention, the waiter is responsible for recycling a + // blocking CompileTask. Since there is only one waiter ever + // waiting on a CompileTask, we know that no one else will + // be using this CompileTask; we can free it. CompileTask::free(task); - return; } - - // It is harmless to check this status without the lock, because - // completion is a stable property (until the task object is recycled). - assert(task->is_complete(), "Compilation should have completed"); - assert(task->code_handle() == NULL, "must be reset"); - - // By convention, the waiter is responsible for recycling a - // blocking CompileTask. Since there is only one waiter ever - // waiting on a CompileTask, we know that no one else will - // be using this CompileTask; we can free it. - CompileTask::free(task); } /** diff --git a/hotspot/src/share/vm/compiler/compileTask.cpp b/hotspot/src/share/vm/compiler/compileTask.cpp index 0cd15c9592e..6ce37cd61e8 100644 --- a/hotspot/src/share/vm/compiler/compileTask.cpp +++ b/hotspot/src/share/vm/compiler/compileTask.cpp @@ -90,6 +90,7 @@ void CompileTask::initialize(int compile_id, _method_holder = JNIHandles::make_global(method->method_holder()->klass_holder()); _osr_bci = osr_bci; _is_blocking = is_blocking; + JVMCI_ONLY(_has_waiter = CompileBroker::compiler(comp_level)->is_jvmci();) _comp_level = comp_level; _num_inlined_bytecodes = 0; diff --git a/hotspot/src/share/vm/compiler/compileTask.hpp b/hotspot/src/share/vm/compiler/compileTask.hpp index b35d1345095..1ec57bd00ab 100644 --- a/hotspot/src/share/vm/compiler/compileTask.hpp +++ b/hotspot/src/share/vm/compiler/compileTask.hpp @@ -53,6 +53,9 @@ class CompileTask : public CHeapObj { bool _is_complete; bool _is_success; bool _is_blocking; +#if INCLUDE_JVMCI + bool _has_waiter; +#endif int _comp_level; int _num_inlined_bytecodes; nmethodLocker* _code_handle; // holder of eventual result @@ -85,6 +88,10 @@ class CompileTask : public CHeapObj { bool is_complete() const { return _is_complete; } bool is_blocking() const { return _is_blocking; } bool is_success() const { return _is_success; } +#if INCLUDE_JVMCI + bool has_waiter() const { return _has_waiter; } + void clear_waiter() { _has_waiter = false; } +#endif nmethodLocker* code_handle() const { return _code_handle; } void set_code_handle(nmethodLocker* l) { _code_handle = l; } From 7112a8bb9e05846dbec45d8ae98c2143602f9e08 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Wed, 18 Nov 2015 10:46:21 -1000 Subject: [PATCH 043/260] 8143151: [JVMCI] assertion for allocation of "too many" CompileTasks must take JVMCI into account Reviewed-by: iignatyev, twisti --- hotspot/src/share/vm/compiler/compileTask.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/compiler/compileTask.cpp b/hotspot/src/share/vm/compiler/compileTask.cpp index 6ce37cd61e8..a0efba91365 100644 --- a/hotspot/src/share/vm/compiler/compileTask.cpp +++ b/hotspot/src/share/vm/compiler/compileTask.cpp @@ -47,7 +47,7 @@ CompileTask* CompileTask::allocate() { } else { task = new CompileTask(); DEBUG_ONLY(_num_allocated_tasks++;) - assert (WhiteBoxAPI || _num_allocated_tasks < 10000, "Leaking compilation tasks?"); + assert (WhiteBoxAPI || JVMCI_ONLY(UseJVMCICompiler ||) _num_allocated_tasks < 10000, "Leaking compilation tasks?"); task->set_next(NULL); task->set_is_free(true); } From f620878faf999382e9e84bb9250c14f210a5b9ad Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 19 Nov 2015 11:02:14 +0100 Subject: [PATCH 044/260] 8143180: Internal Error in src/cpu/ppc/vm/macroAssembler_ppc.cpp:4287 Fix ppc64 issue after 8141133. Reviewed-by: simonis, goetz --- hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index d78395f0a35..141891d0a16 100644 --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -2962,9 +2962,9 @@ void SharedRuntime::generate_uncommon_trap_blob() { __ set_last_Java_frame(/*sp*/R1_SP, /*pc*/R11_scratch1); __ mr(klass_index_reg, R3); - __ li(R5, Deoptimization::Unpack_exception); + __ li(R5_ARG3, Deoptimization::Unpack_uncommon_trap); __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap), - R16_thread, klass_index_reg, R5); + R16_thread, klass_index_reg, R5_ARG3); // Set an oopmap for the call site. oop_maps->add_gc_map(gc_map_pc - start, map); From dd76bcc4c21cb29638589cce6cda078ad8a516f4 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Fri, 18 Sep 2015 13:41:24 +0200 Subject: [PATCH 045/260] 8134579: [TESTBUG] Some bmi tests fail if can_access_local_variables is on Others fail because of uncommon trap. Also fix test file names. Reviewed-by: vlivanov --- .../compiler/intrinsics/bmi/TestAndnI.java | 36 +++++++++++++++---- .../compiler/intrinsics/bmi/TestAndnL.java | 36 +++++++++++++++---- .../{AddnTestI.java => AndnTestI.java} | 14 ++++---- .../{AddnTestL.java => AndnTestL.java} | 14 ++++---- .../intrinsics/bmi/verifycode/LZcntTestI.java | 2 ++ .../intrinsics/bmi/verifycode/LZcntTestL.java | 2 ++ .../intrinsics/bmi/verifycode/TZcntTestI.java | 2 ++ .../intrinsics/bmi/verifycode/TZcntTestL.java | 2 ++ 8 files changed, 82 insertions(+), 26 deletions(-) rename hotspot/test/compiler/intrinsics/bmi/verifycode/{AddnTestI.java => AndnTestI.java} (82%) rename hotspot/test/compiler/intrinsics/bmi/verifycode/{AddnTestL.java => AndnTestL.java} (79%) diff --git a/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java b/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java index cbf08bc465d..0f74509722d 100644 --- a/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java +++ b/hotspot/test/compiler/intrinsics/bmi/TestAndnI.java @@ -61,15 +61,27 @@ public class TestAndnI { } public int intExpr(int src1, Expr.MemI src2) { - return ~src1 & src2.value; + if (src2 != null) { + return ~src1 & src2.value; + } else { + return 0; + } } public int intExpr(Expr.MemI src1, int src2) { - return ~src1.value & src2; + if (src1 != null) { + return ~src1.value & src2; + } else { + return 0; + } } public int intExpr(Expr.MemI src1, Expr.MemI src2) { - return ~src1.value & src2.value; + if (src1 != null && src2 != null) { + return ~src1.value & src2.value; + } else { + return 0; + } } } @@ -80,15 +92,27 @@ public class TestAndnI { } public int intExpr(int src1, Expr.MemI src2) { - return src1 & ~src2.value; + if (src2 != null) { + return src1 & ~src2.value; + } else { + return 0; + } } public int intExpr(Expr.MemI src1, int src2) { - return src1.value & ~src2; + if (src1 != null) { + return src1.value & ~src2; + } else { + return 0; + } } public int intExpr(Expr.MemI src1, Expr.MemI src2) { - return src1.value & ~src2.value; + if (src1 != null && src2 != null) { + return src1.value & ~src2.value; + } else { + return 0; + } } } } diff --git a/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java b/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java index 088d537f633..c8bf93344cc 100644 --- a/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java +++ b/hotspot/test/compiler/intrinsics/bmi/TestAndnL.java @@ -61,15 +61,27 @@ public class TestAndnL { } public long longExpr(long src1, Expr.MemL src2) { - return ~src1 & src2.value; + if (src2 != null) { + return ~src1 & src2.value; + } else { + return 0; + } } public long longExpr(Expr.MemL src1, long src2) { - return ~src1.value & src2; + if (src1 != null) { + return ~src1.value & src2; + } else { + return 0; + } } public long longExpr(Expr.MemL src1, Expr.MemL src2) { - return ~src1.value & src2.value; + if (src1 != null && src2 != null) { + return ~src1.value & src2.value; + } else { + return 0; + } } @@ -82,15 +94,27 @@ public class TestAndnL { } public long longExpr(long src1, Expr.MemL src2) { - return src1 & ~src2.value; + if (src2 != null) { + return src1 & ~src2.value; + } else { + return 0; + } } public long longExpr(Expr.MemL src1, long src2) { - return src1.value & ~src2; + if (src1 != null) { + return src1.value & ~src2; + } else { + return 0; + } } public long longExpr(Expr.MemL src1, Expr.MemL src2) { - return src1.value & ~src2.value; + if (src1 != null && src2 != null) { + return src1.value & ~src2.value; + } else { + return 0; + } } } diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/AndnTestI.java similarity index 82% rename from hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestI.java rename to hotspot/test/compiler/intrinsics/bmi/verifycode/AndnTestI.java index ec950d09aaf..c6897440012 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/AndnTestI.java @@ -27,18 +27,18 @@ * @library /testlibrary /test/lib /compiler/whitebox / .. * @modules java.base/sun.misc * java.management - * @build AddnTestI + * @build AndnTestI * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseBMI1Instructions AddnTestI + * @run main/bootclasspath -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseBMI1Instructions AndnTestI */ import java.lang.reflect.Method; -public class AddnTestI extends BmiIntrinsicBase.BmiTestCase { +public class AndnTestI extends BmiIntrinsicBase.BmiTestCase { - protected AddnTestI(Method method) { + protected AndnTestI(Method method) { super(method); // from intel manual VEX.NDS.LZ.0F38.W0 F2 /r, example c4e260f2c2 instrMask = new byte[]{ @@ -54,7 +54,7 @@ public class AddnTestI extends BmiIntrinsicBase.BmiTestCase { } public static void main(String[] args) throws Exception { - BmiIntrinsicBase.verifyTestCase(AddnTestI::new, TestAndnI.AndnIExpr.class.getDeclaredMethods()); - BmiIntrinsicBase.verifyTestCase(AddnTestI::new, TestAndnI.AndnICommutativeExpr.class.getDeclaredMethods()); + BmiIntrinsicBase.verifyTestCase(AndnTestI::new, TestAndnI.AndnIExpr.class.getDeclaredMethods()); + BmiIntrinsicBase.verifyTestCase(AndnTestI::new, TestAndnI.AndnICommutativeExpr.class.getDeclaredMethods()); } } diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/AndnTestL.java similarity index 79% rename from hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestL.java rename to hotspot/test/compiler/intrinsics/bmi/verifycode/AndnTestL.java index 37579d236c0..8725cb7f0bb 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/AddnTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/AndnTestL.java @@ -27,24 +27,24 @@ * @library /testlibrary /test/lib /compiler/whitebox / .. * @modules java.base/sun.misc * java.management - * @build AddnTestL + * @build AndnTestL * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseBMI1Instructions AddnTestL + * @run main/bootclasspath -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+IgnoreUnrecognizedVMOptions -XX:+UseBMI1Instructions AndnTestL */ import java.lang.reflect.Method; -public class AddnTestL extends AddnTestI { +public class AndnTestL extends AndnTestI { - protected AddnTestL(Method method) { + protected AndnTestL(Method method) { super(method); isLongOperation = true; } public static void main(String[] args) throws Exception { - BmiIntrinsicBase.verifyTestCase(AddnTestL::new, TestAndnL.AndnLExpr.class.getDeclaredMethods()); - BmiIntrinsicBase.verifyTestCase(AddnTestL::new, TestAndnL.AndnLCommutativeExpr.class.getDeclaredMethods()); + BmiIntrinsicBase.verifyTestCase(AndnTestL::new, TestAndnL.AndnLExpr.class.getDeclaredMethods()); + BmiIntrinsicBase.verifyTestCase(AndnTestL::new, TestAndnL.AndnLCommutativeExpr.class.getDeclaredMethods()); } } diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java index ea3055ce376..7436044e78e 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestI.java @@ -50,6 +50,8 @@ public class LZcntTestI extends BmiIntrinsicBase.BmiTestCase_x64 { public static void main(String[] args) throws Exception { // j.l.Integer and Long should be loaded to allow a compilation of the methods that use their methods System.out.println("class java.lang.Integer should be loaded. Proof: " + Integer.class); + // Avoid uncommon traps. + System.out.println("Num leading zeroes: " + new TestLzcntI.LzcntIExpr().intExpr(12341341)); BmiIntrinsicBase.verifyTestCase(LZcntTestI::new, TestLzcntI.LzcntIExpr.class.getDeclaredMethods()); } diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java index 01e669a1595..c96df728df8 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/LZcntTestL.java @@ -46,6 +46,8 @@ public class LZcntTestL extends LZcntTestI { public static void main(String[] args) throws Exception { // j.l.Integer and Long should be loaded to allow a compilation of the methods that use their methods System.out.println("classes java.lang.Long should be loaded. Proof: " + Long.class); + // Avoid uncommon traps. + System.out.println("Num leading zeroes: " + new TestLzcntL.LzcntLExpr().longExpr(12341341)); BmiIntrinsicBase.verifyTestCase(LZcntTestL::new, TestLzcntL.LzcntLExpr.class.getDeclaredMethods()); } } diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java index 0f0a237c0f0..25f90f2e89e 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestI.java @@ -50,6 +50,8 @@ public class TZcntTestI extends BmiIntrinsicBase.BmiTestCase_x64 { public static void main(String[] args) throws Exception { // j.l.Integer and Long should be loaded to allow a compilation of the methods that use their methods System.out.println("class java.lang.Integer should be loaded. Proof: " + Integer.class); + // Avoid uncommon traps. + System.out.println("Num trailing zeroes: " + new TestTzcntI.TzcntIExpr().intExpr(12341341)); BmiIntrinsicBase.verifyTestCase(TZcntTestI::new, TestTzcntI.TzcntIExpr.class.getDeclaredMethods()); } diff --git a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java index 632a6bdd0c3..812123d422a 100644 --- a/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java +++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/TZcntTestL.java @@ -46,6 +46,8 @@ public class TZcntTestL extends TZcntTestI { public static void main(String[] args) throws Exception { // j.l.Integer and Long should be loaded to allow a compilation of the methods that use their methods System.out.println("classes java.lang.Long should be loaded. Proof: " + Long.class); + // Avoid uncommon traps. + System.out.println("Num trailing zeroes: " + new TestTzcntL.TzcntLExpr().longExpr(12341341)); BmiIntrinsicBase.verifyTestCase(TZcntTestL::new, TestTzcntL.TzcntLExpr.class.getDeclaredMethods()); } } From 138d45b4769669eeb5a6d39f7312ffea890df205 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Mon, 28 Sep 2015 08:42:06 -0700 Subject: [PATCH 046/260] 8066272: pack200 must support Multi-Release Jars Reviewed-by: jrose, sdrach --- .../sun/java/util/jar/pack/PackerImpl.java | 47 ++-- jdk/test/tools/pack200/MultiRelease.java | 257 ++++++++++++++++++ 2 files changed, 284 insertions(+), 20 deletions(-) create mode 100644 jdk/test/tools/pack200/MultiRelease.java diff --git a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/PackerImpl.java b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/PackerImpl.java index 5e7da4bb6d4..203fde39335 100644 --- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/PackerImpl.java +++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/PackerImpl.java @@ -272,22 +272,6 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer { // (Done collecting options from props.) - boolean isClassFile(String name) { - if (!name.endsWith(".class")) return false; - for (String prefix = name; ; ) { - if (passFiles.contains(prefix)) return false; - int chop = prefix.lastIndexOf('/'); - if (chop < 0) break; - prefix = prefix.substring(0, chop); - } - return true; - } - - boolean isMetaInfFile(String name) { - return name.startsWith("/" + Utils.METAINF) || - name.startsWith(Utils.METAINF); - } - // Get a new package, based on the old one. private void makeNextPackage() { pkg.reset(); @@ -332,6 +316,29 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer { InFile(JarEntry je) { this(null, je); } + boolean isClassFile() { + if (!name.endsWith(".class")) { + return false; + } + for (String prefix = name;;) { + if (passFiles.contains(prefix)) { + return false; + } + int chop = prefix.lastIndexOf('/'); + if (chop < 0) { + break; + } + prefix = prefix.substring(0, chop); + } + return true; + } + boolean isMetaInfFile() { + return name.startsWith("/" + Utils.METAINF) + || name.startsWith(Utils.METAINF); + } + boolean mustProcess() { + return !isMetaInfFile() && isClassFile(); + } long getInputLength() { long len = (je != null)? je.getSize(): f.length(); assert(len >= 0) : this+".len="+len; @@ -391,7 +398,7 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer { Package.File file = null; // (5078608) : discount the resource files in META-INF // from segment computation. - long inflen = (isMetaInfFile(name)) + long inflen = (inFile.isMetaInfFile()) ? 0L : inFile.getInputLength(); @@ -406,7 +413,7 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer { assert(je.isDirectory() == name.endsWith("/")); - if (isClassFile(name)) { + if (inFile.mustProcess()) { file = readClass(name, bits.getInputStream()); } if (file == null) { @@ -429,7 +436,7 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer { for (InFile inFile : inFiles) { String name = inFile.name; // (5078608) : discount the resource files completely from segmenting - long inflen = (isMetaInfFile(name)) + long inflen = (inFile.isMetaInfFile()) ? 0L : inFile.getInputLength() ; if ((segmentSize += inflen) > segmentLimit) { @@ -447,7 +454,7 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer { if (verbose > 1) Utils.log.fine("Reading " + name); Package.File file = null; - if (isClassFile(name)) { + if (inFile.mustProcess()) { file = readClass(name, strm); if (file == null) { strm.close(); diff --git a/jdk/test/tools/pack200/MultiRelease.java b/jdk/test/tools/pack200/MultiRelease.java new file mode 100644 index 00000000000..7b3f8a3b91a --- /dev/null +++ b/jdk/test/tools/pack200/MultiRelease.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + r You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/* + * @test + * @bug 8066272 + * @summary tests a simple multi-versioned jar file + * @compile -XDignore.symbol.file Utils.java MultiRelease.java + * @run main MultiRelease + * @author ksrini + */ + +public class MultiRelease { + private static final File cwd = new File("."); + private static int pass = 0; + private static int fail = 0; + // specify alternate name via arguments to verify + // if permanent fix works + + private static final String PropKey = "pack200.MultiRelease.META-INF"; + private static final String MetaInfName = System.getProperty(PropKey, "META-INF"); + + public static void main(String... args) throws Exception { + new MultiRelease().run(); + } + + void run() throws Exception { + List testCases = new ArrayList<>(); + testCases.add(new TestCase1()); + testCases.add(new TestCase2()); + for (TestCase tc : testCases) { + tc.run(); + } + if (fail > 0) { + throw new Exception(fail + "/" + testCases.size() + " tests fails"); + } else { + System.out.println("All tests(" + pass + ") passes"); + } + } + + /* + * An abstract class to eliminate test boiler plating. + */ + static abstract class TestCase { + final File tcwd; + final File metaInfDir; + final File versionsDir; + final File manifestFile; + + TestCase(String directory) throws IOException { + System.out.println("initializing directories"); + tcwd = new File(cwd, directory); + metaInfDir = mkdir(new File(tcwd, MetaInfName)); + versionsDir = mkdir(new File(metaInfDir, "versions")); + manifestFile = new File(tcwd, "manifest.tmp"); + List scratch = new ArrayList<>(); + scratch.add("Multi-Release: true"); + Utils.createFile(manifestFile, scratch); + } + + File mkdir(File f) throws IOException { + if (f.exists() && f.isDirectory() && f.canRead() && f.canWrite()) { + return f; + } + if (!f.mkdirs()) { + throw new IOException("mkdirs failed: " + f.getAbsolutePath()); + } + return f; + } + + abstract void emitClassFiles() throws Exception; + + void run() { + try { + emitClassFiles(); + // jar the file up + File testFile = new File(tcwd, "test" + Utils.JAR_FILE_EXT); + Utils.jar("cvfm", + testFile.getAbsolutePath(), + manifestFile.getAbsolutePath(), + "-C", + tcwd.getAbsolutePath(), + "."); + File outFile = new File(tcwd, "test-repacked" + Utils.JAR_FILE_EXT); + List cmdsList = new ArrayList<>(); + + cmdsList.add(Utils.getPack200Cmd()); + cmdsList.add("-J-ea"); + cmdsList.add("-J-esa"); + cmdsList.add("-v"); + cmdsList.add("--repack"); + cmdsList.add(outFile.getAbsolutePath()); + cmdsList.add(testFile.getAbsolutePath()); + List output = Utils.runExec(cmdsList); + Utils.doCompareVerify(testFile.getAbsoluteFile(), outFile.getAbsoluteFile()); + pass++; + } catch (Exception e) { + e.printStackTrace(System.err); + fail++; + } + } + } + + static class TestCase1 extends TestCase { + private TestCase1(String directory) throws IOException { + super(directory); + } + + public TestCase1() throws Exception { + this("case1"); + } + + @Override + void emitClassFiles() throws Exception { + emitClassFile(""); + emitClassFile("7"); + emitClassFile("8"); + emitClassFile("9"); + } + + /* + * Adds different variants of types + */ + void emitClassFile(String version) throws IOException { + final File outDir = mkdir(version.isEmpty() + ? tcwd + : new File(versionsDir, version)); + + final File srcDir = mkdir(version.isEmpty() + ? new File(tcwd, "src") + : new File(new File(versionsDir, version), "src")); + + final String fname = "Foo"; + final File srcFile = new File(srcDir, fname + Utils.JAVA_FILE_EXT); + List scratch = new ArrayList<>(); + + scratch.add("package pkg;"); + switch (version) { + case "7": + scratch.add("public class Foo {"); + scratch.add("public static final class Bar {}"); + break; + case "8": + scratch.add("public abstract class Foo {"); + scratch.add("public final class Bar {}"); + break; + case "9": + scratch.add("public interface Foo {"); + scratch.add("public final class Bar {}"); + break; + default: + scratch.add("public class Foo {"); + scratch.add("public final class Bar {}"); + break; + } + scratch.add("}"); + + Utils.createFile(srcFile, scratch); + Utils.compiler("-d", + outDir.getAbsolutePath(), + srcFile.getAbsolutePath()); + } + } + + static class TestCase2 extends TestCase { + private TestCase2(String directory) throws IOException { + super(directory); + } + + TestCase2() throws Exception { + this("case2"); + } + + @Override + void emitClassFiles() throws Exception { + emitClassFile(""); + emitClassFile("8"); + } + + /* + * Adds different variants of types and tries to invoke an + * interface or concrete method defined by them. + */ + void emitClassFile(String version) throws IOException { + + final File outDir = mkdir(version.isEmpty() + ? tcwd + : new File(versionsDir, version)); + + final File srcDir = mkdir(version.isEmpty() + ? new File(tcwd, "src") + : new File(new File(versionsDir, version), "src")); + + List scratch = new ArrayList<>(); + final String fname1 = "Ab"; + final File srcFile1 = new File(srcDir, fname1 + Utils.JAVA_FILE_EXT); + + final String fname2 = "AbNormal"; + final File srcFile2 = new File(srcDir, fname2 + Utils.JAVA_FILE_EXT); + switch (version) { + case "8": + scratch.clear(); + scratch.add("import java.io.IOException;"); + scratch.add("public interface " + fname1 + "{"); + scratch.add(" public abstract void close() throws IOException ;"); + scratch.add("}"); + Utils.createFile(srcFile1, scratch); + break; + default: + scratch.clear(); + scratch.add("import java.io.IOException;"); + scratch.add("public abstract class " + fname1 + "{"); + scratch.add(" public abstract void close() throws IOException ;"); + scratch.add("}"); + Utils.createFile(srcFile1, scratch); + } + + scratch.clear(); + scratch.add("import java.io.IOException;"); + scratch.add("public class " + fname2 + "{"); + scratch.add(" public void doSomething(Ab ab) throws IOException {"); + scratch.add(" ab.close();"); + scratch.add(" }"); + scratch.add("}"); + + Utils.createFile(srcFile2, scratch); + Utils.compiler("-d", + outDir.getAbsolutePath(), + srcFile1.getAbsolutePath(), + srcFile2.getAbsolutePath()); + } + } +} From 28115bceae6e3a1a545ad5e6f0fef88d01423df8 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Wed, 21 Oct 2015 11:40:05 +0200 Subject: [PATCH 047/260] 8138892: C1: Improve counter overflow checking Reviewed-by: iveresov, goetz, twisti, vlivanov --- .../src/cpu/aarch64/vm/c1_CodeStubs_aarch64.cpp | 4 +++- hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp | 4 +++- hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp | 3 ++- hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp | 8 ++++++++ hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp | 9 +++++---- hotspot/src/share/vm/c1/c1_LIRGenerator.cpp | 16 ++++++++++------ 6 files changed, 31 insertions(+), 13 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/c1_CodeStubs_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_CodeStubs_aarch64.cpp index bdfc017aa82..865b4c20374 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_CodeStubs_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_CodeStubs_aarch64.cpp @@ -41,7 +41,9 @@ void CounterOverflowStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); - ce->store_parameter(_method->as_register(), 1); + Metadata *m = _method->as_constant_ptr()->as_metadata(); + __ mov_metadata(rscratch1, m); + ce->store_parameter(rscratch1, 1); ce->store_parameter(_bci, 0); __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::counter_overflow_id))); ce->add_call_info_here(_info); diff --git a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp index 4f511dce70d..fec821ac6c7 100644 --- a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp @@ -94,8 +94,10 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) { void CounterOverflowStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); __ set(_bci, G4); + Metadata *m = _method->as_constant_ptr()->as_metadata(); + __ set_metadata_constant(m, G5); __ call(Runtime1::entry_for(Runtime1::counter_overflow_id), relocInfo::runtime_call_type); - __ delayed()->mov_or_nop(_method->as_register(), G5); + __ delayed()->nop(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); diff --git a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp index 8a25fd636b3..4f6690fa540 100644 --- a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp @@ -81,7 +81,8 @@ void ConversionStub::emit_code(LIR_Assembler* ce) { void CounterOverflowStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); - ce->store_parameter(_method->as_register(), 1); + Metadata *m = _method->as_constant_ptr()->as_metadata(); + ce->store_parameter(m, 1); ce->store_parameter(_bci, 0); __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::counter_overflow_id))); ce->add_call_info_here(_info); diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp index d3a415be085..6e62429a7ed 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp @@ -2971,6 +2971,14 @@ void LIR_Assembler::store_parameter(jobject o, int offset_from_rsp_in_words) { } +void LIR_Assembler::store_parameter(Metadata* m, int offset_from_rsp_in_words) { + assert(offset_from_rsp_in_words >= 0, "invalid offset from rsp"); + int offset_from_rsp_in_bytes = offset_from_rsp_in_words * BytesPerWord; + assert(offset_from_rsp_in_bytes < frame_map()->reserved_argument_area_size(), "invalid offset"); + __ mov_metadata(Address(rsp, offset_from_rsp_in_bytes), m); +} + + // This code replaces a call to arraycopy; no exception may // be thrown in this code, they must be thrown in the System.arraycopy // activation frame; we could save some checks if this would not be the case diff --git a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp index 6ed351033bc..f9514edef45 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -49,9 +49,10 @@ Register recv, Label* update_done); public: - void store_parameter(Register r, int offset_from_esp_in_words); - void store_parameter(jint c, int offset_from_esp_in_words); - void store_parameter(jobject c, int offset_from_esp_in_words); + void store_parameter(Register r, int offset_from_esp_in_words); + void store_parameter(jint c, int offset_from_esp_in_words); + void store_parameter(jobject c, int offset_from_esp_in_words); + void store_parameter(Metadata* c, int offset_from_esp_in_words); enum { call_stub_size = NOT_LP64(15) LP64_ONLY(28), exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175), diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 79452a4536f..355d5432518 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -3429,14 +3429,18 @@ void LIRGenerator::increment_event_counter_impl(CodeEmitInfo* info, __ add(result, LIR_OprFact::intConst(InvocationCounter::count_increment), result); __ store(result, counter); if (notify) { - LIR_Opr mask = load_immediate(frequency << InvocationCounter::count_shift, T_INT); - LIR_Opr meth = new_register(T_METADATA); - __ metadata2reg(method->constant_encoding(), meth); - __ logical_and(result, mask, result); - __ cmp(lir_cond_equal, result, LIR_OprFact::intConst(0)); + LIR_Opr meth = LIR_OprFact::metadataConst(method->constant_encoding()); // The bci for info can point to cmp for if's we want the if bci CodeStub* overflow = new CounterOverflowStub(info, bci, meth); - __ branch(lir_cond_equal, T_INT, overflow); + int freq = frequency << InvocationCounter::count_shift; + if (freq == 0) { + __ branch(lir_cond_always, T_ILLEGAL, overflow); + } else { + LIR_Opr mask = load_immediate(freq, T_INT); + __ logical_and(result, mask, result); + __ cmp(lir_cond_equal, result, LIR_OprFact::intConst(0)); + __ branch(lir_cond_equal, T_INT, overflow); + } __ branch_destination(overflow->continuation()); } } From f6cb49ba4802fa05583f235f3471d2c874b56901 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Mon, 5 Oct 2015 23:50:43 +0200 Subject: [PATCH 048/260] 8138895: C1: PPC64 Port needs special register for Locks in synchronization code Reviewed-by: vlivanov, goetz --- hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp | 3 ++- hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp | 3 ++- hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp | 3 ++- hotspot/src/share/vm/c1/c1_LIRGenerator.cpp | 2 +- hotspot/src/share/vm/c1/c1_LIRGenerator.hpp | 1 + 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp index fb2c0ae3343..21c7cfc93ff 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, 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. * @@ -70,6 +70,7 @@ LIR_Opr LIRGenerator::divInOpr() { Unimplemented(); return LIR_OprFact::i LIR_Opr LIRGenerator::divOutOpr() { Unimplemented(); return LIR_OprFact::illegalOpr; } LIR_Opr LIRGenerator::remOutOpr() { Unimplemented(); return LIR_OprFact::illegalOpr; } LIR_Opr LIRGenerator::shiftCountOpr() { Unimplemented(); return LIR_OprFact::illegalOpr; } +LIR_Opr LIRGenerator::syncLockOpr() { return new_register(T_INT); } LIR_Opr LIRGenerator::syncTempOpr() { return FrameMap::r0_opr; } LIR_Opr LIRGenerator::getThreadTemp() { return LIR_OprFact::illegalOpr; } diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp index e91142ee011..992cb8d4742 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,6 +68,7 @@ void LIRItem::load_nonconstant() { LIR_Opr LIRGenerator::exceptionOopOpr() { return FrameMap::Oexception_opr; } LIR_Opr LIRGenerator::exceptionPcOpr() { return FrameMap::Oissuing_pc_opr; } +LIR_Opr LIRGenerator::syncLockOpr() { return new_register(T_INT); } LIR_Opr LIRGenerator::syncTempOpr() { return new_register(T_OBJECT); } LIR_Opr LIRGenerator::getThreadTemp() { return rlock_callee_saved(NOT_LP64(T_INT) LP64_ONLY(T_LONG)); } diff --git a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp index 9933655cdba..8303fe989c8 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,6 +80,7 @@ LIR_Opr LIRGenerator::divInOpr() { return FrameMap::rax_opr; } LIR_Opr LIRGenerator::divOutOpr() { return FrameMap::rax_opr; } LIR_Opr LIRGenerator::remOutOpr() { return FrameMap::rdx_opr; } LIR_Opr LIRGenerator::shiftCountOpr() { return FrameMap::rcx_opr; } +LIR_Opr LIRGenerator::syncLockOpr() { return new_register(T_INT); } LIR_Opr LIRGenerator::syncTempOpr() { return FrameMap::rax_opr; } LIR_Opr LIRGenerator::getThreadTemp() { return LIR_OprFact::illegalOpr; } diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 355d5432518..e1e123a6739 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -2802,7 +2802,7 @@ void LIRGenerator::do_Base(Base* x) { assert(obj->is_valid(), "must be valid"); if (method()->is_synchronized() && GenerateSynchronizationCode) { - LIR_Opr lock = new_register(T_INT); + LIR_Opr lock = syncLockOpr(); __ load_stack_address_monitor(0, lock); CodeEmitInfo* info = new CodeEmitInfo(scope()->start()->state()->copy(ValueStack::StateBefore, SynchronizationEntryBCI), NULL, x->check_flag(Instruction::DeoptimizeOnException)); diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp index 69956e7d9e0..89f5960182a 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp @@ -495,6 +495,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { static LIR_Opr divOutOpr(); static LIR_Opr remOutOpr(); static LIR_Opr shiftCountOpr(); + LIR_Opr syncLockOpr(); LIR_Opr syncTempOpr(); LIR_Opr atomicLockOpr(); From 409697a74e49023111a001aa9f480f87fa99d6f1 Mon Sep 17 00:00:00 2001 From: Ron Durbin Date: Wed, 11 Nov 2015 14:57:27 -0800 Subject: [PATCH 049/260] 8141068: refactor -XXFlags= code in preparation for removal Reviewed-by: dcubed, gthornbr, coleenp --- hotspot/src/share/vm/runtime/arguments.cpp | 30 ++++++++-------------- hotspot/src/share/vm/runtime/arguments.hpp | 13 +++++++--- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 76466dd43f5..787e4d6f207 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -74,6 +74,7 @@ do { \ } \ } while(0) +char* Arguments::_jvm_flags_file = NULL; char** Arguments::_jvm_flags_array = NULL; int Arguments::_num_jvm_flags = 0; char** Arguments::_jvm_args_array = NULL; @@ -3957,7 +3958,6 @@ static bool use_vm_log() { #endif // PRODUCT jint Arguments::insert_vm_options_file(const JavaVMInitArgs* args, - char** flags_file, char** vm_options_file, const int vm_options_file_pos, ScopedVMInitArgs *vm_options_file_args, @@ -3976,13 +3976,12 @@ jint Arguments::insert_vm_options_file(const JavaVMInitArgs* args, } jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args, - char ** flags_file, char ** vm_options_file, - ScopedVMInitArgs* vm_options_file_args, ScopedVMInitArgs* args_out) { // Remaining part of option string const char* tail; int vm_options_file_pos = -1; + ScopedVMInitArgs vm_options_file_args; for (int index = 0; index < args->nOptions; index++) { const JavaVMOption* option = args->options + index; @@ -3990,12 +3989,7 @@ jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args, continue; } if (match_option(option, "-XX:Flags=", &tail)) { - *flags_file = (char *) tail; - if (*flags_file == NULL) { - jio_fprintf(defaultStream::error_stream(), - "Cannot copy flags_file name.\n"); - return JNI_ENOMEM; - } + Arguments::set_jvm_flags_file(tail); continue; } if (match_option(option, "-XX:VMOptionsFile=", &tail)) { @@ -4011,9 +4005,9 @@ jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args, *vm_options_file = (char *) tail; vm_options_file_pos = index; // save position of -XX:VMOptionsFile // If there's a VMOptionsFile, parse that (also can set flags_file) - jint code = insert_vm_options_file(args, flags_file, vm_options_file, + jint code = insert_vm_options_file(args, vm_options_file, vm_options_file_pos, - vm_options_file_args, args_out); + &vm_options_file_args, args_out); if (code != JNI_OK) { return code; } @@ -4109,16 +4103,12 @@ jint Arguments::parse(const JavaVMInitArgs* args) { // If flag "-XX:Flags=flags-file" is used it will be the first option to be processed. const char* hotspotrc = ".hotspotrc"; - char* flags_file = NULL; char* vm_options_file = NULL; bool settings_file_specified = false; bool needs_hotspotrc_warning = false; ScopedVMInitArgs java_tool_options_args; ScopedVMInitArgs java_options_args; ScopedVMInitArgs modified_cmd_line_args; - // Pass in vm_options_file_args to keep memory for flags_file from being - // deallocated if found in the vm options file. - ScopedVMInitArgs vm_options_file_args; jint code = parse_java_tool_options_environment_variable(&java_tool_options_args); @@ -4132,13 +4122,12 @@ jint Arguments::parse(const JavaVMInitArgs* args) { } code = match_special_option_and_act(java_tool_options_args.get(), - &flags_file, NULL, NULL, NULL); + NULL, NULL); if (code != JNI_OK) { return code; } - code = match_special_option_and_act(args, &flags_file, &vm_options_file, - &vm_options_file_args, + code = match_special_option_and_act(args, &vm_options_file, &modified_cmd_line_args); if (code != JNI_OK) { return code; @@ -4150,12 +4139,13 @@ jint Arguments::parse(const JavaVMInitArgs* args) { args = modified_cmd_line_args.get(); } - code = match_special_option_and_act(java_options_args.get(), &flags_file, - NULL, NULL, NULL); + code = match_special_option_and_act(java_options_args.get(), + NULL, NULL); if (code != JNI_OK) { return code; } + const char * flags_file = Arguments::get_jvm_flags_file(); settings_file_specified = (flags_file != NULL); if (IgnoreUnrecognizedVMOptions) { diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index 3bd46e75fe2..2322f05bb64 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -244,6 +244,8 @@ class Arguments : AllStatic { private: + // a pointer to the flags file name if it is specified + static char* _jvm_flags_file; // an array containing all flags specified in the .hotspotrc file static char** _jvm_flags_array; static int _num_jvm_flags; @@ -378,15 +380,12 @@ class Arguments : AllStatic { static jint parse_vm_options_file(const char* file_name, ScopedVMInitArgs* vm_args); static jint parse_options_buffer(const char* name, char* buffer, const size_t buf_len, ScopedVMInitArgs* vm_args); static jint insert_vm_options_file(const JavaVMInitArgs* args, - char** flags_file, char** vm_options_file, const int vm_options_file_pos, ScopedVMInitArgs* vm_options_file_args, ScopedVMInitArgs* args_out); static jint match_special_option_and_act(const JavaVMInitArgs* args, - char** flags_file, char** vm_options_file, - ScopedVMInitArgs* vm_options_file_args, ScopedVMInitArgs* args_out); static jint parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args, @@ -514,6 +513,14 @@ class Arguments : AllStatic { static void print_on(outputStream* st); static void print_summary_on(outputStream* st); + // convenient methods to get and set jvm_flags_file + static const char* get_jvm_flags_file() { return _jvm_flags_file; } + static void set_jvm_flags_file(const char *value) { + if (_jvm_flags_file != NULL) { + os::free(_jvm_flags_file); + } + _jvm_flags_file = os::strdup_check_oom(value); + } // convenient methods to obtain / print jvm_flags and jvm_args static const char* jvm_flags() { return build_resource_string(_jvm_flags_array, _num_jvm_flags); } static const char* jvm_args() { return build_resource_string(_jvm_args_array, _num_jvm_args); } From 5386656677ab1770e46e43efb9eed193ade37d16 Mon Sep 17 00:00:00 2001 From: Rachel Protacio Date: Wed, 11 Nov 2015 18:04:33 -0500 Subject: [PATCH 050/260] 8142437: SafepointTest.java is occasionally failing in JPRT A method compilation causing a specific log message to print has been removed because it was not always being compiled. Reviewed-by: coleenp, dholmes --- .../test/runtime/logging/SafepointTest.java | 2 -- .../runtime/logging/SafepointTestMain.java | 27 +------------------ 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/hotspot/test/runtime/logging/SafepointTest.java b/hotspot/test/runtime/logging/SafepointTest.java index fb6805e84bb..79ca2e2b2fa 100644 --- a/hotspot/test/runtime/logging/SafepointTest.java +++ b/hotspot/test/runtime/logging/SafepointTest.java @@ -41,11 +41,9 @@ public class SafepointTest { "-Xlog:safepoint=trace", "SafepointTestMain"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Safepoint synchronization initiated. ("); - output.shouldContain(" thread(s) to block"); output.shouldContain("Entering safepoint region: "); output.shouldContain("Leaving safepoint region"); output.shouldContain("_at_poll_safepoint"); - output.shouldContain("... found polling page "); output.shouldHaveExitValue(0); } } diff --git a/hotspot/test/runtime/logging/SafepointTestMain.java b/hotspot/test/runtime/logging/SafepointTestMain.java index d69c0475dc0..4d65d2fcf3d 100644 --- a/hotspot/test/runtime/logging/SafepointTestMain.java +++ b/hotspot/test/runtime/logging/SafepointTestMain.java @@ -24,21 +24,6 @@ import java.lang.ref.WeakReference; public class SafepointTestMain { - public static class B { - static int count = 0; - public static volatile boolean stop = false; - static void localSleep(int time) { - try{ - Thread.currentThread().sleep(time); - } catch(InterruptedException ie) { - } - } - - public static void infinite() { - while (!stop) { count++; } - } - } - public static byte[] garbage; public static volatile WeakReference weakref; @@ -48,16 +33,7 @@ public class SafepointTestMain { } public static void main(String[] args) throws Exception { - // Run function in separate thread to force compilation and pint safepoint - // message for compiled method - new Thread() { - public void run() { - B.infinite(); - } - }.start(); - B.localSleep(1000); - // Cause several safepoints to run GC while the compiled method is running, - // to see safepoint messages + // Cause several safepoints to run GC to see safepoint messages for (int i = 0; i < 2; i++) { createweakref(); while(weakref.get() != null) { @@ -65,6 +41,5 @@ public class SafepointTestMain { System.gc(); } } - B.stop = true; } } From 250efd235c3f7ba0c423fe0f858072bdc90dc6f7 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Thu, 12 Nov 2015 09:19:44 +0100 Subject: [PATCH 051/260] 8142472: Remove debugging code guarded by CMSPrintPromoBlockInfo Reviewed-by: david, ehelin --- hotspot/src/share/vm/gc/cms/promotionInfo.cpp | 30 ------------------- hotspot/src/share/vm/gc/cms/promotionInfo.hpp | 1 - 2 files changed, 31 deletions(-) diff --git a/hotspot/src/share/vm/gc/cms/promotionInfo.cpp b/hotspot/src/share/vm/gc/cms/promotionInfo.cpp index 4e5d8ea9411..a7a5a3b1fd3 100644 --- a/hotspot/src/share/vm/gc/cms/promotionInfo.cpp +++ b/hotspot/src/share/vm/gc/cms/promotionInfo.cpp @@ -233,41 +233,11 @@ void PromotionInfo::startTrackingPromotions() { _tracking = true; } -#define CMSPrintPromoBlockInfo 1 - void PromotionInfo::stopTrackingPromotions(uint worker_id) { assert(_spoolHead == _spoolTail && _firstIndex == _nextIndex, "spooling inconsistency?"); _firstIndex = _nextIndex = 1; _tracking = false; - if (CMSPrintPromoBlockInfo > 1) { - print_statistics(worker_id); - } -} - -void PromotionInfo::print_statistics(uint worker_id) const { - assert(_spoolHead == _spoolTail && _firstIndex == _nextIndex, - "Else will undercount"); - assert(CMSPrintPromoBlockInfo > 0, "Else unnecessary call"); - // Count the number of blocks and slots in the free pool - size_t slots = 0; - size_t blocks = 0; - for (SpoolBlock* cur_spool = _spareSpool; - cur_spool != NULL; - cur_spool = cur_spool->nextSpoolBlock) { - // the first entry is just a self-pointer; indices 1 through - // bufferSize - 1 are occupied (thus, bufferSize - 1 slots). - assert((void*)cur_spool->displacedHdr == (void*)&cur_spool->displacedHdr, - "first entry of displacedHdr should be self-referential"); - slots += cur_spool->bufferSize - 1; - blocks++; - } - if (_spoolHead != NULL) { - slots += _spoolHead->bufferSize - 1; - blocks++; - } - gclog_or_tty->print_cr(" [worker %d] promo_blocks = " SIZE_FORMAT ", promo_slots = " SIZE_FORMAT, - worker_id, blocks, slots); } // When _spoolTail is not NULL, then the slot <_spoolTail, _nextIndex> diff --git a/hotspot/src/share/vm/gc/cms/promotionInfo.hpp b/hotspot/src/share/vm/gc/cms/promotionInfo.hpp index c5a3f715c96..beb9d4d6068 100644 --- a/hotspot/src/share/vm/gc/cms/promotionInfo.hpp +++ b/hotspot/src/share/vm/gc/cms/promotionInfo.hpp @@ -207,7 +207,6 @@ class PromotionInfo VALUE_OBJ_CLASS_SPEC { } void print_on(outputStream* st) const; - void print_statistics(uint worker_id) const; }; From 0ee0cf9845cb55eee01417b21906dbcb2f24bc43 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Thu, 12 Nov 2015 09:21:16 +0100 Subject: [PATCH 052/260] 8142475: Remove TraceParallelOldGCTasks Reviewed-by: tschatzl, david --- hotspot/src/share/vm/gc/parallel/pcTasks.cpp | 18 ------------------ hotspot/src/share/vm/runtime/globals.hpp | 3 --- 2 files changed, 21 deletions(-) diff --git a/hotspot/src/share/vm/gc/parallel/pcTasks.cpp b/hotspot/src/share/vm/gc/parallel/pcTasks.cpp index 6cdbab8881c..54d75e73aab 100644 --- a/hotspot/src/share/vm/gc/parallel/pcTasks.cpp +++ b/hotspot/src/share/vm/gc/parallel/pcTasks.cpp @@ -52,8 +52,6 @@ void ThreadRootsMarkingTask::do_it(GCTaskManager* manager, uint which) { ResourceMark rm; - NOT_PRODUCT(GCTraceTime tm("ThreadRootsMarkingTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -81,8 +79,6 @@ void ThreadRootsMarkingTask::do_it(GCTaskManager* manager, uint which) { void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) { assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); - NOT_PRODUCT(GCTraceTime tm("MarkFromRootsTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); ParCompactionManager::MarkAndPushClosure mark_and_push_closure(cm); @@ -152,8 +148,6 @@ void RefProcTaskProxy::do_it(GCTaskManager* manager, uint which) { assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); - NOT_PRODUCT(GCTraceTime tm("RefProcTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); ParCompactionManager::MarkAndPushClosure mark_and_push_closure(cm); @@ -208,9 +202,6 @@ StealMarkingTask::StealMarkingTask(ParallelTaskTerminator* t) : void StealMarkingTask::do_it(GCTaskManager* manager, uint which) { assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); - NOT_PRODUCT(GCTraceTime tm("StealMarkingTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); - ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); ParCompactionManager::MarkAndPushClosure mark_and_push_closure(cm); @@ -240,9 +231,6 @@ StealRegionCompactionTask::StealRegionCompactionTask(ParallelTaskTerminator* t): void StealRegionCompactionTask::do_it(GCTaskManager* manager, uint which) { assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); - NOT_PRODUCT(GCTraceTime tm("StealRegionCompactionTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); - ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -307,9 +295,6 @@ UpdateDensePrefixTask::UpdateDensePrefixTask( void UpdateDensePrefixTask::do_it(GCTaskManager* manager, uint which) { - NOT_PRODUCT(GCTraceTime tm("UpdateDensePrefixTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); - ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -322,9 +307,6 @@ void UpdateDensePrefixTask::do_it(GCTaskManager* manager, uint which) { void DrainStacksCompactionTask::do_it(GCTaskManager* manager, uint which) { assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); - NOT_PRODUCT(GCTraceTime tm("DrainStacksCompactionTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); - ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 2ff157f5368..49153c0c62d 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -2523,9 +2523,6 @@ public: develop(bool, TraceWorkGang, false, \ "Trace activities of work gangs") \ \ - product(bool, TraceParallelOldGCTasks, false, \ - "Trace multithreaded GC activity") \ - \ develop(bool, TraceBlockOffsetTable, false, \ "Print BlockOffsetTable maps") \ \ From 3ee73137fb9d2416e8f3d56142d9023265867409 Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Mon, 19 Oct 2015 15:47:36 +0200 Subject: [PATCH 053/260] 8139883: Add virtual destructor G1ParScanThreadState Reviewed-by: tschatzl, mgerdin, stefank --- hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp index df7f6ddf83b..e143ac87474 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp @@ -84,7 +84,7 @@ class G1ParScanThreadState : public CHeapObj { public: G1ParScanThreadState(G1CollectedHeap* g1h, uint worker_id, size_t young_cset_length); - ~G1ParScanThreadState(); + virtual ~G1ParScanThreadState(); void set_ref_processor(ReferenceProcessor* rp) { _scanner.set_ref_processor(rp); } From aefeb2d4423ef8cccad9f849965e5007a8ed420d Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Mon, 19 Oct 2015 16:21:35 +0200 Subject: [PATCH 054/260] 8142390: Move ScanRSClosure to header file Reviewed-by: jmasa, tschatzl --- hotspot/src/share/vm/gc/g1/g1RemSet.cpp | 195 ++++++++++-------------- hotspot/src/share/vm/gc/g1/g1RemSet.hpp | 35 +++++ 2 files changed, 119 insertions(+), 111 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp index 8ea400204c4..ea395791423 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp @@ -73,138 +73,111 @@ G1RemSet::~G1RemSet() { FREE_C_HEAP_ARRAY(G1ParPushHeapRSClosure*, _cset_rs_update_cl); } -class ScanRSClosure : public HeapRegionClosure { - size_t _cards_done, _cards; - G1CollectedHeap* _g1h; - - G1ParPushHeapRSClosure* _oc; - CodeBlobClosure* _code_root_cl; - - G1BlockOffsetSharedArray* _bot_shared; - G1SATBCardTableModRefBS *_ct_bs; - - double _strong_code_root_scan_time_sec; - uint _worker_i; - size_t _block_size; - bool _try_claimed; - -public: - ScanRSClosure(G1ParPushHeapRSClosure* oc, - CodeBlobClosure* code_root_cl, - uint worker_i) : +ScanRSClosure::ScanRSClosure(G1ParPushHeapRSClosure* oc, + CodeBlobClosure* code_root_cl, + uint worker_i) : _oc(oc), _code_root_cl(code_root_cl), _strong_code_root_scan_time_sec(0.0), _cards(0), _cards_done(0), _worker_i(worker_i), - _try_claimed(false) - { - _g1h = G1CollectedHeap::heap(); - _bot_shared = _g1h->bot_shared(); - _ct_bs = _g1h->g1_barrier_set(); - _block_size = MAX2(G1RSetScanBlockSize, 1); + _try_claimed(false) { + _g1h = G1CollectedHeap::heap(); + _bot_shared = _g1h->bot_shared(); + _ct_bs = _g1h->g1_barrier_set(); + _block_size = MAX2(G1RSetScanBlockSize, 1); +} + +void ScanRSClosure::scanCard(size_t index, HeapRegion *r) { + // Stack allocate the DirtyCardToOopClosure instance + HeapRegionDCTOC cl(_g1h, r, _oc, + CardTableModRefBS::Precise); + + // Set the "from" region in the closure. + _oc->set_region(r); + MemRegion card_region(_bot_shared->address_for_index(index), G1BlockOffsetSharedArray::N_words); + MemRegion pre_gc_allocated(r->bottom(), r->scan_top()); + MemRegion mr = pre_gc_allocated.intersection(card_region); + if (!mr.is_empty() && !_ct_bs->is_card_claimed(index)) { + // We make the card as "claimed" lazily (so races are possible + // but they're benign), which reduces the number of duplicate + // scans (the rsets of the regions in the cset can intersect). + _ct_bs->set_card_claimed(index); + _cards_done++; + cl.do_MemRegion(mr); } +} - void set_try_claimed() { _try_claimed = true; } +void ScanRSClosure::printCard(HeapRegion* card_region, size_t card_index, + HeapWord* card_start) { + gclog_or_tty->print_cr("T %u Region [" PTR_FORMAT ", " PTR_FORMAT ") " + "RS names card " SIZE_FORMAT_HEX ": " + "[" PTR_FORMAT ", " PTR_FORMAT ")", + _worker_i, + p2i(card_region->bottom()), p2i(card_region->end()), + card_index, + p2i(card_start), p2i(card_start + G1BlockOffsetSharedArray::N_words)); +} - void scanCard(size_t index, HeapRegion *r) { - // Stack allocate the DirtyCardToOopClosure instance - HeapRegionDCTOC cl(_g1h, r, _oc, - CardTableModRefBS::Precise); +void ScanRSClosure::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); +} - // Set the "from" region in the closure. - _oc->set_region(r); - MemRegion card_region(_bot_shared->address_for_index(index), G1BlockOffsetSharedArray::N_words); - MemRegion pre_gc_allocated(r->bottom(), r->scan_top()); - MemRegion mr = pre_gc_allocated.intersection(card_region); - if (!mr.is_empty() && !_ct_bs->is_card_claimed(index)) { - // We make the card as "claimed" lazily (so races are possible - // but they're benign), which reduces the number of duplicate - // scans (the rsets of the regions in the cset can intersect). - _ct_bs->set_card_claimed(index); - _cards_done++; - cl.do_MemRegion(mr); +bool ScanRSClosure::doHeapRegion(HeapRegion* r) { + assert(r->in_collection_set(), "should only be called on elements of CS."); + HeapRegionRemSet* hrrs = r->rem_set(); + if (hrrs->iter_is_complete()) return false; // All done. + if (!_try_claimed && !hrrs->claim_iter()) return false; + // If we ever free the collection set concurrently, we should also + // clear the card table concurrently therefore we won't need to + // add regions of the collection set to the dirty cards region. + _g1h->push_dirty_cards_region(r); + // If we didn't return above, then + // _try_claimed || r->claim_iter() + // is true: either we're supposed to work on claimed-but-not-complete + // regions, or we successfully claimed the region. + + HeapRegionRemSetIterator iter(hrrs); + size_t card_index; + + // We claim cards in block so as to reduce the contention. The block size is determined by + // the G1RSetScanBlockSize parameter. + size_t jump_to_card = hrrs->iter_claimed_next(_block_size); + for (size_t current_card = 0; iter.has_next(card_index); current_card++) { + if (current_card >= jump_to_card + _block_size) { + jump_to_card = hrrs->iter_claimed_next(_block_size); } - } - - void printCard(HeapRegion* card_region, size_t card_index, - HeapWord* card_start) { - gclog_or_tty->print_cr("T %u Region [" PTR_FORMAT ", " PTR_FORMAT ") " - "RS names card " SIZE_FORMAT_HEX ": " - "[" PTR_FORMAT ", " PTR_FORMAT ")", - _worker_i, - p2i(card_region->bottom()), p2i(card_region->end()), - card_index, - p2i(card_start), p2i(card_start + G1BlockOffsetSharedArray::N_words)); - } - - void 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); - } - - bool doHeapRegion(HeapRegion* r) { - assert(r->in_collection_set(), "should only be called on elements of CS."); - HeapRegionRemSet* hrrs = r->rem_set(); - if (hrrs->iter_is_complete()) return false; // All done. - if (!_try_claimed && !hrrs->claim_iter()) return false; - // If we ever free the collection set concurrently, we should also - // clear the card table concurrently therefore we won't need to - // add regions of the collection set to the dirty cards region. - _g1h->push_dirty_cards_region(r); - // If we didn't return above, then - // _try_claimed || r->claim_iter() - // is true: either we're supposed to work on claimed-but-not-complete - // regions, or we successfully claimed the region. - - HeapRegionRemSetIterator iter(hrrs); - size_t card_index; - - // We claim cards in block so as to reduce the contention. The block size is determined by - // the G1RSetScanBlockSize parameter. - size_t jump_to_card = hrrs->iter_claimed_next(_block_size); - for (size_t current_card = 0; iter.has_next(card_index); current_card++) { - if (current_card >= jump_to_card + _block_size) { - jump_to_card = hrrs->iter_claimed_next(_block_size); - } - if (current_card < jump_to_card) continue; - HeapWord* card_start = _g1h->bot_shared()->address_for_index(card_index); + if (current_card < jump_to_card) continue; + HeapWord* card_start = _g1h->bot_shared()->address_for_index(card_index); #if 0 - gclog_or_tty->print("Rem set iteration yielded card [" PTR_FORMAT ", " PTR_FORMAT ").\n", - card_start, card_start + CardTableModRefBS::card_size_in_words); + gclog_or_tty->print("Rem set iteration yielded card [" PTR_FORMAT ", " PTR_FORMAT ").\n", + card_start, card_start + CardTableModRefBS::card_size_in_words); #endif - HeapRegion* card_region = _g1h->heap_region_containing(card_start); - _cards++; + HeapRegion* card_region = _g1h->heap_region_containing(card_start); + _cards++; - if (!card_region->is_on_dirty_cards_region_list()) { - _g1h->push_dirty_cards_region(card_region); - } - - // If the card is dirty, then we will scan it during updateRS. - if (!card_region->in_collection_set() && - !_ct_bs->is_card_dirty(card_index)) { - scanCard(card_index, card_region); - } + if (!card_region->is_on_dirty_cards_region_list()) { + _g1h->push_dirty_cards_region(card_region); } - if (!_try_claimed) { - // Scan the strong code root list attached to the current region - scan_strong_code_roots(r); - hrrs->set_iter_complete(); + // If the card is dirty, then we will scan it during updateRS. + if (!card_region->in_collection_set() && + !_ct_bs->is_card_dirty(card_index)) { + scanCard(card_index, card_region); } - return false; } + if (!_try_claimed) { + // Scan the strong code root list attached to the current region + scan_strong_code_roots(r); - double strong_code_root_scan_time_sec() { - return _strong_code_root_scan_time_sec; + hrrs->set_iter_complete(); } - - size_t cards_done() { return _cards_done;} - size_t cards_looked_up() { return _cards;} -}; + return false; +} size_t G1RemSet::scanRS(G1ParPushHeapRSClosure* oc, CodeBlobClosure* heap_region_codeblobs, diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.hpp b/hotspot/src/share/vm/gc/g1/g1RemSet.hpp index 1ecb25c27dc..39563cb1f37 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.hpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.hpp @@ -156,6 +156,41 @@ public: } }; +class ScanRSClosure : public HeapRegionClosure { + size_t _cards_done, _cards; + G1CollectedHeap* _g1h; + + G1ParPushHeapRSClosure* _oc; + CodeBlobClosure* _code_root_cl; + + G1BlockOffsetSharedArray* _bot_shared; + G1SATBCardTableModRefBS *_ct_bs; + + double _strong_code_root_scan_time_sec; + uint _worker_i; + size_t _block_size; + bool _try_claimed; + +public: + ScanRSClosure(G1ParPushHeapRSClosure* oc, + CodeBlobClosure* code_root_cl, + uint worker_i); + + bool doHeapRegion(HeapRegion* r); + + double strong_code_root_scan_time_sec() { + return _strong_code_root_scan_time_sec; + } + size_t cards_done() { return _cards_done;} + size_t cards_looked_up() { return _cards;} + void set_try_claimed() { _try_claimed = true; } +private: + void scanCard(size_t index, HeapRegion *r); + void printCard(HeapRegion* card_region, size_t card_index, + HeapWord* card_start); + void scan_strong_code_roots(HeapRegion* r); +}; + class UpdateRSOopClosure: public ExtendedOopClosure { HeapRegion* _from; G1RemSet* _rs; From 8d94626bb38b33f7bdf8eecc045a49f19c79a6d6 Mon Sep 17 00:00:00 2001 From: Stanislav Smirnov Date: Fri, 20 Nov 2015 09:44:16 -0500 Subject: [PATCH 055/260] 8133416: [TESTBUG] Remove @ignore for closed/runtime/4345157/Prog.java Rewrote test in Java with a number of improvements and conditional exclusion using make file Reviewed-by: dholmes, ctornqvi, ddmitriev --- hotspot/make/test/JtregNative.gmk | 3 +- .../test/runtime/ThreadSignalMask/Prog.java | 29 ++ .../ThreadSignalMask/ThreadSignalMask.java | 118 ++++++++ .../ThreadSignalMask/exeThreadSignalMask.c | 253 ++++++++++++++++++ 4 files changed, 402 insertions(+), 1 deletion(-) create mode 100644 hotspot/test/runtime/ThreadSignalMask/Prog.java create mode 100644 hotspot/test/runtime/ThreadSignalMask/ThreadSignalMask.java create mode 100644 hotspot/test/runtime/ThreadSignalMask/exeThreadSignalMask.c diff --git a/hotspot/make/test/JtregNative.gmk b/hotspot/make/test/JtregNative.gmk index b158b7eddb2..09c48d77aba 100644 --- a/hotspot/make/test/JtregNative.gmk +++ b/hotspot/make/test/JtregNative.gmk @@ -51,7 +51,8 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \ # Add conditional directories here when needed. ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), solaris-sparc) BUILD_HOTSPOT_JTREG_NATIVE_SRC += \ - $(HOTSPOT_TOPDIR)/test/runtime/libadimalloc.solaris.sparc + $(HOTSPOT_TOPDIR)/test/runtime/libadimalloc.solaris.sparc \ + $(HOTSPOT_TOPDIR)/test/runtime/ThreadSignalMask endif ifeq ($(TOOLCHAIN_TYPE), solstudio) diff --git a/hotspot/test/runtime/ThreadSignalMask/Prog.java b/hotspot/test/runtime/ThreadSignalMask/Prog.java new file mode 100644 index 00000000000..586b64e50e1 --- /dev/null +++ b/hotspot/test/runtime/ThreadSignalMask/Prog.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public class Prog { + + public static void main(String args[]) { + System.out.println("Java class invoked: " + args[0]); + } +} diff --git a/hotspot/test/runtime/ThreadSignalMask/ThreadSignalMask.java b/hotspot/test/runtime/ThreadSignalMask/ThreadSignalMask.java new file mode 100644 index 00000000000..39af699218d --- /dev/null +++ b/hotspot/test/runtime/ThreadSignalMask/ThreadSignalMask.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.ProcessBuilder.Redirect; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.Arrays; +import java.util.List; +import jdk.test.lib.Asserts; + +/* + * @test + * @key cte_test + * @bug 4345157 + * @summary JDK 1.3.0 alters thread signal mask + * @requires (os.simpleArch == "sparcv9") + * @library /testlibrary + * @compile Prog.java + * @run main/native ThreadSignalMask + */ +public class ThreadSignalMask { + + public static void main(String args[]) throws Exception { + + String testClasses = getSystemProperty("test.classes"); + + String testNativePath = getSystemProperty("test.nativepath"); + + String testJdk = getSystemProperty("test.jdk"); + + Path currentDirPath = Paths.get("."); + + Path classFilePath = Paths.get(testClasses, + Prog.class.getSimpleName() + ".class"); + + // copy Prog.class file to be invoked from native + Files.copy(classFilePath, + currentDirPath.resolve(Prog.class.getSimpleName() + ".class"), + StandardCopyOption.REPLACE_EXISTING); + + Path executableFilePath = Paths.get(testNativePath, + ThreadSignalMask.class.getSimpleName()); + + Path executableFileLocalPath = currentDirPath.resolve( + ThreadSignalMask.class.getSimpleName()); + + // copy compiled native executable ThreadSignalMask + Files.copy(executableFilePath, + executableFileLocalPath, + StandardCopyOption.REPLACE_EXISTING); + + executableFileLocalPath.toFile().setExecutable(true); + + long[] intervalsArray = {2000, 5000, 10000, 20000}; + + List processArgs = Arrays.asList( + executableFileLocalPath.toString(), + testJdk); + ProcessBuilder pb = new ProcessBuilder(processArgs); + pb.redirectOutput(Redirect.INHERIT); + pb.redirectError(Redirect.INHERIT); + int result = 0; + for (long interval : intervalsArray) { + Process p = pb.start(); + + // sleep for a specified period of time to let native run + sleep(interval); + p.destroy(); + + // wait for process to finish, get exit value and validate it + result = p.waitFor(); + System.out.println("Result = " + result); + if (result == 0) { + break; + } + } + + Asserts.assertEquals(result, 0); + } + + // Utility method to handle Thread.sleep + private static void sleep(long millis) throws InterruptedException { + System.out.println("Sleep for " + millis); + Thread.sleep(millis); + } + + // Utility method to retrieve and validate system properties + private static String getSystemProperty(String propertyName) throws Error { + String systemProperty = System.getProperty(propertyName, "").trim(); + System.out.println(propertyName + " = " + systemProperty); + if (systemProperty.isEmpty()) { + throw new Error("TESTBUG: property " + propertyName + " is empty"); + } + return systemProperty; + } +} diff --git a/hotspot/test/runtime/ThreadSignalMask/exeThreadSignalMask.c b/hotspot/test/runtime/ThreadSignalMask/exeThreadSignalMask.c new file mode 100644 index 00000000000..7e879e4c09c --- /dev/null +++ b/hotspot/test/runtime/ThreadSignalMask/exeThreadSignalMask.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#define _POSIX_PTHREAD_SEMANTICS // to enable POSIX semantics for certain common APIs + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void *handle; +char *error; +char path[PATH_MAX]; + +jint(JNICALL *jni_create_java_vm)(JavaVM **, JNIEnv **, void *) = NULL; + +JavaVM *jvm; + +// method to perform dlclose on an open dynamic library handle +void closeHandle() { + dlclose(handle); + if ((error = dlerror()) != NULL) { + fputs("Error occurred while closing handle\n", stderr); + } +} + +// method to exit with a fail status +void fail() { + if (handle) { + closeHandle(); + } + exit(1); +} + +// method to handle occurred error and fail +void handleError(char *messageTitle, char *messageBody) { + fprintf(stderr, "%s: %s\n", messageTitle, messageBody); + fail(); +} + +// method to load the dynamic library libjvm +void loadJVM() { + char lib[PATH_MAX]; + snprintf(lib, sizeof (lib), "%s/lib/sparcv9/server/libjvm.so", path); + handle = dlopen(lib, RTLD_LAZY); + if (!handle) { + handleError(dlerror(), "2"); + } + fputs("Will load JVM...\n", stdout); + + // find the address of function + *(void **) (&jni_create_java_vm) = dlsym(handle, "JNI_CreateJavaVM"); + if ((error = dlerror()) != NULL) { + handleError(error, "3"); + } + + fputs("JVM loaded okay.\n", stdout); +} + +// method to get created jvm environment +JNIEnv* initJVM() { + JNIEnv *env = NULL; + JavaVMInitArgs vm_args; + JavaVMOption options[1]; + jint res; + + options[0].optionString = "-Xrs"; + + vm_args.version = JNI_VERSION_1_2; + vm_args.nOptions = 1; + vm_args.options = options; + vm_args.ignoreUnrecognized = JNI_FALSE; + + fputs("Will create JVM...\n", stdout); + + res = (*jni_create_java_vm)(&jvm, &env, &vm_args); + if (res < 0) { + handleError("Can't create Java VM", strerror(res)); + } + + fputs("JVM created OK!\n", stdout); + return env; +} + +// method to invoke java method from java class +void callJava(JNIEnv *env) { + jclass cls; + jmethodID mid; + jstring jstr; + jobjectArray args; + + cls = (*env)->FindClass(env, "Prog"); + if (cls == 0) { + handleError("FindClass", "Can't find Prog class"); + } + + mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V"); + if (mid == 0) { + handleError("GetStaticMethodID", "Can't find Prog.main"); + } + + jstr = (*env)->NewStringUTF(env, "from C!"); + if (jstr == 0) { + handleError("NewStringUTF", "Out of memory"); + } + args = (*env)->NewObjectArray(env, 1, + (*env)->FindClass(env, "java/lang/String"), jstr); + if (args == 0) { + handleError("NewObjectArray", "Out of memory"); + } + (*env)->CallStaticVoidMethod(env, cls, mid, args); + +} + +// method to load, init jvm and then invoke java method +void* loadAndCallJava(void* x) { + JNIEnv *env; + + fputs("Some thread will create JVM.\n", stdout); + loadJVM(); + env = initJVM(); + + fputs("Some thread will call Java.\n", stdout); + + callJava(env); + + if ((*jvm)->DetachCurrentThread(jvm) != 0) + fputs("Error: thread not detached!\n", stderr); + fputs("Some thread exiting.\n", stdout); + return env; +} + +int main(int argc, char **argv) { + JNIEnv *env; + sigset_t set; + pthread_t thr1; + pthread_attr_t attr; + size_t ss = 0; + int sig; + int rc; // return code for pthread_* methods + + // verify input + if (argc != 2) { + handleError("usage", "a.out jdk_path"); + } + // copy input jdk path into a char buffer + strncpy(path, argv[1], PATH_MAX); + // add null termination character + path[PATH_MAX - 1] = '\0'; + + fputs("Main thread will set signal mask.\n", stdout); + + // initialize the signal set + sigemptyset(&set); + // add a number of signals to a signal set + sigaddset(&set, SIGPIPE); + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGHUP); + sigaddset(&set, SIGINT); + + // examine and change mask of blocked signal + if ((rc = pthread_sigmask(SIG_BLOCK, &set, NULL))) { + // handle error if occurred + handleError("main: pthread_sigmask() error", strerror(rc)); + } + + // initializes the thread attributes object with default attribute values + if ((rc = pthread_attr_init(&attr))) { + // handle error if occurred + handleError("main: pthread_attr_init() error", strerror(rc)); + } + + ss = 1024 * 1024; + // set the stack size attribute of the thread attributes object + if ((rc = pthread_attr_setstacksize(&attr, ss))) { + // handle error if occurred + handleError("main: pthread_attr_setstacksize() error", strerror(rc)); + } + // get the stack size attribute of the thread attributes object + if ((rc = pthread_attr_getstacksize(&attr, &ss))) { + // handle error if occurred + handleError("main: pthread_attr_getstacksize() error", strerror(rc)); + } + fprintf(stderr, "Stack size: %zu\n", ss); + + // start a new thread in the calling process, + // loadAndCallJava logic is passed as a start_routine argument + if ((rc = pthread_create(&thr1, NULL, loadAndCallJava, NULL))) { + // handle error if occurred + handleError("main: pthread_create() error", strerror(rc)); + } + + // initialize the signal set + sigemptyset(&set); + // add a number of signals to a signal set + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGHUP); + sigaddset(&set, SIGINT); + + fputs("Main thread waiting for signal.\n", stdout); + + do { + int err; + + sig = 0; + err = sigwait(&set, &sig); + if (err != 0) { + // print error message if unexpected signal occurred + fprintf(stderr, "main: sigwait() error: %s\n", strerror(err)); + } else { + // print success message and exit if expected signal occurred + // this branch generally acts when JVM executes destroy() + fprintf(stdout, "main: sigwait() got: %d\nSucceed!\n", sig); + exit(0); + } + } while (sig != SIGTERM && sig != SIGINT); // exit the loop condition + + // join with a terminated thread + if ((rc = pthread_join(thr1, NULL))) { + // handle error if occurred + handleError("main: pthread_join() error", strerror(rc)); + } + + // close an open dynamic library handle + closeHandle(); + fputs("Main thread exiting.\n", stdout); + return 0; +} From 2d7e74703ded28c735d1ebe1f08b39215784c559 Mon Sep 17 00:00:00 2001 From: David Lindholm Date: Fri, 20 Nov 2015 17:32:02 +0100 Subject: [PATCH 056/260] 8138681: Runtime.getFreeMemory() reports wrong value after humongous allocation Reviewed-by: tschatzl, mgerdin --- .../src/share/vm/gc/g1/g1BlockOffsetTable.cpp | 7 ++-- .../src/share/vm/gc/g1/g1BlockOffsetTable.hpp | 2 +- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 34 +++++++++---------- hotspot/src/share/vm/gc/g1/heapRegion.cpp | 22 ++---------- hotspot/src/share/vm/gc/g1/heapRegion.hpp | 6 ++-- 5 files changed, 28 insertions(+), 43 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp index 801e4c9f5cf..a1542adf8e5 100644 --- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp +++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp @@ -499,11 +499,14 @@ HeapWord* G1BlockOffsetArrayContigSpace::initialize_threshold() { return _next_offset_threshold; } -void G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* obj_top) { +void G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* obj_top, size_t fill_size) { // The first BOT entry should have offset 0. reset_bot(); alloc_block(_bottom, obj_top); - } + if (fill_size > 0) { + alloc_block(obj_top, fill_size); + } +} #ifndef PRODUCT void G1BlockOffsetArrayContigSpace::print_on(outputStream* out) { diff --git a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp index 7592dec864d..7c900fb960a 100644 --- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp +++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp @@ -372,7 +372,7 @@ class G1BlockOffsetArrayContigSpace: public G1BlockOffsetArray { HeapWord* block_start_unsafe(const void* addr); HeapWord* block_start_unsafe_const(const void* addr) const; - void set_for_starts_humongous(HeapWord* obj_top); + void set_for_starts_humongous(HeapWord* obj_top, size_t fill_size); virtual void print_on(outputStream* out) PRODUCT_RETURN; }; diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index 7b319955f19..e1938d910af 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -339,11 +339,18 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first, // thread to calculate the object size incorrectly. Copy::fill_to_words(new_obj, oopDesc::header_size(), 0); + size_t fill_size = word_size_sum - word_size; + if (fill_size >= min_fill_size()) { + fill_with_objects(obj_top, fill_size); + } else { + fill_size = 0; + } + // We will set up the first region as "starts humongous". This // will also update the BOT covering all the regions to reflect // that there is a single object that starts at the bottom of the // first region. - first_hr->set_starts_humongous(obj_top); + first_hr->set_starts_humongous(obj_top, fill_size); first_hr->set_allocation_context(context); // Then, if there are any, we will set up the "continues // humongous" regions. @@ -365,9 +372,9 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first, // Now that the BOT and the object header have been initialized, // we can update top of the "starts humongous" region. - first_hr->set_top(MIN2(first_hr->end(), obj_top)); + first_hr->set_top(first_hr->end()); if (_hr_printer.is_active()) { - _hr_printer.alloc(G1HRPrinter::StartsHumongous, first_hr, first_hr->top()); + _hr_printer.alloc(G1HRPrinter::StartsHumongous, first_hr, first_hr->end()); } // Now, we will update the top fields of the "continues humongous" @@ -375,25 +382,18 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first, hr = NULL; for (uint i = first + 1; i < last; ++i) { hr = region_at(i); - if ((i + 1) == last) { - // last continues humongous region - assert(hr->bottom() < obj_top && obj_top <= hr->end(), - "new_top should fall on this region"); - hr->set_top(obj_top); - _hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, obj_top); - } else { - // not last one - assert(obj_top > hr->end(), "obj_top should be above this region"); - hr->set_top(hr->end()); + hr->set_top(hr->end()); + if (_hr_printer.is_active()) { _hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, hr->end()); } } - // If we have continues humongous regions (hr != NULL), its top should - // match obj_top. - assert(hr == NULL || (hr->top() == obj_top), "sanity"); + + assert(hr == NULL || (hr->bottom() < obj_top && obj_top <= hr->end()), + "obj_top should be in last region"); + check_bitmaps("Humongous Region Allocation", first_hr); - increase_used(word_size * HeapWordSize); + increase_used(word_size_sum * HeapWordSize); for (uint i = first; i < last; ++i) { _humongous_set.add(region_at(i)); diff --git a/hotspot/src/share/vm/gc/g1/heapRegion.cpp b/hotspot/src/share/vm/gc/g1/heapRegion.cpp index 6d6081f3af0..73fa00be4ee 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp @@ -211,14 +211,14 @@ void HeapRegion::calc_gc_efficiency() { _gc_efficiency = (double) reclaimable_bytes() / region_elapsed_time_ms; } -void HeapRegion::set_starts_humongous(HeapWord* obj_top) { +void HeapRegion::set_starts_humongous(HeapWord* obj_top, size_t fill_size) { assert(!is_humongous(), "sanity / pre-condition"); assert(top() == bottom(), "should be empty"); _type.set_starts_humongous(); _humongous_start_region = this; - _offsets.set_for_starts_humongous(obj_top); + _offsets.set_for_starts_humongous(obj_top, fill_size); } void HeapRegion::set_continues_humongous(HeapRegion* first_hr) { @@ -756,16 +756,6 @@ void HeapRegion::verify(VerifyOption vo, size_t obj_size = block_size(p); object_num += 1; - if (is_region_humongous != g1->is_humongous(obj_size) && - !g1->is_obj_dead(obj, this)) { // Dead objects may have bigger block_size since they span several objects. - gclog_or_tty->print_cr("obj " PTR_FORMAT " is of %shumongous size (" - SIZE_FORMAT " words) in a %shumongous region", - p2i(p), g1->is_humongous(obj_size) ? "" : "non-", - obj_size, is_region_humongous ? "" : "non-"); - *failures = true; - return; - } - if (!g1->is_obj_dead_cond(obj, this, vo)) { if (obj->is_oop()) { Klass* klass = obj->klass(); @@ -876,14 +866,6 @@ void HeapRegion::verify(VerifyOption vo, } } - if (is_region_humongous && object_num > 1) { - gclog_or_tty->print_cr("region [" PTR_FORMAT "," PTR_FORMAT "] is humongous " - "but has " SIZE_FORMAT ", objects", - p2i(bottom()), p2i(end()), object_num); - *failures = true; - return; - } - verify_strong_code_roots(vo, failures); } diff --git a/hotspot/src/share/vm/gc/g1/heapRegion.hpp b/hotspot/src/share/vm/gc/g1/heapRegion.hpp index eba1934dda0..c6d47ab3011 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp @@ -455,9 +455,9 @@ class HeapRegion: public G1OffsetTableContigSpace { // the first region in a series of one or more contiguous regions // that will contain a single "humongous" object. // - // obj_top : points to the end of the humongous object that's being - // allocated. - void set_starts_humongous(HeapWord* obj_top); + // obj_top : points to the top of the humongous object. + // fill_size : size of the filler object at the end of the region series. + void set_starts_humongous(HeapWord* obj_top, size_t fill_size); // Makes the current region be a "continues humongous' // region. first_hr is the "start humongous" region of the series From dd059bb29fcfacc0000443f1ebf03a9cd61ac482 Mon Sep 17 00:00:00 2001 From: Marcus Larsson Date: Wed, 11 Nov 2015 15:45:17 +0100 Subject: [PATCH 057/260] 8142483: Unified logging log instances cause warnings on windows when only static functions are used Reviewed-by: brutisso, sla --- hotspot/src/share/vm/logging/log.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hotspot/src/share/vm/logging/log.hpp b/hotspot/src/share/vm/logging/log.hpp index 2f041afeb78..bcd6cde58b4 100644 --- a/hotspot/src/share/vm/logging/log.hpp +++ b/hotspot/src/share/vm/logging/log.hpp @@ -88,6 +88,11 @@ class Log VALUE_OBJ_CLASS_SPEC { // is not __NO_TAG, the number of tags given exceeds the maximum allowed. STATIC_ASSERT(GuardTag == LogTag::__NO_TAG); // Number of logging tags exceeds maximum supported! + // Empty constructor to avoid warnings on MSVC about unused variables + // when the log instance is only used for static functions. + Log() { + } + static bool is_level(LogLevelType level) { return LogTagSetMapping::tagset().is_level(level); } From 8af1d18e787af1055a7fb2cfd96b5ad15ec0da52 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Thu, 19 Nov 2015 16:14:45 +0100 Subject: [PATCH 058/260] 8143255: Remove debug logging from SymbolTable::unlink() and SymbolTable::possibly_parallel_unlink() Reviewed-by: coleenp, tschatzl --- .../src/share/vm/classfile/symbolTable.cpp | 19 +++---------------- .../src/share/vm/classfile/symbolTable.hpp | 2 +- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp index eeb23890265..b268e08bdba 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.cpp +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp @@ -97,7 +97,7 @@ int SymbolTable::_symbols_removed = 0; int SymbolTable::_symbols_counted = 0; volatile int SymbolTable::_parallel_claimed_idx = 0; -void SymbolTable::buckets_unlink(int start_idx, int end_idx, int* processed, int* removed, size_t* memory_total) { +void SymbolTable::buckets_unlink(int start_idx, int end_idx, int* processed, int* removed) { for (int i = start_idx; i < end_idx; ++i) { HashtableEntry** p = the_table()->bucket_addr(i); HashtableEntry* entry = the_table()->bucket(i); @@ -110,7 +110,6 @@ void SymbolTable::buckets_unlink(int start_idx, int end_idx, int* processed, int break; } Symbol* s = entry->literal(); - (*memory_total) += s->size(); (*processed)++; assert(s != NULL, "just checking"); // If reference count is zero, remove. @@ -133,15 +132,9 @@ void SymbolTable::buckets_unlink(int start_idx, int end_idx, int* processed, int // This is done late during GC. void SymbolTable::unlink(int* processed, int* removed) { size_t memory_total = 0; - buckets_unlink(0, the_table()->table_size(), processed, removed, &memory_total); + buckets_unlink(0, the_table()->table_size(), processed, removed); _symbols_removed += *removed; _symbols_counted += *processed; - // Exclude printing for normal PrintGCDetails because people parse - // this output. - if (PrintGCDetails && Verbose && WizardMode) { - gclog_or_tty->print(" [Symbols=%d size=" SIZE_FORMAT "K] ", *processed, - (memory_total*HeapWordSize)/1024); - } } void SymbolTable::possibly_parallel_unlink(int* processed, int* removed) { @@ -158,16 +151,10 @@ void SymbolTable::possibly_parallel_unlink(int* processed, int* removed) { } int end_idx = MIN2(limit, start_idx + ClaimChunkSize); - buckets_unlink(start_idx, end_idx, processed, removed, &memory_total); + buckets_unlink(start_idx, end_idx, processed, removed); } Atomic::add(*processed, &_symbols_counted); Atomic::add(*removed, &_symbols_removed); - // Exclude printing for normal PrintGCDetails because people parse - // this output. - if (PrintGCDetails && Verbose && WizardMode) { - gclog_or_tty->print(" [Symbols: scanned=%d removed=%d size=" SIZE_FORMAT "K] ", *processed, *removed, - (memory_total*HeapWordSize)/1024); - } } // Create a new table and using alternate hash code, populate the new table diff --git a/hotspot/src/share/vm/classfile/symbolTable.hpp b/hotspot/src/share/vm/classfile/symbolTable.hpp index 29ee8d2b779..8f310e70e1b 100644 --- a/hotspot/src/share/vm/classfile/symbolTable.hpp +++ b/hotspot/src/share/vm/classfile/symbolTable.hpp @@ -132,7 +132,7 @@ private: static volatile int _parallel_claimed_idx; // Release any dead symbols - static void buckets_unlink(int start_idx, int end_idx, int* processed, int* removed, size_t* memory_total); + static void buckets_unlink(int start_idx, int end_idx, int* processed, int* removed); public: enum { symbol_alloc_batch_size = 8, From c02b26ee45b405fd55ba4e15dedc6ed1d7912b14 Mon Sep 17 00:00:00 2001 From: Christian Tornqvist Date: Thu, 19 Nov 2015 10:34:11 -0800 Subject: [PATCH 059/260] 8143324: Backout JDK-8087223 Reviewed-by: coleenp, acorn --- hotspot/src/share/vm/ci/ciEnv.cpp | 9 +- hotspot/src/share/vm/ci/ciEnv.hpp | 3 +- hotspot/src/share/vm/ci/ciMethod.cpp | 3 +- .../src/share/vm/interpreter/linkResolver.cpp | 21 +- .../src/share/vm/interpreter/linkResolver.hpp | 21 +- .../src/share/vm/jvmci/jvmciCompilerToVM.cpp | 4 +- hotspot/src/share/vm/jvmci/jvmciEnv.cpp | 8 +- hotspot/src/share/vm/jvmci/jvmciEnv.hpp | 3 +- hotspot/src/share/vm/oops/constantPool.cpp | 23 -- hotspot/src/share/vm/oops/constantPool.hpp | 3 - hotspot/src/share/vm/prims/methodHandles.cpp | 6 +- hotspot/src/share/vm/runtime/javaCalls.cpp | 6 +- hotspot/src/share/vm/runtime/reflection.cpp | 2 +- .../runtime/8087223/BadMethodHandles.java | 250 ------------------ hotspot/test/runtime/8087223/IntfMethod.java | 156 ----------- 15 files changed, 22 insertions(+), 496 deletions(-) delete mode 100644 hotspot/test/runtime/8087223/BadMethodHandles.java delete mode 100644 hotspot/test/runtime/8087223/IntfMethod.java diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index 2e096bb303a..9c9d7b300c2 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -704,14 +704,13 @@ Method* ciEnv::lookup_method(InstanceKlass* accessor, InstanceKlass* holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc, - constantTag tag) { + Bytecodes::Code bc) { EXCEPTION_CONTEXT; KlassHandle h_accessor(THREAD, accessor); KlassHandle h_holder(THREAD, holder); LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL)); methodHandle dest_method; - LinkInfo link_info(h_holder, name, sig, h_accessor, LinkInfo::needs_access_check, tag); + LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true); switch (bc) { case Bytecodes::_invokestatic: dest_method = @@ -797,9 +796,7 @@ ciMethod* ciEnv::get_method_by_index_impl(const constantPoolHandle& cpool, if (holder_is_accessible) { // Our declared holder is loaded. InstanceKlass* lookup = declared_holder->get_instanceKlass(); - constantTag tag = cpool->tag_ref_at(index); - assert(accessor->get_instanceKlass() == cpool->pool_holder(), "not the pool holder?"); - Method* m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc, tag); + Method* m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc); if (m != NULL && (bc == Bytecodes::_invokestatic ? m->method_holder()->is_not_initialized() diff --git a/hotspot/src/share/vm/ci/ciEnv.hpp b/hotspot/src/share/vm/ci/ciEnv.hpp index abffa79e4e5..b1a95bd38f6 100644 --- a/hotspot/src/share/vm/ci/ciEnv.hpp +++ b/hotspot/src/share/vm/ci/ciEnv.hpp @@ -158,8 +158,7 @@ private: InstanceKlass* holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc, - constantTag tag); + Bytecodes::Code bc); // Get a ciObject from the object factory. Ensures uniqueness // of ciObjects. diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index 50aa4dc42c1..0acf602a4cc 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -786,8 +786,7 @@ ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, boo Symbol* h_name = name()->get_symbol(); Symbol* h_signature = signature()->get_symbol(); - LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass, - check_access ? LinkInfo::needs_access_check : LinkInfo::skip_access_check); + LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass, check_access); methodHandle m; // Only do exact lookup if receiver klass has been linked. Otherwise, // the vtable has not been setup, and the LinkResolver will fail. diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index 42dc138319a..173ec0ec667 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -245,7 +245,6 @@ LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, TRAPS) { // Get name, signature, and static klass _name = pool->name_ref_at(index); _signature = pool->signature_ref_at(index); - _tag = pool->tag_ref_at(index); _current_klass = KlassHandle(THREAD, pool->pool_holder()); // Coming from the constant pool always checks access @@ -682,15 +681,6 @@ methodHandle LinkResolver::resolve_method(const LinkInfo& link_info, THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } - // check tag at call is method - if (!link_info.tag().is_invalid() && !link_info.tag().is_method()) { - ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "Resolving to non regular method %s", link_info.method_string()); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); - } - - // 2. lookup method in resolved klass and its super klasses methodHandle resolved_method = lookup_method_in_klasses(link_info, true, false, CHECK_NULL); @@ -750,14 +740,6 @@ methodHandle LinkResolver::resolve_interface_method(const LinkInfo& link_info, THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } - // check tag at call is an interface method - if (!link_info.tag().is_invalid() && !link_info.tag().is_interface_method()) { - ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "Resolving to non interface method %s", link_info.method_string()); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); - } - // lookup method in this interface or its super, java.lang.Object // JDK8: also look for static methods methodHandle resolved_method = lookup_method_in_klasses(link_info, false, true, CHECK_NULL); @@ -935,8 +917,7 @@ void LinkResolver::resolve_static_call(CallInfo& result, resolved_klass->initialize(CHECK); // Use updated LinkInfo (to reresolve with resolved_klass as method_holder?) LinkInfo new_info(resolved_klass, link_info.name(), link_info.signature(), - link_info.current_klass(), - link_info.check_access() ? LinkInfo::needs_access_check : LinkInfo::skip_access_check); + link_info.current_klass(), link_info.check_access()); resolved_method = linktime_resolve_static_method(new_info, CHECK); } diff --git a/hotspot/src/share/vm/interpreter/linkResolver.hpp b/hotspot/src/share/vm/interpreter/linkResolver.hpp index 919496bfa69..198eefbe2c0 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp @@ -135,35 +135,20 @@ class LinkInfo : public StackObj { KlassHandle _resolved_klass; // class that the constant pool entry points to KlassHandle _current_klass; // class that owns the constant pool bool _check_access; - constantTag _tag; public: - enum AccessCheck { - needs_access_check, - skip_access_check - }; - LinkInfo(const constantPoolHandle& pool, int index, TRAPS); - // Condensed information from other call sites within the vm. - LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature, KlassHandle current_klass, - AccessCheck check_access = needs_access_check, - constantTag tag = JVM_CONSTANT_Invalid) : + LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature, + KlassHandle current_klass, bool check_access = true) : _resolved_klass(resolved_klass), _name(name), _signature(signature), _current_klass(current_klass), - _check_access(check_access == needs_access_check && current_klass.not_null()), _tag(tag) {} - - // Case where we just find the method and don't check access against the current class - LinkInfo(KlassHandle resolved_klass, Symbol*name, Symbol* signature) : - _resolved_klass(resolved_klass), - _name(name), _signature(signature), _current_klass(NULL), - _check_access(false), _tag(JVM_CONSTANT_Invalid) {} + _check_access(check_access) {} // accessors Symbol* name() const { return _name; } Symbol* signature() const { return _signature; } KlassHandle resolved_klass() const { return _resolved_klass; } KlassHandle current_klass() const { return _current_klass; } - constantTag tag() const { return _tag; } bool check_access() const { return _check_access; } char* method_string() const; diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp index c4d3dfbb6b2..c0f773e279b 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -574,7 +574,7 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t if (holder_klass->is_interface()) { // do link-time resolution to check all access rules. - LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass); + LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true); methodHandle resolved_method = LinkResolver::linktime_resolve_interface_method_or_null(link_info); if (resolved_method.is_null() || resolved_method->is_private()) { return NULL; @@ -586,7 +586,7 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t return JNIHandles::make_local(THREAD, result); } else { // do link-time resolution to check all access rules. - LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass); + LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true); methodHandle resolved_method = LinkResolver::linktime_resolve_virtual_method_or_null(link_info); if (resolved_method.is_null()) { return NULL; diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp index 808d4924ea8..348a28601be 100644 --- a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp @@ -282,12 +282,11 @@ methodHandle JVMCIEnv::lookup_method(instanceKlassHandle& h_accessor, instanceKlassHandle& h_holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc, - constantTag tag) { + Bytecodes::Code bc) { JVMCI_EXCEPTION_CONTEXT; LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL)); methodHandle dest_method; - LinkInfo link_info(h_holder, name, sig, h_accessor, LinkInfo::needs_access_check, tag); + LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true); switch (bc) { case Bytecodes::_invokestatic: dest_method = @@ -360,8 +359,7 @@ methodHandle JVMCIEnv::get_method_by_index_impl(const constantPoolHandle& cpool, if (holder_is_accessible) { // Our declared holder is loaded. instanceKlassHandle lookup = get_instance_klass_for_declared_method_holder(holder); - constantTag tag = cpool->tag_ref_at(index); - methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc, tag); + methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc); if (!m.is_null() && (bc == Bytecodes::_invokestatic ? InstanceKlass::cast(m->method_holder())->is_not_initialized() diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp index 4f9cf9271b7..f0291efde26 100644 --- a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp @@ -125,8 +125,7 @@ private: instanceKlassHandle& holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc, - constantTag tag); + Bytecodes::Code bc); private: diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp index 9900c45c816..006a1e5b5a6 100644 --- a/hotspot/src/share/vm/oops/constantPool.cpp +++ b/hotspot/src/share/vm/oops/constantPool.cpp @@ -409,19 +409,6 @@ int ConstantPool::impl_name_and_type_ref_index_at(int which, bool uncached) { return extract_high_short_from_int(ref_index); } -constantTag ConstantPool::impl_tag_ref_at(int which, bool uncached) { - int pool_index = which; - if (!uncached && cache() != NULL) { - if (ConstantPool::is_invokedynamic_index(which)) { - // Invokedynamic index is index into resolved_references - pool_index = invokedynamic_cp_cache_entry_at(which)->constant_pool_index(); - } else { - // change byte-ordering and go via cache - pool_index = remap_instruction_operand_from_cache(which); - } - } - return tag_at(pool_index); -} int ConstantPool::impl_klass_ref_index_at(int which, bool uncached) { guarantee(!ConstantPool::is_invokedynamic_index(which), @@ -677,7 +664,6 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, in int callee_index = this_cp->method_handle_klass_index_at(index); Symbol* name = this_cp->method_handle_name_ref_at(index); Symbol* signature = this_cp->method_handle_signature_ref_at(index); - constantTag m_tag = this_cp->tag_at(this_cp->method_handle_index_at(index)); if (PrintMiscellaneous) tty->print_cr("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s", ref_kind, index, this_cp->method_handle_index_at(index), @@ -686,15 +672,6 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, in { Klass* k = klass_at_impl(this_cp, callee_index, true, CHECK_NULL); callee = KlassHandle(THREAD, k); } - if ((callee->is_interface() && m_tag.is_method()) || - (!callee->is_interface() && m_tag.is_interface_method())) { - ResourceMark rm(THREAD); - char buf[200]; - jio_snprintf(buf, sizeof(buf), "Inconsistent constant data for %s.%s%s at index %d", - callee->name()->as_C_string(), name->as_C_string(), signature->as_C_string(), index); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); - } - KlassHandle klass(THREAD, this_cp->pool_holder()); Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind, callee, name, signature, diff --git a/hotspot/src/share/vm/oops/constantPool.hpp b/hotspot/src/share/vm/oops/constantPool.hpp index 740e9f77bac..99d77253be9 100644 --- a/hotspot/src/share/vm/oops/constantPool.hpp +++ b/hotspot/src/share/vm/oops/constantPool.hpp @@ -664,8 +664,6 @@ class ConstantPool : public Metadata { int remap_instruction_operand_from_cache(int operand); // operand must be biased by CPCACHE_INDEX_TAG - constantTag tag_ref_at(int cp_cache_index) { return impl_tag_ref_at(cp_cache_index, false); } - // Lookup for entries consisting of (name_index, signature_index) int name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt) int signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt) @@ -786,7 +784,6 @@ class ConstantPool : public Metadata { Symbol* impl_signature_ref_at(int which, bool uncached); int impl_klass_ref_index_at(int which, bool uncached); int impl_name_and_type_ref_index_at(int which, bool uncached); - constantTag impl_tag_ref_at(int which, bool uncached); // Used while constructing constant pool (only by ClassFileParser) jint klass_index_at(int which) { diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index 0a72474dfa3..0f58dde7063 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -679,7 +679,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS case IS_METHOD: { CallInfo result; - LinkInfo link_info(defc, name, type, caller); + LinkInfo link_info(defc, name, type, caller, caller.not_null()); { assert(!HAS_PENDING_EXCEPTION, ""); if (ref_kind == JVM_REF_invokeStatic) { @@ -716,7 +716,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS case IS_CONSTRUCTOR: { CallInfo result; - LinkInfo link_info(defc, name, type, caller); + LinkInfo link_info(defc, name, type, caller, caller.not_null()); { assert(!HAS_PENDING_EXCEPTION, ""); if (name == vmSymbols::object_initializer_name()) { @@ -737,7 +737,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS fieldDescriptor result; // find_field initializes fd if found { assert(!HAS_PENDING_EXCEPTION, ""); - LinkInfo link_info(defc, name, type, caller, LinkInfo::skip_access_check); + LinkInfo link_info(defc, name, type, caller, /*check_access*/false); LinkResolver::resolve_field(result, link_info, Bytecodes::_nop, false, THREAD); if (HAS_PENDING_EXCEPTION) { return empty; diff --git a/hotspot/src/share/vm/runtime/javaCalls.cpp b/hotspot/src/share/vm/runtime/javaCalls.cpp index 82cbd26b2d4..9acd0200b29 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.cpp +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp @@ -183,7 +183,7 @@ void JavaCalls::call_virtual(JavaValue* result, KlassHandle spec_klass, Symbol* CallInfo callinfo; Handle receiver = args->receiver(); KlassHandle recvrKlass(THREAD, receiver.is_null() ? (Klass*)NULL : receiver->klass()); - LinkInfo link_info(spec_klass, name, signature); + LinkInfo link_info(spec_klass, name, signature, KlassHandle(), /*check_access*/false); LinkResolver::resolve_virtual_call( callinfo, receiver, recvrKlass, link_info, true, CHECK); methodHandle method = callinfo.selected_method(); @@ -220,7 +220,7 @@ void JavaCalls::call_virtual(JavaValue* result, Handle receiver, KlassHandle spe void JavaCalls::call_special(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) { CallInfo callinfo; - LinkInfo link_info(klass, name, signature); + LinkInfo link_info(klass, name, signature, KlassHandle(), /*check_access*/false); LinkResolver::resolve_special_call(callinfo, link_info, CHECK); methodHandle method = callinfo.selected_method(); assert(method.not_null(), "should have thrown exception"); @@ -255,7 +255,7 @@ void JavaCalls::call_special(JavaValue* result, Handle receiver, KlassHandle kla void JavaCalls::call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) { CallInfo callinfo; - LinkInfo link_info(klass, name, signature); + LinkInfo link_info(klass, name, signature, KlassHandle(), /*check_access*/false); LinkResolver::resolve_static_call(callinfo, link_info, true, CHECK); methodHandle method = callinfo.selected_method(); assert(method.not_null(), "should have thrown exception"); diff --git a/hotspot/src/share/vm/runtime/reflection.cpp b/hotspot/src/share/vm/runtime/reflection.cpp index d44ce3869fa..45746d67c7c 100644 --- a/hotspot/src/share/vm/runtime/reflection.cpp +++ b/hotspot/src/share/vm/runtime/reflection.cpp @@ -830,7 +830,7 @@ methodHandle Reflection::resolve_interface_call(instanceKlassHandle klass, const Symbol* signature = method->signature(); Symbol* name = method->name(); LinkResolver::resolve_interface_call(info, receiver, recv_klass, - LinkInfo(klass, name, signature), + LinkInfo(klass, name, signature, KlassHandle(), false), true, CHECK_(methodHandle())); return info.selected_method(); diff --git a/hotspot/test/runtime/8087223/BadMethodHandles.java b/hotspot/test/runtime/8087223/BadMethodHandles.java deleted file mode 100644 index 57defac0fe2..00000000000 --- a/hotspot/test/runtime/8087223/BadMethodHandles.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * $bug 8087223 - * @summary Adding constantTag to keep method call consistent with it. - * @compile -XDignore.symbol.file BadMethodHandles.java - * @run main/othervm BadMethodHandles - */ - -import jdk.internal.org.objectweb.asm.*; -import java.io.FileOutputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import static jdk.internal.org.objectweb.asm.Opcodes.*; - -public class BadMethodHandles { - - static byte[] dumpBadInterfaceMethodref() { - ClassWriter cw = new ClassWriter(0); - cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadInterfaceMethodref", null, "java/lang/Object", null); - Handle handle1 = - new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "m", "()V"); - Handle handle2 = - new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "staticM", "()V"); - - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null); - mv.visitCode(); - mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); - mv.visitLdcInsn("hello from m"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null); - mv.visitCode(); - mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); - mv.visitLdcInsn("hello from staticM"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 1); - mv.visitEnd(); - } - - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null); - mv.visitCode(); - // REF_invokeStatic - mv.visitLdcInsn(handle1); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null); - mv.visitCode(); - // REF_invokeStatic - mv.visitLdcInsn(handle2); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - cw.visitEnd(); - return cw.toByteArray(); - } - - static byte[] dumpIBad() { - ClassWriter cw = new ClassWriter(0); - cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "IBad", null, "java/lang/Object", null); - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null); - mv.visitCode(); - mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); - mv.visitLdcInsn("hello from m"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null); - mv.visitCode(); - mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); - mv.visitLdcInsn("hello from staticM"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 1); - mv.visitEnd(); - } - cw.visitEnd(); - return cw.toByteArray(); - } - - static byte[] dumpBadMethodref() { - ClassWriter cw = new ClassWriter(0); - cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadMethodref", null, "java/lang/Object", new String[]{"IBad"}); - Handle handle1 = - new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "m", "()V"); - Handle handle2 = - new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "staticM", "()V"); - - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null); - mv.visitCode(); - // REF_invokeStatic - mv.visitLdcInsn(handle1); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null); - mv.visitCode(); - // REF_invokeStatic - mv.visitLdcInsn(handle2); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - cw.visitEnd(); - return cw.toByteArray(); - } - static class CL extends ClassLoader { - @Override - protected Class findClass(String name) throws ClassNotFoundException { - byte[] classBytes = null; - switch (name) { - case "BadInterfaceMethodref": classBytes = dumpBadInterfaceMethodref(); break; - case "BadMethodref" : classBytes = dumpBadMethodref(); break; - case "IBad" : classBytes = dumpIBad(); break; - default : throw new ClassNotFoundException(name); - } - return defineClass(name, classBytes, 0, classBytes.length); - } - } - - public static void main(String[] args) throws Throwable { - try (FileOutputStream fos = new FileOutputStream("BadInterfaceMethodref.class")) { - fos.write(dumpBadInterfaceMethodref()); - } - try (FileOutputStream fos = new FileOutputStream("IBad.class")) { - fos.write(dumpIBad()); - } - try (FileOutputStream fos = new FileOutputStream("BadMethodref.class")) { - fos.write(dumpBadMethodref()); - } - - Class cls = (new CL()).loadClass("BadInterfaceMethodref"); - String[] methods = {"runm", "runStaticM"}; - System.out.println("Test BadInterfaceMethodref:"); - int success = 0; - for (String name : methods) { - try { - System.out.printf("invoke %s: \n", name); - cls.getMethod(name).invoke(cls.newInstance()); - System.out.println("FAILED (no exception)"); // ICCE should be thrown - } catch (Throwable e) { - if (e instanceof InvocationTargetException && e.getCause() != null && - e.getCause() instanceof IncompatibleClassChangeError) { - System.out.println("PASSED"); - success++; - continue; - } else { - System.out.println("FAILED with exception"); - throw e; - } - } - } - if (success != methods.length) { - throw new Exception("BadInterfaceMethodRef Failed to catch IncompatibleClassChangeError"); - } - System.out.println("Test BadMethodref:"); - cls = (new CL()).loadClass("BadMethodref"); - success = 0; - for (String name : methods) { - try { - System.out.printf("invoke %s: \n", name); - cls.getMethod(name).invoke(cls.newInstance()); - System.out.println("FAILED (no exception)"); // ICCE should be thrown - } catch (Throwable e) { - if (e instanceof InvocationTargetException && e.getCause() != null && - e.getCause() instanceof IncompatibleClassChangeError) { - System.out.println("PASSED"); - success++; - continue; - } else { - System.out.println("FAILED with exception"); - throw e; - } - } - } - if (success != methods.length) { - throw new Exception("BadMethodRef Failed to catch IncompatibleClassChangeError"); - } - - } -} diff --git a/hotspot/test/runtime/8087223/IntfMethod.java b/hotspot/test/runtime/8087223/IntfMethod.java deleted file mode 100644 index a3a4ee3b8d8..00000000000 --- a/hotspot/test/runtime/8087223/IntfMethod.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * $bug 8087223 - * @summary Adding constantTag to keep method call consistent with it. - * @compile -XDignore.symbol.file IntfMethod.java - * @run main/othervm IntfMethod - * @run main/othervm -Xint IntfMethod - * @run main/othervm -Xcomp IntfMethod - */ - - -import jdk.internal.org.objectweb.asm.*; -import java.io.FileOutputStream; -import java.lang.reflect.InvocationTargetException; -import static jdk.internal.org.objectweb.asm.Opcodes.*; - -public class IntfMethod { - static byte[] dumpC() { - ClassWriter cw = new ClassWriter(0); - cw.visit(52, ACC_PUBLIC | ACC_SUPER, "C", null, "java/lang/Object", new String[]{"I"}); - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testSpecialIntf", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "I", "f1", "()V", /*itf=*/false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testStaticIntf", "()V", null, null); - mv.visitCode(); - mv.visitMethodInsn(INVOKESTATIC, "I", "f2", "()V", /*itf=*/false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testSpecialClass", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "C", "f1", "()V", /*itf=*/true); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f2", "()V", null, null); - mv.visitCode(); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testStaticClass", "()V", null, null); - mv.visitCode(); - mv.visitMethodInsn(INVOKESTATIC, "C", "f2", "()V", /*itf=*/true); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - cw.visitEnd(); - return cw.toByteArray(); - } - - static byte[] dumpI() { - ClassWriter cw = new ClassWriter(0); - cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "I", null, "java/lang/Object", null); - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "f1", "()V", null, null); - mv.visitCode(); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 1); - mv.visitEnd(); - } - { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f2", "()V", null, null); - mv.visitCode(); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 1); - mv.visitEnd(); - } - cw.visitEnd(); - return cw.toByteArray(); - } - - static class CL extends ClassLoader { - @Override - protected Class findClass(String name) throws ClassNotFoundException { - byte[] classFile; - switch (name) { - case "I": classFile = dumpI(); break; - case "C": classFile = dumpC(); break; - default: - throw new ClassNotFoundException(name); - } - return defineClass(name, classFile, 0, classFile.length); - } - } - - public static void main(String[] args) throws Throwable { - Class cls = (new CL()).loadClass("C"); - try (FileOutputStream fos = new FileOutputStream("I.class")) { fos.write(dumpI()); } - try (FileOutputStream fos = new FileOutputStream("C.class")) { fos.write(dumpC()); } - - int success = 0; - for (String name : new String[] { "testSpecialIntf", "testStaticIntf", "testSpecialClass", "testStaticClass"}) { - System.out.printf("%s: ", name); - try { - cls.getMethod(name).invoke(cls.newInstance()); - System.out.println("FAILED"); - } catch (Throwable e) { - if (e instanceof InvocationTargetException && - e.getCause() != null && e.getCause() instanceof IncompatibleClassChangeError) { - System.out.println("PASSED"); - success++; - continue; - } - } - } - if (success != 4) throw new Exception("Failed to catch ICCE"); - } -} From 961fbacd764aa23555e1c6ec0ee5438d9d5eea87 Mon Sep 17 00:00:00 2001 From: Marcus Larsson Date: Fri, 20 Nov 2015 12:42:21 +0100 Subject: [PATCH 060/260] 8143229: Replace the develop level with develop macros in Unified Logging Reviewed-by: brutisso, coleenp, dholmes, rprotacio --- hotspot/src/share/vm/logging/log.cpp | 4 ++-- hotspot/src/share/vm/logging/log.hpp | 14 ++++++++++++-- hotspot/src/share/vm/logging/logConfiguration.cpp | 1 + hotspot/src/share/vm/logging/logLevel.hpp | 11 ++--------- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/hotspot/src/share/vm/logging/log.cpp b/hotspot/src/share/vm/logging/log.cpp index 1e9f94bec9d..eda1877c88c 100644 --- a/hotspot/src/share/vm/logging/log.cpp +++ b/hotspot/src/share/vm/logging/log.cpp @@ -37,10 +37,10 @@ void Test_log_length() { // Write long message to output file MutexLocker ml(LogConfiguration_lock); - LogConfiguration::parse_log_arguments("loglengthoutput.txt", "logging=develop", + LogConfiguration::parse_log_arguments("loglengthoutput.txt", "logging=trace", NULL, NULL, NULL); ResourceMark rm; - outputStream* logstream = LogHandle(logging)::develop_stream(); + outputStream* logstream = LogHandle(logging)::trace_stream(); logstream->print_cr("01:1234567890-" "02:1234567890-" "03:1234567890-" diff --git a/hotspot/src/share/vm/logging/log.hpp b/hotspot/src/share/vm/logging/log.hpp index bcd6cde58b4..8b65f0cd2dd 100644 --- a/hotspot/src/share/vm/logging/log.hpp +++ b/hotspot/src/share/vm/logging/log.hpp @@ -49,11 +49,21 @@ #define log_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : Log::write #define log_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : Log::write #define log_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : Log::write + +// Macros for logging that should be excluded in product builds. +// Available for levels Info, Debug and Trace. Includes test macro that +// evaluates to false in product builds. #ifndef PRODUCT -#define log_develop(...) (!log_is_enabled(Develop, __VA_ARGS__)) ? (void)0 : Log::write +#define log_develop_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : Log::write +#define log_develop_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : Log::write +#define log_develop_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : Log::write +#define develop_log_is_enabled(level, ...) log_is_enabled(level, __VA_ARGS__) #else #define DUMMY_ARGUMENT_CONSUMER(...) -#define log_develop(...) DUMMY_ARGUMENT_CONSUMER +#define log_develop_info(...) DUMMY_ARGUMENT_CONSUMER +#define log_develop_debug(...) DUMMY_ARGUMENT_CONSUMER +#define log_develop_trace(...) DUMMY_ARGUMENT_CONSUMER +#define develop_log_is_enabled(...) false #endif // Convenience macro to test if the logging is enabled on the specified level for given tags. diff --git a/hotspot/src/share/vm/logging/logConfiguration.cpp b/hotspot/src/share/vm/logging/logConfiguration.cpp index d575a458249..704c2e3e31b 100644 --- a/hotspot/src/share/vm/logging/logConfiguration.cpp +++ b/hotspot/src/share/vm/logging/logConfiguration.cpp @@ -44,6 +44,7 @@ void LogConfiguration::post_initialize() { LogDiagnosticCommand::registerCommand(); LogHandle(logging) log; log.info("Log configuration fully initialized."); + log_develop_info(logging)("Develop logging is available."); if (log.is_trace()) { ResourceMark rm; MutexLocker ml(LogConfiguration_lock); diff --git a/hotspot/src/share/vm/logging/logLevel.hpp b/hotspot/src/share/vm/logging/logLevel.hpp index 55ac3564d2c..7106c548e80 100644 --- a/hotspot/src/share/vm/logging/logLevel.hpp +++ b/hotspot/src/share/vm/logging/logLevel.hpp @@ -29,14 +29,8 @@ // The list of log levels: // -// develop - A non-product level that is finer than trace. -// Should be used for really expensive and/or -// extensive logging, or logging that shouldn't -// or can't be included in a product build. -// -// trace - Finest level of logging in product builds. -// Use for extensive/noisy logging that can -// give slow-down when enabled. +// trace - Finest level of logging. Use for extensive/noisy +// logging that can give slow-down when enabled. // // debug - A finer level of logging. Use for semi-noisy // logging that is does not fit the info level. @@ -49,7 +43,6 @@ // error - Critical messages caused by errors. // #define LOG_LEVEL_LIST \ - NOT_PRODUCT(LOG_LEVEL(Develop, develop)) \ LOG_LEVEL(Trace, trace) \ LOG_LEVEL(Debug, debug) \ LOG_LEVEL(Info, info) \ From a138de135444c7a34dadd48d4c9839da84e6500e Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Fri, 20 Nov 2015 11:57:33 -0600 Subject: [PATCH 061/260] 8141706: [TESTBUG] Update tests failing due to changed behavior Add UnlockDiagnosticVMOptions as appropriate. Reviewed-by: kvn, dholmes --- hotspot/test/compiler/c2/8004741/Test8004741.java | 4 ++-- .../test/compiler/loopopts/TestCastIINoLoopLimitCheck.java | 2 +- hotspot/test/compiler/runtime/7196199/Test7196199.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hotspot/test/compiler/c2/8004741/Test8004741.java b/hotspot/test/compiler/c2/8004741/Test8004741.java index baacc34763d..7e64ff14d6e 100644 --- a/hotspot/test/compiler/c2/8004741/Test8004741.java +++ b/hotspot/test/compiler/c2/8004741/Test8004741.java @@ -25,8 +25,8 @@ * @test Test8004741.java * @bug 8004741 * @summary Missing compiled exception handle table entry for multidimensional array allocation - * @run main/othervm -Xmx64m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:+StressCompiledExceptionHandlers -XX:+SafepointALot -XX:GuaranteedSafepointInterval=100 Test8004741 - * @run main/othervm -Xmx64m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:+StressCompiledExceptionHandlers Test8004741 + * @run main/othervm -Xmx64m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:+StressCompiledExceptionHandlers -XX:+SafepointALot -XX:GuaranteedSafepointInterval=100 Test8004741 + * @run main/othervm -Xmx64m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:+StressCompiledExceptionHandlers Test8004741 */ import java.util.*; diff --git a/hotspot/test/compiler/loopopts/TestCastIINoLoopLimitCheck.java b/hotspot/test/compiler/loopopts/TestCastIINoLoopLimitCheck.java index c9c985ab4ac..57a61459192 100644 --- a/hotspot/test/compiler/loopopts/TestCastIINoLoopLimitCheck.java +++ b/hotspot/test/compiler/loopopts/TestCastIINoLoopLimitCheck.java @@ -26,7 +26,7 @@ * @test * @bug 8073184 * @summary CastII that guards counted loops confuses range check elimination with LoopLimitCheck off - * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-LoopLimitCheck -XX:CompileOnly=TestCastIINoLoopLimitCheck.m -Xcomp TestCastIINoLoopLimitCheck + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-LoopLimitCheck -XX:CompileOnly=TestCastIINoLoopLimitCheck.m -Xcomp TestCastIINoLoopLimitCheck * */ diff --git a/hotspot/test/compiler/runtime/7196199/Test7196199.java b/hotspot/test/compiler/runtime/7196199/Test7196199.java index 6aa35369a31..8f0c520df0e 100644 --- a/hotspot/test/compiler/runtime/7196199/Test7196199.java +++ b/hotspot/test/compiler/runtime/7196199/Test7196199.java @@ -27,7 +27,7 @@ * @bug 7196199 * @summary java/text/Bidi/Bug6665028.java failed: Bidi run count incorrect * - * @run main/othervm/timeout=400 -Xmx32m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:CompileCommand=exclude,Test7196199.test -XX:+SafepointALot -XX:GuaranteedSafepointInterval=100 Test7196199 + * @run main/othervm/timeout=400 -Xmx32m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:CompileCommand=exclude,Test7196199.test -XX:+SafepointALot -XX:GuaranteedSafepointInterval=100 Test7196199 */ From f3ff4f52ccc4349ef814594f64f71ee02da2a08c Mon Sep 17 00:00:00 2001 From: Alexander Harlap Date: Mon, 23 Nov 2015 11:43:02 -0500 Subject: [PATCH 062/260] 8141135: Remove G1RemSet::write_ref Remove unused memembers of G1RemSet Reviewed-by: kbarrett, tschatzl --- hotspot/src/share/vm/gc/g1/g1RemSet.hpp | 11 ----------- hotspot/src/share/vm/gc/g1/g1RemSet.inline.hpp | 5 ----- 2 files changed, 16 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.hpp b/hotspot/src/share/vm/gc/g1/g1RemSet.hpp index 39563cb1f37..72a259ef417 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.hpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.hpp @@ -54,16 +54,6 @@ protected: uint n_workers(); protected: - enum SomePrivateConstants { - UpdateRStoMergeSync = 0, - MergeRStoDoDirtySync = 1, - DoDirtySync = 2, - LastSync = 3, - - SeqTask = 0, - NumSeqTasks = 1 - }; - CardTableModRefBS* _ct_bs; G1CollectorPolicy* _g1p; @@ -123,7 +113,6 @@ public: // Record, if necessary, the fact that *p (where "p" is in region "from", // which is required to be non-NULL) has changed to a new non-NULL value. - template void write_ref(HeapRegion* from, T* p); template void par_write_ref(HeapRegion* from, T* p, uint tid); // Requires "region_bm" and "card_bm" to be bitmaps with 1 bit per region diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.inline.hpp b/hotspot/src/share/vm/gc/g1/g1RemSet.inline.hpp index af8f2e96f16..f90c966e051 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.inline.hpp @@ -34,11 +34,6 @@ inline uint G1RemSet::n_workers() { return _g1->workers()->total_workers(); } -template -inline void G1RemSet::write_ref(HeapRegion* from, T* p) { - par_write_ref(from, p, 0); -} - template inline void G1RemSet::par_write_ref(HeapRegion* from, T* p, uint tid) { oop obj = oopDesc::load_decode_heap_oop(p); From bf9af24b553bc118b5980e77f0bcb41d23bcdeae Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Mon, 23 Nov 2015 12:44:43 -0800 Subject: [PATCH 063/260] 8140450: Implement JEP 259: Stack-Walking API Co-authored-by: Brent Christian Co-authored-by: Daniel Fuchs Co-authored-by: Hamlin Li Reviewed-by: coleenp, dfuchs, bchristi, psandoz, sspitsyn --- hotspot/make/share/makefiles/mapfile-vers | 4 + .../src/share/vm/classfile/javaClasses.cpp | 224 +++++++-- .../src/share/vm/classfile/javaClasses.hpp | 83 +++- .../share/vm/classfile/javaClasses.inline.hpp | 63 +++ .../share/vm/classfile/systemDictionary.hpp | 8 +- hotspot/src/share/vm/classfile/vmSymbols.hpp | 29 ++ hotspot/src/share/vm/memory/universe.cpp | 14 + hotspot/src/share/vm/memory/universe.hpp | 3 + hotspot/src/share/vm/prims/jvm.cpp | 89 ++++ hotspot/src/share/vm/prims/jvm.h | 31 ++ hotspot/src/share/vm/prims/stackwalk.cpp | 470 ++++++++++++++++++ hotspot/src/share/vm/prims/stackwalk.hpp | 102 ++++ hotspot/src/share/vm/runtime/globals.hpp | 6 + hotspot/src/share/vm/runtime/vframe.hpp | 12 +- 14 files changed, 1080 insertions(+), 58 deletions(-) create mode 100644 hotspot/src/share/vm/prims/stackwalk.cpp create mode 100644 hotspot/src/share/vm/prims/stackwalk.hpp diff --git a/hotspot/make/share/makefiles/mapfile-vers b/hotspot/make/share/makefiles/mapfile-vers index 7021e53d444..9672bfe3fc9 100644 --- a/hotspot/make/share/makefiles/mapfile-vers +++ b/hotspot/make/share/makefiles/mapfile-vers @@ -7,6 +7,7 @@ JVM_ActiveProcessorCount; JVM_ArrayCopy; JVM_AssertionStatusDirectives; + JVM_CallStackWalk; JVM_ClassDepth; JVM_ClassLoaderDepth; JVM_Clone; @@ -36,6 +37,7 @@ JVM_DumpAllStacks; JVM_DumpThreads; JVM_FillInStackTrace; + JVM_FillStackFrames; JVM_FindClassFromCaller; JVM_FindClassFromClass; JVM_FindClassFromBootLoader; @@ -133,6 +135,7 @@ JVM_MonitorNotify; JVM_MonitorNotifyAll; JVM_MonitorWait; + JVM_MoreStackWalk; JVM_NanoTime; JVM_NativePath; JVM_NewArray; @@ -150,6 +153,7 @@ JVM_SetClassSigners; JVM_SetNativeThreadName; JVM_SetPrimitiveArrayElement; + JVM_SetMethodInfo; JVM_SetThreadPriority; JVM_Sleep; JVM_StartThread; diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index a9f7c4616c6..242bafdfc53 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -1518,43 +1518,11 @@ void java_lang_Throwable::print(Handle throwable, outputStream* st) { // After this many redefines, the stack trace is unreliable. const int MAX_VERSION = USHRT_MAX; -// Helper backtrace functions to store bci|version together. -static inline int merge_bci_and_version(int bci, int version) { - // only store u2 for version, checking for overflow. - if (version > USHRT_MAX || version < 0) version = MAX_VERSION; - assert((jushort)bci == bci, "bci should be short"); - return build_int_from_shorts(version, bci); -} - -static inline int bci_at(unsigned int merged) { - return extract_high_short_from_int(merged); -} -static inline int version_at(unsigned int merged) { - return extract_low_short_from_int(merged); -} - static inline bool version_matches(Method* method, int version) { assert(version < MAX_VERSION, "version is too big"); return method != NULL && (method->constants()->version() == version); } -static inline int get_line_number(Method* method, int bci) { - int line_number = 0; - if (method->is_native()) { - // Negative value different from -1 below, enabling Java code in - // class java.lang.StackTraceElement to distinguish "native" from - // "no LineNumberTable". JDK tests for -2. - line_number = -2; - } else { - // Returns -1 if no LineNumberTable, and otherwise actual line number - line_number = method->line_number_from_bci(bci); - if (line_number == -1 && ShowHiddenFrames) { - line_number = bci + 1000000; - } - } - return line_number; -} - // This class provides a simple wrapper over the internal structure of // exception backtrace to insulate users of the backtrace from needing // to know what it looks like. @@ -1676,7 +1644,7 @@ class BacktraceBuilder: public StackObj { } _methods->short_at_put(_index, method->orig_method_idnum()); - _bcis->int_at_put(_index, merge_bci_and_version(bci, method->constants()->version())); + _bcis->int_at_put(_index, Backtrace::merge_bci_and_version(bci, method->constants()->version())); _cprefs->short_at_put(_index, method->name_index()); // We need to save the mirrors in the backtrace to keep the class @@ -1688,19 +1656,6 @@ class BacktraceBuilder: public StackObj { }; -Symbol* get_source_file_name(InstanceKlass* holder, int version) { - // Find the specific ik version that contains this source_file_name_index - // via the previous versions list, but use the current version's - // constant pool to look it up. The previous version's index has been - // merged for the current constant pool. - InstanceKlass* ik = holder->get_klass_version(version); - // This version has been cleaned up. - if (ik == NULL) return NULL; - int source_file_name_index = ik->source_file_name_index(); - return (source_file_name_index == 0) ? - (Symbol*)NULL : holder->constants()->symbol_at(source_file_name_index); -} - // Print stack trace element to resource allocated buffer char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, int method_id, int version, int bci, int cpref) { @@ -1718,7 +1673,7 @@ char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, buf_len += (int)strlen(method_name); char* source_file_name = NULL; - Symbol* source = get_source_file_name(holder, version); + Symbol* source = Backtrace::get_source_file_name(holder, version); if (source != NULL) { source_file_name = source->as_C_string(); buf_len += (int)strlen(source_file_name); @@ -1733,7 +1688,7 @@ char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, if (!version_matches(method, version)) { strcat(buf, "(Redefined)"); } else { - int line_number = get_line_number(method, bci); + int line_number = Backtrace::get_line_number(method, bci); if (line_number == -2) { strcat(buf, "(Native Method)"); } else { @@ -1802,8 +1757,8 @@ void java_lang_Throwable::print_stack_trace(oop throwable, outputStream* st) { // NULL mirror means end of stack trace if (mirror.is_null()) goto handle_cause; int method = methods->short_at(index); - int version = version_at(bcis->int_at(index)); - int bci = bci_at(bcis->int_at(index)); + int version = Backtrace::version_at(bcis->int_at(index)); + int bci = Backtrace::bci_at(bcis->int_at(index)); int cpref = cprefs->short_at(index); print_stack_element(st, mirror, method, version, bci, cpref); } @@ -2090,8 +2045,8 @@ oop java_lang_Throwable::get_stack_trace_element(oop throwable, int index, TRAPS assert(methods != NULL && bcis != NULL && mirrors != NULL, "sanity check"); int method = methods->short_at(chunk_index); - int version = version_at(bcis->int_at(chunk_index)); - int bci = bci_at(bcis->int_at(chunk_index)); + int version = Backtrace::version_at(bcis->int_at(chunk_index)); + int bci = Backtrace::bci_at(bcis->int_at(chunk_index)); int cpref = cprefs->short_at(chunk_index); Handle mirror(THREAD, mirrors->obj_at(chunk_index)); @@ -2114,6 +2069,7 @@ oop java_lang_StackTraceElement::create(Handle mirror, int method_id, } Handle element = ik->allocate_instance_handle(CHECK_0); + // Fill in class name ResourceMark rm(THREAD); InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); @@ -2136,13 +2092,13 @@ oop java_lang_StackTraceElement::create(Handle mirror, int method_id, java_lang_StackTraceElement::set_lineNumber(element(), -1); } else { // Fill in source file name and line number. - Symbol* source = get_source_file_name(holder, version); + Symbol* source = Backtrace::get_source_file_name(holder, version); if (ShowHiddenFrames && source == NULL) source = vmSymbols::unknown_class_name(); oop filename = StringTable::intern(source, CHECK_0); java_lang_StackTraceElement::set_fileName(element(), filename); - int line_number = get_line_number(method, bci); + int line_number = Backtrace::get_line_number(method, bci); java_lang_StackTraceElement::set_lineNumber(element(), line_number); } return element(); @@ -2155,6 +2111,108 @@ oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, TRA return create(mirror, method_id, method->constants()->version(), bci, cpref, THREAD); } +Method* java_lang_StackFrameInfo::get_method(Handle stackFrame, InstanceKlass* holder, TRAPS) { + if (MemberNameInStackFrame) { + Handle mname(THREAD, stackFrame->obj_field(_memberName_offset)); + Method* method = (Method*)java_lang_invoke_MemberName::vmtarget(mname()); + // we should expand MemberName::name when Throwable uses StackTrace + // MethodHandles::expand_MemberName(mname, MethodHandles::_suppress_defc|MethodHandles::_suppress_type, CHECK_NULL); + return method; + } else { + short mid = stackFrame->short_field(_mid_offset); + short version = stackFrame->short_field(_version_offset); + return holder->method_with_orig_idnum(mid, version); + } +} + +Symbol* java_lang_StackFrameInfo::get_file_name(Handle stackFrame, InstanceKlass* holder) { + if (MemberNameInStackFrame) { + return holder->source_file_name(); + } else { + short version = stackFrame->short_field(_version_offset); + return Backtrace::get_source_file_name(holder, version); + } +} + +void java_lang_StackFrameInfo::set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci) { + // set Method* or mid/cpref + if (MemberNameInStackFrame) { + oop mname = stackFrame->obj_field(_memberName_offset); + InstanceKlass* ik = method->method_holder(); + CallInfo info(method(), ik); + MethodHandles::init_method_MemberName(mname, info); + } else { + int mid = method->orig_method_idnum(); + int cpref = method->name_index(); + assert((jushort)mid == mid, "mid should be short"); + assert((jushort)cpref == cpref, "cpref should be short"); + java_lang_StackFrameInfo::set_mid(stackFrame(), (short)mid); + java_lang_StackFrameInfo::set_cpref(stackFrame(), (short)cpref); + } + // set bci + java_lang_StackFrameInfo::set_bci(stackFrame(), bci); + // method may be redefined; store the version + int version = method->constants()->version(); + assert((jushort)version == version, "version should be short"); + java_lang_StackFrameInfo::set_version(stackFrame(), (short)version); +} + +void java_lang_StackFrameInfo::fill_methodInfo(Handle stackFrame, TRAPS) { + ResourceMark rm(THREAD); + oop k = stackFrame->obj_field(_declaringClass_offset); + InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(k)); + Method* method = java_lang_StackFrameInfo::get_method(stackFrame, holder, CHECK); + int bci = stackFrame->int_field(_bci_offset); + + // The method can be NULL if the requested class version is gone + Symbol* sym = (method != NULL) ? method->name() : NULL; + if (MemberNameInStackFrame) { + assert(sym != NULL, "MemberName must have method name"); + } else { + // The method can be NULL if the requested class version is gone + if (sym == NULL) { + short cpref = stackFrame->short_field(_cpref_offset); + sym = holder->constants()->symbol_at(cpref); + } + } + + // set method name + oop methodname = StringTable::intern(sym, CHECK); + java_lang_StackFrameInfo::set_methodName(stackFrame(), methodname); + + // set file name and line number + Symbol* source = get_file_name(stackFrame, holder); + if (source != NULL) { + oop filename = StringTable::intern(source, CHECK); + java_lang_StackFrameInfo::set_fileName(stackFrame(), filename); + } + + // if the method has been redefined, the bci is no longer applicable + short version = stackFrame->short_field(_version_offset); + if (version_matches(method, version)) { + int line_number = Backtrace::get_line_number(method, bci); + java_lang_StackFrameInfo::set_lineNumber(stackFrame(), line_number); + } +} + +void java_lang_StackFrameInfo::compute_offsets() { + Klass* k = SystemDictionary::StackFrameInfo_klass(); + compute_offset(_declaringClass_offset, k, vmSymbols::declaringClass_name(), vmSymbols::class_signature()); + compute_offset(_memberName_offset, k, vmSymbols::memberName_name(), vmSymbols::object_signature()); + compute_offset(_bci_offset, k, vmSymbols::bci_name(), vmSymbols::int_signature()); + compute_offset(_methodName_offset, k, vmSymbols::methodName_name(), vmSymbols::string_signature()); + compute_offset(_fileName_offset, k, vmSymbols::fileName_name(), vmSymbols::string_signature()); + compute_offset(_lineNumber_offset, k, vmSymbols::lineNumber_name(), vmSymbols::int_signature()); + STACKFRAMEINFO_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); +} + +void java_lang_LiveStackFrameInfo::compute_offsets() { + Klass* k = SystemDictionary::LiveStackFrameInfo_klass(); + compute_offset(_monitors_offset, k, vmSymbols::monitors_name(), vmSymbols::object_array_signature()); + compute_offset(_locals_offset, k, vmSymbols::locals_name(), vmSymbols::object_array_signature()); + compute_offset(_operands_offset, k, vmSymbols::operands_name(), vmSymbols::object_array_signature()); +} + void java_lang_reflect_AccessibleObject::compute_offsets() { Klass* k = SystemDictionary::reflect_AccessibleObject_klass(); compute_offset(override_offset, k, vmSymbols::override_name(), vmSymbols::bool_signature()); @@ -3471,6 +3529,18 @@ int java_lang_StackTraceElement::declaringClass_offset; int java_lang_StackTraceElement::methodName_offset; int java_lang_StackTraceElement::fileName_offset; int java_lang_StackTraceElement::lineNumber_offset; +int java_lang_StackFrameInfo::_declaringClass_offset; +int java_lang_StackFrameInfo::_memberName_offset; +int java_lang_StackFrameInfo::_bci_offset; +int java_lang_StackFrameInfo::_methodName_offset; +int java_lang_StackFrameInfo::_fileName_offset; +int java_lang_StackFrameInfo::_lineNumber_offset; +int java_lang_StackFrameInfo::_mid_offset; +int java_lang_StackFrameInfo::_version_offset; +int java_lang_StackFrameInfo::_cpref_offset; +int java_lang_LiveStackFrameInfo::_monitors_offset; +int java_lang_LiveStackFrameInfo::_locals_offset; +int java_lang_LiveStackFrameInfo::_operands_offset; int java_lang_AssertionStatusDirectives::classes_offset; int java_lang_AssertionStatusDirectives::classEnabled_offset; int java_lang_AssertionStatusDirectives::packages_offset; @@ -3500,6 +3570,50 @@ void java_lang_StackTraceElement::set_lineNumber(oop element, int value) { element->int_field_put(lineNumber_offset, value); } +// Support for java_lang_StackFrameInfo +void java_lang_StackFrameInfo::set_declaringClass(oop element, oop value) { + element->obj_field_put(_declaringClass_offset, value); +} + +void java_lang_StackFrameInfo::set_mid(oop element, short value) { + element->short_field_put(_mid_offset, value); +} + +void java_lang_StackFrameInfo::set_version(oop element, short value) { + element->short_field_put(_version_offset, value); +} + +void java_lang_StackFrameInfo::set_cpref(oop element, short value) { + element->short_field_put(_cpref_offset, value); +} + +void java_lang_StackFrameInfo::set_bci(oop element, int value) { + element->int_field_put(_bci_offset, value); +} + +void java_lang_StackFrameInfo::set_fileName(oop element, oop value) { + element->obj_field_put(_fileName_offset, value); +} + +void java_lang_StackFrameInfo::set_methodName(oop element, oop value) { + element->obj_field_put(_methodName_offset, value); +} + +void java_lang_StackFrameInfo::set_lineNumber(oop element, int value) { + element->int_field_put(_lineNumber_offset, value); +} + +void java_lang_LiveStackFrameInfo::set_monitors(oop element, oop value) { + element->obj_field_put(_monitors_offset, value); +} + +void java_lang_LiveStackFrameInfo::set_locals(oop element, oop value) { + element->obj_field_put(_locals_offset, value); +} + +void java_lang_LiveStackFrameInfo::set_operands(oop element, oop value) { + element->obj_field_put(_operands_offset, value); +} // Support for java Assertions - java_lang_AssertionStatusDirectives. @@ -3633,6 +3747,8 @@ void JavaClasses::compute_offsets() { sun_reflect_ConstantPool::compute_offsets(); sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets(); java_lang_reflect_Parameter::compute_offsets(); + java_lang_StackFrameInfo::compute_offsets(); + java_lang_LiveStackFrameInfo::compute_offsets(); // generated interpreter code wants to know about the offsets we just computed: AbstractAssembler::update_delayed_values(); diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 403e33e9ee3..8e66cccf695 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -1359,6 +1359,85 @@ class java_lang_StackTraceElement: AllStatic { }; +class Backtrace: AllStatic { + public: + // Helper backtrace functions to store bci|version together. + static int merge_bci_and_version(int bci, int version); + static int merge_mid_and_cpref(int mid, int cpref); + static int bci_at(unsigned int merged); + static int version_at(unsigned int merged); + static int mid_at(unsigned int merged); + static int cpref_at(unsigned int merged); + static int get_line_number(const methodHandle& method, int bci); + static Symbol* get_source_file_name(InstanceKlass* holder, int version); + + // Debugging + friend class JavaClasses; +}; + +// Interface to java.lang.StackFrameInfo objects + +#define STACKFRAMEINFO_INJECTED_FIELDS(macro) \ + macro(java_lang_StackFrameInfo, mid, short_signature, false) \ + macro(java_lang_StackFrameInfo, version, short_signature, false) \ + macro(java_lang_StackFrameInfo, cpref, short_signature, false) + +class java_lang_StackFrameInfo: AllStatic { +private: + static int _declaringClass_offset; + static int _memberName_offset; + static int _bci_offset; + static int _methodName_offset; + static int _fileName_offset; + static int _lineNumber_offset; + + static int _mid_offset; + static int _version_offset; + static int _cpref_offset; + + static Method* get_method(Handle stackFrame, InstanceKlass* holder, TRAPS); + static Symbol* get_file_name(Handle stackFrame, InstanceKlass* holder); + +public: + // Setters + static void set_declaringClass(oop info, oop value); + static void set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci); + static void set_bci(oop info, int value); + + // set method info in an instance of StackFrameInfo + static void fill_methodInfo(Handle info, TRAPS); + static void set_methodName(oop info, oop value); + static void set_fileName(oop info, oop value); + static void set_lineNumber(oop info, int value); + + // these injected fields are only used if -XX:-MemberNameInStackFrame set + static void set_mid(oop info, short value); + static void set_version(oop info, short value); + static void set_cpref(oop info, short value); + + static void compute_offsets(); + + // Debugging + friend class JavaClasses; +}; + +class java_lang_LiveStackFrameInfo: AllStatic { + private: + static int _monitors_offset; + static int _locals_offset; + static int _operands_offset; + + public: + static void set_monitors(oop info, oop value); + static void set_locals(oop info, oop value); + static void set_operands(oop info, oop value); + + static void compute_offsets(); + + // Debugging + friend class JavaClasses; +}; + // Interface to java.lang.AssertionStatusDirectives objects class java_lang_AssertionStatusDirectives: AllStatic { @@ -1442,7 +1521,9 @@ class InjectedField { CLASS_INJECTED_FIELDS(macro) \ CLASSLOADER_INJECTED_FIELDS(macro) \ MEMBERNAME_INJECTED_FIELDS(macro) \ - CALLSITECONTEXT_INJECTED_FIELDS(macro) + CALLSITECONTEXT_INJECTED_FIELDS(macro) \ + STACKFRAMEINFO_INJECTED_FIELDS(macro) + // Interface to hard-coded offset checking diff --git a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp index 723c2e86757..ac35ccb8439 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp @@ -73,4 +73,67 @@ inline bool java_lang_invoke_DirectMethodHandle::is_instance(oop obj) { return obj != NULL && is_subclass(obj->klass()); } +inline int Backtrace::merge_bci_and_version(int bci, int version) { + // only store u2 for version, checking for overflow. + if (version > USHRT_MAX || version < 0) version = USHRT_MAX; + assert((jushort)bci == bci, "bci should be short"); + return build_int_from_shorts(version, bci); +} + +inline int Backtrace::merge_mid_and_cpref(int mid, int cpref) { + // only store u2 for mid and cpref, checking for overflow. + assert((jushort)mid == mid, "mid should be short"); + assert((jushort)cpref == cpref, "cpref should be short"); + return build_int_from_shorts(cpref, mid); +} + +inline int Backtrace::bci_at(unsigned int merged) { + return extract_high_short_from_int(merged); +} + +inline int Backtrace::version_at(unsigned int merged) { + return extract_low_short_from_int(merged); +} + +inline int Backtrace::mid_at(unsigned int merged) { + return extract_high_short_from_int(merged); +} + +inline int Backtrace::cpref_at(unsigned int merged) { + return extract_low_short_from_int(merged); +} + +inline int Backtrace::get_line_number(const methodHandle& method, int bci) { + int line_number = 0; + if (method->is_native()) { + // Negative value different from -1 below, enabling Java code in + // class java.lang.StackTraceElement to distinguish "native" from + // "no LineNumberTable". JDK tests for -2. + line_number = -2; + } else { + // Returns -1 if no LineNumberTable, and otherwise actual line number + line_number = method->line_number_from_bci(bci); + if (line_number == -1 && ShowHiddenFrames) { + line_number = bci + 1000000; + } + } + return line_number; +} + +/* + * Returns the source file name of a given InstanceKlass and version + */ +inline Symbol* Backtrace::get_source_file_name(InstanceKlass* holder, int version) { + // Find the specific ik version that contains this source_file_name_index + // via the previous versions list, but use the current version's + // constant pool to look it up. The previous version's index has been + // merged for the current constant pool. + InstanceKlass* ik = holder->get_klass_version(version); + // This version has been cleaned up. + if (ik == NULL) return NULL; + int source_file_name_index = ik->source_file_name_index(); + return (source_file_name_index == 0) ? + (Symbol*)NULL : holder->constants()->symbol_at(source_file_name_index); +} + #endif // SHARE_VM_CLASSFILE_JAVACLASSES_INLINE_HPP diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index b9491903cfd..56da06d00aa 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -179,11 +179,17 @@ class Ticks; do_klass(sun_misc_Launcher_klass, sun_misc_Launcher, Pre ) \ do_klass(CodeSource_klass, java_security_CodeSource, Pre ) \ \ - /* It's NULL in non-1.4 JDKs. */ \ do_klass(StackTraceElement_klass, java_lang_StackTraceElement, Opt ) \ + \ /* It's okay if this turns out to be NULL in non-1.4 JDKs. */ \ do_klass(nio_Buffer_klass, java_nio_Buffer, Opt ) \ \ + /* Stack Walking */ \ + do_klass(StackWalker_klass, java_lang_StackWalker, Opt ) \ + do_klass(AbstractStackWalker_klass, java_lang_StackStreamFactory_AbstractStackWalker, Opt ) \ + do_klass(StackFrameInfo_klass, java_lang_StackFrameInfo, Opt ) \ + do_klass(LiveStackFrameInfo_klass, java_lang_LiveStackFrameInfo, Opt ) \ + \ /* Preload boxing klasses */ \ do_klass(Boolean_klass, java_lang_Boolean, Pre ) \ do_klass(Character_klass, java_lang_Character, Pre ) \ diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index f98f400064d..ca3acadf87e 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -310,6 +310,22 @@ /* Support for JVMCI */ \ JVMCI_VM_SYMBOLS_DO(template, do_alias) \ \ + template(java_lang_StackWalker, "java/lang/StackWalker") \ + template(java_lang_StackFrameInfo, "java/lang/StackFrameInfo") \ + template(java_lang_LiveStackFrameInfo, "java/lang/LiveStackFrameInfo") \ + template(java_lang_StackStreamFactory_AbstractStackWalker, "java/lang/StackStreamFactory$AbstractStackWalker") \ + template(doStackWalk_name, "doStackWalk") \ + template(doStackWalk_signature, "(JIIII)Ljava/lang/Object;") \ + template(asPrimitive_name, "asPrimitive") \ + template(asPrimitive_int_signature, "(I)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + template(asPrimitive_long_signature, "(J)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + template(asPrimitive_short_signature, "(S)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + template(asPrimitive_byte_signature, "(B)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + template(asPrimitive_char_signature, "(C)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + template(asPrimitive_float_signature, "(F)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + template(asPrimitive_double_signature, "(D)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + template(asPrimitive_boolean_signature, "(Z)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + \ /* common method and field names */ \ template(object_initializer_name, "") \ template(class_initializer_name, "") \ @@ -410,6 +426,18 @@ template(append_name, "append") \ template(klass_name, "klass") \ template(array_klass_name, "array_klass") \ + template(declaringClass_name, "declaringClass") \ + template(memberName_name, "memberName") \ + template(mid_name, "mid") \ + template(cpref_name, "cpref") \ + template(version_name, "version") \ + template(bci_name, "bci") \ + template(methodName_name, "methodName") \ + template(fileName_name, "fileName") \ + template(lineNumber_name, "lineNumber") \ + template(monitors_name, "monitors") \ + template(locals_name, "locals") \ + template(operands_name, "operands") \ template(oop_size_name, "oop_size") \ template(static_oop_field_count_name, "static_oop_field_count") \ template(protection_domain_name, "protection_domain") \ @@ -514,6 +542,7 @@ template(class_array_signature, "[Ljava/lang/Class;") \ template(classloader_signature, "Ljava/lang/ClassLoader;") \ template(object_signature, "Ljava/lang/Object;") \ + template(object_array_signature, "[Ljava/lang/Object;") \ template(class_signature, "Ljava/lang/Class;") \ template(string_signature, "Ljava/lang/String;") \ template(reference_signature, "Ljava/lang/ref/Reference;") \ diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index 7ec9cfa3a99..d06a7fbddc3 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -115,6 +115,7 @@ LatestMethodCache* Universe::_finalizer_register_cache = NULL; LatestMethodCache* Universe::_loader_addClass_cache = NULL; LatestMethodCache* Universe::_pd_implies_cache = NULL; LatestMethodCache* Universe::_throw_illegal_access_error_cache = NULL; +LatestMethodCache* Universe::_do_stack_walk_cache = NULL; oop Universe::_out_of_memory_error_java_heap = NULL; oop Universe::_out_of_memory_error_metaspace = NULL; oop Universe::_out_of_memory_error_class_metaspace = NULL; @@ -240,6 +241,7 @@ void Universe::serialize(SerializeClosure* f, bool do_all) { _loader_addClass_cache->serialize(f); _pd_implies_cache->serialize(f); _throw_illegal_access_error_cache->serialize(f); + _do_stack_walk_cache->serialize(f); } void Universe::check_alignment(uintx size, uintx alignment, const char* name) { @@ -674,6 +676,7 @@ jint universe_init() { Universe::_loader_addClass_cache = new LatestMethodCache(); Universe::_pd_implies_cache = new LatestMethodCache(); Universe::_throw_illegal_access_error_cache = new LatestMethodCache(); + Universe::_do_stack_walk_cache = new LatestMethodCache(); if (UseSharedSpaces) { // Read the data structures supporting the shared spaces (shared @@ -1048,6 +1051,17 @@ bool universe_post_init() { SystemDictionary::ProtectionDomain_klass(), m); } + // Setup method for stack walking + InstanceKlass::cast(SystemDictionary::AbstractStackWalker_klass())->link_class(CHECK_false); + m = InstanceKlass::cast(SystemDictionary::AbstractStackWalker_klass())-> + find_method(vmSymbols::doStackWalk_name(), + vmSymbols::doStackWalk_signature()); + // Allow NULL which should only happen with bootstrapping. + if (m != NULL) { + Universe::_do_stack_walk_cache->init( + SystemDictionary::AbstractStackWalker_klass(), m); + } + // This needs to be done before the first scavenge/gc, since // it's an input to soft ref clearing policy. { diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index 854a818883c..f2dc42e6cfe 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -149,6 +149,7 @@ class Universe: AllStatic { static LatestMethodCache* _loader_addClass_cache; // method for registering loaded classes in class loader vector static LatestMethodCache* _pd_implies_cache; // method for checking protection domain attributes static LatestMethodCache* _throw_illegal_access_error_cache; // Unsafe.throwIllegalAccessError() method + static LatestMethodCache* _do_stack_walk_cache; // method for stack walker callback // preallocated error objects (no backtrace) static oop _out_of_memory_error_java_heap; @@ -314,6 +315,8 @@ class Universe: AllStatic { static Method* protection_domain_implies_method() { return _pd_implies_cache->get_method(); } static Method* throw_illegal_access_error() { return _throw_illegal_access_error_cache->get_method(); } + static Method* do_stack_walk_method() { return _do_stack_walk_cache->get_method(); } + static oop null_ptr_exception_instance() { return _null_ptr_exception_instance; } static oop arithmetic_exception_instance() { return _arithmetic_exception_instance; } static oop virtual_machine_error_instance() { return _virtual_machine_error_instance; } diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 45db3542ec2..f6442b98574 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -46,6 +46,7 @@ #include "prims/jvmtiThreadState.hpp" #include "prims/nativeLookup.hpp" #include "prims/privilegedStack.hpp" +#include "prims/stackwalk.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/handles.inline.hpp" @@ -547,6 +548,94 @@ JVM_ENTRY(jobject, JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint JVM_END +// java.lang.StackWalker ////////////////////////////////////////////////////// + + +JVM_ENTRY(jobject, JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode, + jint skip_frames, jint frame_count, jint start_index, + jobjectArray classes, + jobjectArray frames)) + JVMWrapper("JVM_CallStackWalk"); + JavaThread* jt = (JavaThread*) THREAD; + if (!jt->is_Java_thread() || !jt->has_last_Java_frame()) { + THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: no stack trace", NULL); + } + + Handle stackStream_h(THREAD, JNIHandles::resolve_non_null(stackStream)); + objArrayOop ca = objArrayOop(JNIHandles::resolve_non_null(classes)); + objArrayHandle classes_array_h(THREAD, ca); + + // frames array is null when only getting caller reference + objArrayOop fa = objArrayOop(JNIHandles::resolve(frames)); + objArrayHandle frames_array_h(THREAD, fa); + + int limit = start_index + frame_count; + if (classes_array_h->length() < limit) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers", NULL); + } + + Handle result = StackWalk::walk(stackStream_h, mode, skip_frames, frame_count, + start_index, classes_array_h, + frames_array_h, CHECK_NULL); + return JNIHandles::make_local(env, result()); +JVM_END + + +JVM_ENTRY(jint, JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor, + jint frame_count, jint start_index, + jobjectArray classes, + jobjectArray frames)) + JVMWrapper("JVM_MoreStackWalk"); + JavaThread* jt = (JavaThread*) THREAD; + objArrayOop ca = objArrayOop(JNIHandles::resolve_non_null(classes)); + objArrayHandle classes_array_h(THREAD, ca); + + // frames array is null when only getting caller reference + objArrayOop fa = objArrayOop(JNIHandles::resolve(frames)); + objArrayHandle frames_array_h(THREAD, fa); + + int limit = start_index+frame_count; + if (classes_array_h->length() < limit) { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers"); + } + + Handle stackStream_h(THREAD, JNIHandles::resolve_non_null(stackStream)); + return StackWalk::moreFrames(stackStream_h, mode, anchor, frame_count, + start_index, classes_array_h, + frames_array_h, THREAD); +JVM_END + +JVM_ENTRY(void, JVM_FillStackFrames(JNIEnv *env, jclass stackStream, + jint start_index, + jobjectArray frames, + jint from_index, jint to_index)) + JVMWrapper("JVM_FillStackFrames"); + if (TraceStackWalk) { + tty->print("JVM_FillStackFrames() start_index=%d from_index=%d to_index=%d\n", + start_index, from_index, to_index); + } + + JavaThread* jt = (JavaThread*) THREAD; + + objArrayOop fa = objArrayOop(JNIHandles::resolve_non_null(frames)); + objArrayHandle frames_array_h(THREAD, fa); + + if (frames_array_h->length() < to_index) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "array length not matched"); + } + + for (int i = from_index; i < to_index; i++) { + Handle stackFrame(THREAD, frames_array_h->obj_at(i)); + java_lang_StackFrameInfo::fill_methodInfo(stackFrame, CHECK); + } +JVM_END + +JVM_ENTRY(void, JVM_SetMethodInfo(JNIEnv *env, jobject frame)) + JVMWrapper("JVM_SetMethodInfo"); + Handle stackFrame(THREAD, JNIHandles::resolve(frame)); + java_lang_StackFrameInfo::fill_methodInfo(stackFrame, THREAD); +JVM_END + // java.lang.Object /////////////////////////////////////////////// diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index bc42dbf3edb..021f55dccb3 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -200,6 +200,37 @@ JVM_GetStackTraceDepth(JNIEnv *env, jobject throwable); JNIEXPORT jobject JNICALL JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint index); +/* + * java.lang.StackWalker + */ +enum { + JVM_STACKWALK_FILL_CLASS_REFS_ONLY = 0x2, + JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE = 0x10, + JVM_STACKWALK_SHOW_HIDDEN_FRAMES = 0x20, + JVM_STACKWALK_FILL_LIVE_STACK_FRAMES = 0x100 +}; + +JNIEXPORT jobject JNICALL +JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode, + jint skip_frames, jint frame_count, jint start_index, + jobjectArray classes, + jobjectArray frames); + +JNIEXPORT jint JNICALL +JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor, + jint frame_count, jint start_index, + jobjectArray classes, + jobjectArray frames); + +JNIEXPORT void JNICALL +JVM_FillStackFrames(JNIEnv* env, jclass cls, + jint start_index, + jobjectArray frames, + jint from_index, jint toIndex); + +JNIEXPORT void JNICALL +JVM_SetMethodInfo(JNIEnv* env, jobject frame); + /* * java.lang.Thread */ diff --git a/hotspot/src/share/vm/prims/stackwalk.cpp b/hotspot/src/share/vm/prims/stackwalk.cpp new file mode 100644 index 00000000000..3e292641a79 --- /dev/null +++ b/hotspot/src/share/vm/prims/stackwalk.cpp @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/javaClasses.hpp" +#include "classfile/javaClasses.inline.hpp" +#include "classfile/vmSymbols.hpp" +#include "memory/oopFactory.hpp" +#include "oops/oop.inline.hpp" +#include "oops/objArrayOop.inline.hpp" +#include "prims/stackwalk.hpp" +#include "runtime/globals.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/vframe.hpp" +#include "utilities/globalDefinitions.hpp" + +// setup and cleanup actions +void StackWalkAnchor::setup_magic_on_entry(objArrayHandle classes_array) { + classes_array->obj_at_put(magic_pos, _thread->threadObj()); + _anchor = address_value(); + assert(check_magic(classes_array), "invalid magic"); +} + +bool StackWalkAnchor::check_magic(objArrayHandle classes_array) { + oop m1 = classes_array->obj_at(magic_pos); + jlong m2 = _anchor; + if (m1 == _thread->threadObj() && m2 == address_value()) return true; + return false; +} + +bool StackWalkAnchor::cleanup_magic_on_exit(objArrayHandle classes_array) { + bool ok = check_magic(classes_array); + classes_array->obj_at_put(magic_pos, NULL); + _anchor = 0L; + return ok; +} + +// Returns StackWalkAnchor for the current stack being traversed. +// +// Parameters: +// thread Current Java thread. +// magic Magic value used for each stack walking +// classes_array User-supplied buffers. The 0th element is reserved +// to this StackWalkAnchor to use +// +StackWalkAnchor* StackWalkAnchor::from_current(JavaThread* thread, jlong magic, + objArrayHandle classes_array) +{ + assert(thread != NULL && thread->is_Java_thread(), ""); + oop m1 = classes_array->obj_at(magic_pos); + if (m1 != thread->threadObj()) return NULL; + if (magic == 0L) return NULL; + StackWalkAnchor* anchor = (StackWalkAnchor*) (intptr_t) magic; + if (!anchor->is_valid_in(thread, classes_array)) return NULL; + return anchor; +} + +// Unpacks one or more frames into user-supplied buffers. +// Updates the end index, and returns the number of unpacked frames. +// Always start with the existing vfst.method and bci. +// Do not call vfst.next to advance over the last returned value. +// In other words, do not leave any stale data in the vfst. +// +// Parameters: +// mode Restrict which frames to be decoded. +// vfst vFrameStream. +// max_nframes Maximum number of frames to be filled. +// start_index Start index to the user-supplied buffers. +// classes_array Buffer to store classes in, starting at start_index. +// frames_array Buffer to store StackFrame in, starting at start_index. +// NULL if not used. +// end_index End index to the user-supplied buffers with unpacked frames. +// +// Returns the number of frames whose information was transferred into the buffers. +// +int StackWalk::fill_in_frames(jlong mode, vframeStream& vfst, + int max_nframes, int start_index, + objArrayHandle classes_array, + objArrayHandle frames_array, + int& end_index, TRAPS) { + if (TraceStackWalk) { + tty->print_cr("fill_in_frames limit=%d start=%d frames length=%d", + max_nframes, start_index, classes_array->length()); + } + assert(max_nframes > 0, "invalid max_nframes"); + assert(start_index + max_nframes <= classes_array->length(), "oob"); + + int frames_decoded = 0; + for (; !vfst.at_end(); vfst.next()) { + Method* method = vfst.method(); + int bci = vfst.bci(); + + if (method == NULL) continue; + if (!ShowHiddenFrames && StackWalk::skip_hidden_frames(mode)) { + if (method->is_hidden()) { + if (TraceStackWalk) { + tty->print(" hidden method: "); method->print_short_name(); + tty->print("\n"); + } + continue; + } + } + + int index = end_index++; + if (TraceStackWalk) { + tty->print(" %d: frame method: ", index); method->print_short_name(); + tty->print_cr(" bci=%d", bci); + } + + classes_array->obj_at_put(index, method->method_holder()->java_mirror()); + // fill in StackFrameInfo and initialize MemberName + if (live_frame_info(mode)) { + Handle stackFrame(frames_array->obj_at(index)); + fill_live_stackframe(stackFrame, method, bci, vfst.java_frame(), CHECK_0); + } else if (need_method_info(mode)) { + Handle stackFrame(frames_array->obj_at(index)); + fill_stackframe(stackFrame, method, bci); + } + if (++frames_decoded >= max_nframes) break; + } + return frames_decoded; +} + +static oop create_primitive_value_instance(StackValueCollection* values, int i, TRAPS) { + Klass* k = SystemDictionary::resolve_or_null(vmSymbols::java_lang_LiveStackFrameInfo(), CHECK_NULL); + instanceKlassHandle ik (THREAD, k); + + JavaValue result(T_OBJECT); + JavaCallArguments args; + Symbol* signature = NULL; + + // ## TODO: type is only available in LocalVariable table, if present. + // ## StackValue type is T_INT or T_OBJECT. + switch (values->at(i)->type()) { + case T_INT: + args.push_int(values->int_at(i)); + signature = vmSymbols::asPrimitive_int_signature(); + break; + + case T_LONG: + args.push_long(values->long_at(i)); + signature = vmSymbols::asPrimitive_long_signature(); + break; + + case T_FLOAT: + args.push_float(values->float_at(i)); + signature = vmSymbols::asPrimitive_float_signature(); + break; + + case T_DOUBLE: + args.push_double(values->double_at(i)); + signature = vmSymbols::asPrimitive_double_signature(); + break; + + case T_BYTE: + args.push_int(values->int_at(i)); + signature = vmSymbols::asPrimitive_byte_signature(); + break; + + case T_SHORT: + args.push_int(values->int_at(i)); + signature = vmSymbols::asPrimitive_short_signature(); + break; + + case T_CHAR: + args.push_int(values->int_at(i)); + signature = vmSymbols::asPrimitive_char_signature(); + break; + + case T_BOOLEAN: + args.push_int(values->int_at(i)); + signature = vmSymbols::asPrimitive_boolean_signature(); + break; + + case T_OBJECT: + return values->obj_at(i)(); + + case T_CONFLICT: + // put a non-null slot + args.push_int(0); + signature = vmSymbols::asPrimitive_int_signature(); + break; + + default: ShouldNotReachHere(); + } + JavaCalls::call_static(&result, + ik, + vmSymbols::asPrimitive_name(), + signature, + &args, + CHECK_NULL); + return (instanceOop) result.get_jobject(); +} + +static objArrayHandle values_to_object_array(StackValueCollection* values, TRAPS) { + objArrayHandle empty; + int length = values->size(); + objArrayOop array_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), + length, CHECK_(empty)); + objArrayHandle array_h(THREAD, array_oop); + for (int i = 0; i < values->size(); i++) { + StackValue* st = values->at(i); + oop obj = create_primitive_value_instance(values, i, CHECK_(empty)); + if (obj != NULL) + array_h->obj_at_put(i, obj); + } + return array_h; +} + +static objArrayHandle monitors_to_object_array(GrowableArray* monitors, TRAPS) { + int length = monitors->length(); + objArrayOop array_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), + length, CHECK_(objArrayHandle())); + objArrayHandle array_h(THREAD, array_oop); + for (int i = 0; i < length; i++) { + MonitorInfo* monitor = monitors->at(i); + array_h->obj_at_put(i, monitor->owner()); + } + return array_h; +} + +// Fill StackFrameInfo with declaringClass and bci and initialize memberName +void StackWalk::fill_stackframe(Handle stackFrame, const methodHandle& method, int bci) { + java_lang_StackFrameInfo::set_declaringClass(stackFrame(), method->method_holder()->java_mirror()); + java_lang_StackFrameInfo::set_method_and_bci(stackFrame(), method, bci); +} + +// Fill LiveStackFrameInfo with locals, monitors, and expressions +void StackWalk::fill_live_stackframe(Handle stackFrame, const methodHandle& method, + int bci, javaVFrame* jvf, TRAPS) { + fill_stackframe(stackFrame, method, bci); + if (jvf != NULL) { + StackValueCollection* locals = jvf->locals(); + StackValueCollection* expressions = jvf->expressions(); + GrowableArray* monitors = jvf->monitors(); + + if (!locals->is_empty()) { + objArrayHandle locals_h = values_to_object_array(locals, CHECK); + java_lang_LiveStackFrameInfo::set_locals(stackFrame(), locals_h()); + } + if (!expressions->is_empty()) { + objArrayHandle expressions_h = values_to_object_array(expressions, CHECK); + java_lang_LiveStackFrameInfo::set_operands(stackFrame(), expressions_h()); + } + if (monitors->length() > 0) { + objArrayHandle monitors_h = monitors_to_object_array(monitors, CHECK); + java_lang_LiveStackFrameInfo::set_monitors(stackFrame(), monitors_h()); + } + } +} + +// Begins stack walking. +// +// Parameters: +// stackStream StackStream object +// mode Stack walking mode. +// skip_frames Number of frames to be skipped. +// frame_count Number of frames to be traversed. +// start_index Start index to the user-supplied buffers. +// classes_array Buffer to store classes in, starting at start_index. +// frames_array Buffer to store StackFrame in, starting at start_index. +// NULL if not used. +// +// Returns Object returned from AbstractStackWalker::doStackWalk call. +// +oop StackWalk::walk(Handle stackStream, jlong mode, + int skip_frames, int frame_count, int start_index, + objArrayHandle classes_array, + objArrayHandle frames_array, + TRAPS) { + JavaThread* jt = (JavaThread*)THREAD; + if (TraceStackWalk) { + tty->print_cr("Start walking: mode " JLONG_FORMAT " skip %d frames batch size %d", + mode, skip_frames, frame_count); + } + + if (need_method_info(mode)) { + if (frames_array.is_null()) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", NULL); + } + } + + Klass* stackWalker_klass = SystemDictionary::StackWalker_klass(); + Klass* abstractStackWalker_klass = SystemDictionary::AbstractStackWalker_klass(); + + methodHandle m_doStackWalk(THREAD, Universe::do_stack_walk_method()); + + // Open up a traversable stream onto my stack. + // This stream will be made available by *reference* to the inner Java call. + StackWalkAnchor anchor(jt); + vframeStream& vfst = anchor.vframe_stream(); + + { + // Skip all methods from AbstractStackWalker and StackWalk (enclosing method) + if (!fill_in_stacktrace(mode)) { + while (!vfst.at_end()) { + InstanceKlass* ik = vfst.method()->method_holder(); + if (ik != stackWalker_klass && + ik != abstractStackWalker_klass && ik->super() != abstractStackWalker_klass) { + break; + } + + if (TraceStackWalk) { + tty->print(" skip "); vfst.method()->print_short_name(); tty->print("\n"); + } + vfst.next(); + } + } + + // For exceptions, skip Throwable::fillInStackTrace and methods + // of the exception class and superclasses + if (fill_in_stacktrace(mode)) { + bool skip_to_fillInStackTrace = false; + bool skip_throwableInit_check = false; + while (!vfst.at_end() && !skip_throwableInit_check) { + InstanceKlass* ik = vfst.method()->method_holder(); + Method* method = vfst.method(); + if (!skip_to_fillInStackTrace) { + if (ik == SystemDictionary::Throwable_klass() && + method->name() == vmSymbols::fillInStackTrace_name()) { + // this frame will be skipped + skip_to_fillInStackTrace = true; + } + } else if (!(ik->is_subclass_of(SystemDictionary::Throwable_klass()) && + method->name() == vmSymbols::object_initializer_name())) { + // there are none or we've seen them all - either way stop checking + skip_throwableInit_check = true; + break; + } + + if (TraceStackWalk) { + tty->print("stack walk: skip "); vfst.method()->print_short_name(); tty->print("\n"); + } + vfst.next(); + } + } + + // stack frame has been traversed individually and resume stack walk + // from the stack frame at depth == skip_frames. + for (int n=0; n < skip_frames && !vfst.at_end(); vfst.next(), n++) { + if (TraceStackWalk) { + tty->print(" skip "); vfst.method()->print_short_name(); + tty->print_cr(" frame id: " PTR_FORMAT " pc: " PTR_FORMAT, + p2i(vfst.frame_id()), p2i(vfst.frame_pc())); + } + } + } + + // The Method* pointer in the vfst has a very short shelf life. Grab it now. + int end_index = start_index; + int numFrames = 0; + if (!vfst.at_end()) { + numFrames = fill_in_frames(mode, vfst, frame_count, start_index, classes_array, + frames_array, end_index, CHECK_NULL); + if (numFrames < 1) { + THROW_MSG_(vmSymbols::java_lang_InternalError(), "stack walk: decode failed", NULL); + } + } + + // JVM_CallStackWalk walks the stack and fills in stack frames, then calls to + // Java method java.lang.StackStreamFactory.AbstractStackWalker::doStackWalk + // which calls the implementation to consume the stack frames. + // When JVM_CallStackWalk returns, it invalidates the stack stream. + JavaValue result(T_OBJECT); + JavaCallArguments args(stackStream); + args.push_long(anchor.address_value()); + args.push_int(skip_frames); + args.push_int(frame_count); + args.push_int(start_index); + args.push_int(end_index); + + // Link the thread and vframe stream into the callee-visible object + anchor.setup_magic_on_entry(classes_array); + + JavaCalls::call(&result, m_doStackWalk, &args, THREAD); + + // Do this before anything else happens, to disable any lingering stream objects + bool ok = anchor.cleanup_magic_on_exit(classes_array); + + // Throw pending exception if we must + (void) (CHECK_NULL); + + if (!ok) { + THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers on exit", NULL); + } + + // Return normally + return (oop)result.get_jobject(); + +} + +// Walk the next batch of stack frames +// +// Parameters: +// stackStream StackStream object +// mode Stack walking mode. +// magic Must be valid value to continue the stack walk +// frame_count Number of frames to be decoded. +// start_index Start index to the user-supplied buffers. +// classes_array Buffer to store classes in, starting at start_index. +// frames_array Buffer to store StackFrame in, starting at start_index. +// NULL if not used. +// +// Returns the end index of frame filled in the buffer. +// +jint StackWalk::moreFrames(Handle stackStream, jlong mode, jlong magic, + int frame_count, int start_index, + objArrayHandle classes_array, + objArrayHandle frames_array, + TRAPS) +{ + JavaThread* jt = (JavaThread*)THREAD; + StackWalkAnchor* existing_anchor = StackWalkAnchor::from_current(jt, magic, classes_array); + if (existing_anchor == NULL) { + THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers", 0L); + } + + if ((need_method_info(mode) || live_frame_info(mode)) && frames_array.is_null()) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", 0L); + } + + if (TraceStackWalk) { + tty->print_cr("StackWalk::moreFrames frame_count %d existing_anchor " PTR_FORMAT " start %d frames %d", + frame_count, p2i(existing_anchor), start_index, classes_array->length()); + } + int end_index = start_index; + if (frame_count <= 0) { + return end_index; // No operation. + } + + int count = frame_count + start_index; + assert (classes_array->length() >= count, "not enough space in buffers"); + + StackWalkAnchor& anchor = (*existing_anchor); + vframeStream& vfst = anchor.vframe_stream(); + if (!vfst.at_end()) { + vfst.next(); // this was the last frame decoded in the previous batch + if (!vfst.at_end()) { + int n = fill_in_frames(mode, vfst, frame_count, start_index, classes_array, + frames_array, end_index, CHECK_0); + if (n < 1) { + THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: later decode failed", 0L); + } + return end_index; + } + } + return end_index; +} diff --git a/hotspot/src/share/vm/prims/stackwalk.hpp b/hotspot/src/share/vm/prims/stackwalk.hpp new file mode 100644 index 00000000000..1fa906815be --- /dev/null +++ b/hotspot/src/share/vm/prims/stackwalk.hpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + + +#ifndef SHARE_VM_PRIMS_STACKWALK_HPP +#define SHARE_VM_PRIMS_STACKWALK_HPP + +#include "oops/oop.hpp" +#include "runtime/vframe.hpp" + +class StackWalkAnchor : public StackObj { +private: + enum { + magic_pos = 0 + }; + + JavaThread* _thread; + vframeStream _vfst; + jlong _anchor; +public: + StackWalkAnchor(JavaThread* thread) + : _thread(thread), _vfst(thread), _anchor(0L) {} + + vframeStream& vframe_stream() { return _vfst; } + JavaThread* thread() { return _thread; } + + void setup_magic_on_entry(objArrayHandle classes_array); + bool check_magic(objArrayHandle classes_array); + bool cleanup_magic_on_exit(objArrayHandle classes_array); + + bool is_valid_in(Thread* thread, objArrayHandle classes_array) { + return (_thread == thread && check_magic(classes_array)); + } + + jlong address_value() { + return (jlong) castable_address(this); + } + + static StackWalkAnchor* from_current(JavaThread* thread, jlong anchor, objArrayHandle frames_array); +}; + +class StackWalk : public AllStatic { +private: + static int fill_in_frames(jlong mode, vframeStream& vfst, + int max_nframes, int start_index, + objArrayHandle classes_array, + objArrayHandle frames_array, + int& end_index, TRAPS); + + static void fill_stackframe(Handle stackFrame, const methodHandle& method, int bci); + + static void fill_live_stackframe(Handle stackFrame, const methodHandle& method, int bci, + javaVFrame* jvf, TRAPS); + + static inline bool skip_hidden_frames(int mode) { + return (mode & JVM_STACKWALK_SHOW_HIDDEN_FRAMES) == 0; + } + static inline bool need_method_info(int mode) { + return (mode & JVM_STACKWALK_FILL_CLASS_REFS_ONLY) == 0; + } + static inline bool live_frame_info(int mode) { + return (mode & JVM_STACKWALK_FILL_LIVE_STACK_FRAMES) != 0; + } + static inline bool fill_in_stacktrace(int mode) { + return (mode & JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE) != 0; + } + +public: + static oop walk(Handle stackStream, jlong mode, + int skip_frames, int frame_count, int start_index, + objArrayHandle classes_array, + objArrayHandle frames_array, + TRAPS); + + static jint moreFrames(Handle stackStream, jlong mode, jlong magic, + int frame_count, int start_index, + objArrayHandle classes_array, + objArrayHandle frames_array, + TRAPS); +}; +#endif // SHARE_VM_PRIMS_STACKWALK_HPP diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 9724ebdd6d4..7359bb563a9 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3118,6 +3118,12 @@ public: "exceptions (0 means all)") \ range(0, max_jint/2) \ \ + develop(bool, TraceStackWalk, false, \ + "Trace stack walking") \ + \ + product(bool, MemberNameInStackFrame, true, \ + "Use MemberName in StackFrame") \ + \ /* notice: the max range value here is max_jint, not max_intx */ \ /* because of overflow issue */ \ NOT_EMBEDDED(diagnostic(intx, GuaranteedSafepointInterval, 1000, \ diff --git a/hotspot/src/share/vm/runtime/vframe.hpp b/hotspot/src/share/vm/runtime/vframe.hpp index 74c9b725811..654d6b823b1 100644 --- a/hotspot/src/share/vm/runtime/vframe.hpp +++ b/hotspot/src/share/vm/runtime/vframe.hpp @@ -317,10 +317,18 @@ class vframeStreamCommon : StackObj { intptr_t* frame_id() const { return _frame.id(); } address frame_pc() const { return _frame.pc(); } + javaVFrame* java_frame() { + vframe* vf = vframe::new_vframe(&_frame, &_reg_map, _thread); + if (vf->is_java_frame()) { + return (javaVFrame*)vf; + } + return NULL; + } + CodeBlob* cb() const { return _frame.cb(); } nmethod* nm() const { - assert( cb() != NULL && cb()->is_nmethod(), "usage"); - return (nmethod*) cb(); + assert( cb() != NULL && cb()->is_nmethod(), "usage"); + return (nmethod*) cb(); } // Frame type From c67974cf0ffaa7a13b653595ee2f3db1d221e8ad Mon Sep 17 00:00:00 2001 From: Rachel Protacio Date: Mon, 23 Nov 2015 16:16:46 -0500 Subject: [PATCH 064/260] 8143157: Convert TraceVMOperation to Unified Logging The former -XX:+TraceVMOperation flag is updated to the unified logging framework and is now replaced with -Xlog:vmoperation in product mode. Reviewed-by: coleenp, dholmes, mockner --- hotspot/src/share/vm/logging/logTag.hpp | 3 +- hotspot/src/share/vm/runtime/globals.hpp | 3 -- .../src/share/vm/runtime/vm_operations.cpp | 17 +++++-- .../test/runtime/logging/VMOperationTest.java | 46 +++++++++++++++++++ .../runtime/logging/VMOperationTestMain.java | 43 +++++++++++++++++ 5 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 hotspot/test/runtime/logging/VMOperationTest.java create mode 100644 hotspot/test/runtime/logging/VMOperationTestMain.java diff --git a/hotspot/src/share/vm/logging/logTag.hpp b/hotspot/src/share/vm/logging/logTag.hpp index 4d5d6caf73d..aa1ef40c118 100644 --- a/hotspot/src/share/vm/logging/logTag.hpp +++ b/hotspot/src/share/vm/logging/logTag.hpp @@ -33,7 +33,8 @@ #define LOG_TAG_LIST \ LOG_TAG(defaultmethods) \ LOG_TAG(logging) \ - LOG_TAG(safepoint) + LOG_TAG(safepoint) \ + LOG_TAG(vmoperation) #define PREFIX_LOG_TAG(T) (LogTag::T) diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 9724ebdd6d4..cf6637e396a 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1073,9 +1073,6 @@ public: develop(bool, BreakAtWarning, false, \ "Execute breakpoint upon encountering VM warning") \ \ - develop(bool, TraceVMOperation, false, \ - "Trace VM operations") \ - \ develop(bool, UseFakeTimers, false, \ "Tell whether the VM should use system time or a fake timer") \ \ diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp index ff402e1eb58..92e855b9e83 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.cpp +++ b/hotspot/src/share/vm/runtime/vm_operations.cpp @@ -29,6 +29,7 @@ #include "code/codeCacheExtensions.hpp" #include "compiler/compileBroker.hpp" #include "gc/shared/isGCActiveMark.hpp" +#include "logging/log.hpp" #include "memory/heapInspection.hpp" #include "memory/resourceArea.hpp" #include "oops/symbol.hpp" @@ -55,13 +56,19 @@ void VM_Operation::set_calling_thread(Thread* thread, ThreadPriority priority) { void VM_Operation::evaluate() { ResourceMark rm; - if (TraceVMOperation) { - tty->print("["); - NOT_PRODUCT(print();) + outputStream* debugstream; + bool enabled = log_is_enabled(Debug, vmoperation); + if (enabled) { + debugstream = LogHandle(vmoperation)::debug_stream(); + debugstream->print("begin "); + print_on_error(debugstream); + debugstream->cr(); } doit(); - if (TraceVMOperation) { - tty->print_cr("]"); + if (enabled) { + debugstream->print("end "); + print_on_error(debugstream); + debugstream->cr(); } } diff --git a/hotspot/test/runtime/logging/VMOperationTest.java b/hotspot/test/runtime/logging/VMOperationTest.java new file mode 100644 index 00000000000..630dcd14386 --- /dev/null +++ b/hotspot/test/runtime/logging/VMOperationTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143157 + * @summary vmoperation=debug should have logging output + * @library /testlibrary + * @compile VMOperationTestMain.java + * @modules java.base/sun.misc + * java.management + * @run main VMOperationTest + */ + +import jdk.test.lib.*; + +public class VMOperationTest { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xlog:vmoperation=debug", "-Xmx64m", "-Xms64m", "VMOperationTestMain"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("VM_Operation ("); + output.shouldHaveExitValue(0); + } +} + diff --git a/hotspot/test/runtime/logging/VMOperationTestMain.java b/hotspot/test/runtime/logging/VMOperationTestMain.java new file mode 100644 index 00000000000..53101892dc2 --- /dev/null +++ b/hotspot/test/runtime/logging/VMOperationTestMain.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.ref.WeakReference; + +public class VMOperationTestMain { + public static byte[] garbage; + public static volatile WeakReference weakref; + + public static void createweakref() { + Object o = new Object(); + weakref = new WeakReference<>(o); + } + + // Loop until a GC runs. + public static void main(String[] args) throws Exception { + createweakref(); + while (weakref.get() != null) { + garbage = new byte[8192]; + System.gc(); + } + } +} From 274653d406083f942ee41d06915f4d808fd5e637 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 23 Nov 2015 21:05:43 -0500 Subject: [PATCH 065/260] 8143836: [TESTBUG] runtime/CommandLine/IgnoreUnrecognizedVMOptions fails in jdk9/dev Reviewed-by: coleenp, hseigel --- .../IgnoreUnrecognizedVMOptions.java | 36 ++++++++----------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/hotspot/test/runtime/CommandLine/IgnoreUnrecognizedVMOptions.java b/hotspot/test/runtime/CommandLine/IgnoreUnrecognizedVMOptions.java index c876b136969..d24a1f31019 100644 --- a/hotspot/test/runtime/CommandLine/IgnoreUnrecognizedVMOptions.java +++ b/hotspot/test/runtime/CommandLine/IgnoreUnrecognizedVMOptions.java @@ -131,47 +131,41 @@ public class IgnoreUnrecognizedVMOptions { /* #1.7 locked flag: - diagnostic & locked experimental & locked commercial & locked - -XX:-UnlockDiagnosticVMOptions -XX:-UnlockExperimentalVMOptions -XX:-UnlockCommercialFeatures - -XX:+PrintInlining -XX:+AlwaysSafeConstructors -XX:+FlightRecorder - -IgnoreUnrecognizedVMOptions ERR ERR ERR - +IgnoreUnrecognizedVMOptions ERR ERR ERR + diagnostic & locked experimental & locked + -XX:-UnlockDiagnosticVMOptions -XX:-UnlockExperimentalVMOptions + -XX:+PrintInlining -XX:+AlwaysSafeConstructors + -IgnoreUnrecognizedVMOptions ERR ERR + +IgnoreUnrecognizedVMOptions ERR ERR */ runJavaAndCheckExitValue(false, "-XX:-IgnoreUnrecognizedVMOptions", "-XX:-UnlockDiagnosticVMOptions", "-XX:+PrintInlining", "-version"); runJavaAndCheckExitValue(false, "-XX:-IgnoreUnrecognizedVMOptions", "-XX:-UnlockExperimentalVMOptions", "-XX:+AlwaysSafeConstructors", "-version"); - runJavaAndCheckExitValue(false, "-XX:-IgnoreUnrecognizedVMOptions", "-XX:-UnlockCommercialFeatures", "-XX:+FlightRecorder", "-version"); runJavaAndCheckExitValue(false, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UnlockDiagnosticVMOptions", "-XX:+PrintInlining", "-version"); runJavaAndCheckExitValue(false, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UnlockExperimentalVMOptions", "-XX:+AlwaysSafeConstructors", "-version"); - runJavaAndCheckExitValue(false, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UnlockCommercialFeatures", "-XX:+FlightRecorder", "-version"); /* #1.8 malformed locked flag: - diagnostic & locked experimental & locked commercial & locked - -XX:-UnlockDiagnosticVMOptions -XX:-UnlockExperimentalVMOptions -XX:-UnlockCommercialFeatures - -XX:PrintInlining -XX:AlwaysSafeConstructors -XX:FlightRecorder - -IgnoreUnrecognizedVMOptions ERR ERR ERR - +IgnoreUnrecognizedVMOptions ERR ERR ERR + diagnostic & locked experimental & locked + -XX:-UnlockDiagnosticVMOptions -XX:-UnlockExperimentalVMOptions + -XX:PrintInlining -XX:AlwaysSafeConstructors + -IgnoreUnrecognizedVMOptions ERR ERR + +IgnoreUnrecognizedVMOptions ERR ERR */ runJavaAndCheckExitValue(false, "-XX:-IgnoreUnrecognizedVMOptions", "-XX:-UnlockDiagnosticVMOptions", "-XX:PrintInlining", "-version"); runJavaAndCheckExitValue(false, "-XX:-IgnoreUnrecognizedVMOptions", "-XX:-UnlockExperimentalVMOptions", "-XX:AlwaysSafeConstructors", "-version"); - runJavaAndCheckExitValue(false, "-XX:-IgnoreUnrecognizedVMOptions", "-XX:-UnlockCommercialFeatures", "-XX:FlightRecorder", "-version"); runJavaAndCheckExitValue(false, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UnlockDiagnosticVMOptions", "-XX:PrintInlining", "-version"); runJavaAndCheckExitValue(false, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UnlockExperimentalVMOptions", "-XX:AlwaysSafeConstructors", "-version"); - runJavaAndCheckExitValue(false, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UnlockCommercialFeatures", "-XX:FlightRecorder", "-version"); /* #1.9 malformed unlocked flag: - diagnostic & locked experimental & locked commercial & locked - -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UnlockCommercialFeatures - -XX:PrintInlining -XX:AlwaysSafeConstructors -XX:FlightRecorder - -IgnoreUnrecognizedVMOptions ERR ERR ERR - +IgnoreUnrecognizedVMOptions ERR ERR ERR + diagnostic & locked experimental & locked + -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions + -XX:PrintInlining -XX:AlwaysSafeConstructors + -IgnoreUnrecognizedVMOptions ERR ERR + +IgnoreUnrecognizedVMOptions ERR ERR */ runJavaAndCheckExitValue(false, "-XX:-IgnoreUnrecognizedVMOptions", "-XX:-UnlockDiagnosticVMOptions", "-XX:PrintInlining", "-version"); runJavaAndCheckExitValue(false, "-XX:-IgnoreUnrecognizedVMOptions", "-XX:-UnlockExperimentalVMOptions", "-XX:AlwaysSafeConstructors", "-version"); - runJavaAndCheckExitValue(false, "-XX:-IgnoreUnrecognizedVMOptions", "-XX:-UnlockCommercialFeatures", "-XX:FlightRecorder", "-version"); runJavaAndCheckExitValue(false, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UnlockDiagnosticVMOptions", "-XX:PrintInlining", "-version"); runJavaAndCheckExitValue(false, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UnlockExperimentalVMOptions", "-XX:AlwaysSafeConstructors", "-version"); - runJavaAndCheckExitValue(false, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UnlockCommercialFeatures", "-XX:FlightRecorder", "-version"); } } From 7b9d2f145368f7c94c65daee897b144a60f194f8 Mon Sep 17 00:00:00 2001 From: Dmitry Dmitriev Date: Tue, 24 Nov 2015 09:42:05 +0300 Subject: [PATCH 066/260] 8143038: [TESTBUG] TestOptionsWithRanges: allow excluding only a subset of tested values specified for a flag Reviewed-by: gziemski, ctornqvi --- .../TestOptionsWithRanges.java | 67 +++++++---- .../optionsvalidation/DoubleJVMOption.java | 32 +++--- .../optionsvalidation/IntJVMOption.java | 108 ++++++++++-------- .../common/optionsvalidation/JVMOption.java | 26 +++++ 4 files changed, 150 insertions(+), 83 deletions(-) diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java index 5c9e0b43913..dcd29e4f4cb 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java @@ -41,22 +41,45 @@ import optionsvalidation.JVMOptionsUtils; public class TestOptionsWithRanges { + private static Map allOptionsAsMap; + + private static void excludeTestMaxRange(String optionName) { + JVMOption option = allOptionsAsMap.get(optionName); + + if (option != null) { + option.excludeTestMaxRange(); + } + } + + private static void excludeTestMinRange(String optionName) { + JVMOption option = allOptionsAsMap.get(optionName); + + if (option != null) { + option.excludeTestMinRange(); + } + } + + private static void excludeTestRange(String optionName) { + allOptionsAsMap.remove(optionName); + } + public static void main(String[] args) throws Exception { int failedTests; - Map allOptionsAsMap = JVMOptionsUtils.getOptionsWithRangeAsMap(); List allOptions; + allOptionsAsMap = JVMOptionsUtils.getOptionsWithRangeAsMap(); + /* * Remove CICompilerCount from testing because currently it can hang system */ - allOptionsAsMap.remove("CICompilerCount"); + excludeTestMaxRange("CICompilerCount"); /* * JDK-8136766 * Temporarily remove ThreadStackSize from testing because Windows can set it to 0 * (for default OS size) but other platforms insist it must be greater than 0 - */ - allOptionsAsMap.remove("ThreadStackSize"); + */ + excludeTestRange("ThreadStackSize"); /* * JDK-8141650 @@ -64,7 +87,7 @@ public class TestOptionsWithRanges { * "The shared miscellaneous data space is not large enough to preload requested classes." * message at min value. */ - allOptionsAsMap.remove("SharedMiscDataSize"); + excludeTestRange("SharedMiscDataSize"); /* * JDK-8142874 @@ -72,25 +95,25 @@ public class TestOptionsWithRanges { * "The shared miscellaneous data space is not large enough to preload requested classes." * message at max values. */ - allOptionsAsMap.remove("SharedReadWriteSize"); - allOptionsAsMap.remove("SharedReadOnlySize"); - allOptionsAsMap.remove("SharedMiscDataSize"); - allOptionsAsMap.remove("SharedMiscCodeSize"); + excludeTestRange("SharedReadWriteSize"); + excludeTestRange("SharedReadOnlySize"); + excludeTestRange("SharedMiscDataSize"); + excludeTestRange("SharedMiscCodeSize"); /* * Exclude MallocMaxTestWords as it is expected to exit VM at small values (>=0) */ - allOptionsAsMap.remove("MallocMaxTestWords"); + excludeTestMinRange("MallocMaxTestWords"); /* * Exclude below options as their maximum value would consume too much memory * and would affect other tests that run in parallel. */ - allOptionsAsMap.remove("G1ConcRefinementThreads"); - allOptionsAsMap.remove("G1RSetRegionEntries"); - allOptionsAsMap.remove("G1RSetSparseRegionEntries"); - allOptionsAsMap.remove("G1UpdateBufferSize"); - allOptionsAsMap.remove("InitialBootClassLoaderMetaspaceSize"); + excludeTestMaxRange("G1ConcRefinementThreads"); + excludeTestMaxRange("G1RSetRegionEntries"); + excludeTestMaxRange("G1RSetSparseRegionEntries"); + excludeTestMaxRange("G1UpdateBufferSize"); + excludeTestMaxRange("InitialBootClassLoaderMetaspaceSize"); /* * Remove parameters controlling the code cache. As these @@ -102,13 +125,13 @@ public class TestOptionsWithRanges { * hotspot/src/shared/vm/code/codeCache.cpp), therefore * omitting testing for them does not pose a problem. */ - allOptionsAsMap.remove("InitialCodeCacheSize"); - allOptionsAsMap.remove("CodeCacheMinimumUseSpace"); - allOptionsAsMap.remove("ReservedCodeCacheSize"); - allOptionsAsMap.remove("NonProfiledCodeHeapSize"); - allOptionsAsMap.remove("ProfiledCodeHeapSize"); - allOptionsAsMap.remove("NonNMethodCodeHeapSize"); - allOptionsAsMap.remove("CodeCacheExpansionSize"); + excludeTestMaxRange("InitialCodeCacheSize"); + excludeTestMaxRange("CodeCacheMinimumUseSpace"); + excludeTestMaxRange("ReservedCodeCacheSize"); + excludeTestMaxRange("NonProfiledCodeHeapSize"); + excludeTestMaxRange("ProfiledCodeHeapSize"); + excludeTestMaxRange("NonNMethodCodeHeapSize"); + excludeTestMaxRange("CodeCacheExpansionSize"); allOptions = new ArrayList<>(allOptionsAsMap.values()); diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/DoubleJVMOption.java b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/DoubleJVMOption.java index d6c4abc563c..b80fc268515 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/DoubleJVMOption.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/DoubleJVMOption.java @@ -123,22 +123,28 @@ public class DoubleJVMOption extends JVMOption { protected List getValidValues() { List validValues = new ArrayList<>(); - validValues.add(formatValue(min)); - validValues.add(formatValue(max)); - - if ((Double.compare(min, ADDITIONAL_TEST_DOUBLE_NEGATIVE) < 0) - && (Double.compare(max, ADDITIONAL_TEST_DOUBLE_NEGATIVE) > 0)) { - validValues.add(formatValue(ADDITIONAL_TEST_DOUBLE_NEGATIVE)); + if (testMinRange) { + validValues.add(formatValue(min)); + } + if (testMaxRange) { + validValues.add(formatValue(max)); } - if ((Double.compare(min, ADDITIONAL_TEST_DOUBLE_ZERO) < 0) - && (Double.compare(max, ADDITIONAL_TEST_DOUBLE_ZERO) > 0)) { - validValues.add(formatValue(ADDITIONAL_TEST_DOUBLE_ZERO)); - } + if (testMinRange) { + if ((Double.compare(min, ADDITIONAL_TEST_DOUBLE_NEGATIVE) < 0) + && (Double.compare(max, ADDITIONAL_TEST_DOUBLE_NEGATIVE) > 0)) { + validValues.add(formatValue(ADDITIONAL_TEST_DOUBLE_NEGATIVE)); + } - if ((Double.compare(min, ADDITIONAL_TEST_DOUBLE_POSITIVE) < 0) - && (Double.compare(max, ADDITIONAL_TEST_DOUBLE_POSITIVE) > 0)) { - validValues.add(formatValue(ADDITIONAL_TEST_DOUBLE_POSITIVE)); + if ((Double.compare(min, ADDITIONAL_TEST_DOUBLE_ZERO) < 0) + && (Double.compare(max, ADDITIONAL_TEST_DOUBLE_ZERO) > 0)) { + validValues.add(formatValue(ADDITIONAL_TEST_DOUBLE_ZERO)); + } + + if ((Double.compare(min, ADDITIONAL_TEST_DOUBLE_POSITIVE) < 0) + && (Double.compare(max, ADDITIONAL_TEST_DOUBLE_POSITIVE) > 0)) { + validValues.add(formatValue(ADDITIONAL_TEST_DOUBLE_POSITIVE)); + } } return validValues; diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java index a7685f37ae5..417178ead8d 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java @@ -200,43 +200,51 @@ public class IntJVMOption extends JVMOption { protected List getValidValues() { List validValues = new ArrayList<>(); - validValues.add(min.toString()); - validValues.add(max.toString()); - - if ((min.compareTo(MINUS_ONE) == -1) && (max.compareTo(MINUS_ONE) == 1)) { - /* - * Add -1 as valid value if min is less than -1 and max is greater than -1 - */ - validValues.add("-1"); + if (testMinRange) { + validValues.add(min.toString()); + } + if (testMaxRange) { + validValues.add(max.toString()); } - if ((min.compareTo(BigInteger.ZERO) == -1) && (max.compareTo(BigInteger.ZERO) == 1)) { - /* - * Add 0 as valid value if min is less than 0 and max is greater than 0 - */ - validValues.add("0"); - } - if ((min.compareTo(BigInteger.ONE) == -1) && (max.compareTo(BigInteger.ONE) == 1)) { - /* - * Add 1 as valid value if min is less than 1 and max is greater than 1 - */ - validValues.add("1"); + if (testMinRange) { + if ((min.compareTo(MINUS_ONE) == -1) && (max.compareTo(MINUS_ONE) == 1)) { + /* + * Add -1 as valid value if min is less than -1 and max is greater than -1 + */ + validValues.add("-1"); + } + + if ((min.compareTo(BigInteger.ZERO) == -1) && (max.compareTo(BigInteger.ZERO) == 1)) { + /* + * Add 0 as valid value if min is less than 0 and max is greater than 0 + */ + validValues.add("0"); + } + if ((min.compareTo(BigInteger.ONE) == -1) && (max.compareTo(BigInteger.ONE) == 1)) { + /* + * Add 1 as valid value if min is less than 1 and max is greater than 1 + */ + validValues.add("1"); + } } - if ((min.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == -1) && (max.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == 1)) { - /* - * Check for overflow when flag is assigned to the - * 4 byte int variable - */ - validValues.add(MAX_4_BYTE_INT_PLUS_ONE.toString()); - } + if (testMaxRange) { + if ((min.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == -1) && (max.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == 1)) { + /* + * Check for overflow when flag is assigned to the + * 4 byte int variable + */ + validValues.add(MAX_4_BYTE_INT_PLUS_ONE.toString()); + } - if ((min.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == -1) && (max.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == 1)) { - /* - * Check for overflow when flag is assigned to the - * 4 byte unsigned int variable - */ - validValues.add(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE.toString()); + if ((min.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == -1) && (max.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == 1)) { + /* + * Check for overflow when flag is assigned to the + * 4 byte unsigned int variable + */ + validValues.add(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE.toString()); + } } return validValues; @@ -252,24 +260,28 @@ public class IntJVMOption extends JVMOption { protected List getInvalidValues() { List invalidValues = new ArrayList<>(); + /* Return invalid values only for options which have defined range in VM */ if (withRange) { - /* Return invalid values only for options which have defined range in VM */ - if ((is32Bit && min.compareTo(MIN_4_BYTE_INT) != 0) - || (!is32Bit && min.compareTo(MIN_LONG) != 0)) { - invalidValues.add(min.subtract(BigInteger.ONE).toString()); - } + if (unsigned) { + /* Only add non-negative out-of-range values for unsigned options */ + if (min.compareTo(BigInteger.ZERO) == 1) { + invalidValues.add(min.subtract(BigInteger.ONE).toString()); + } - if (!unsigned - && ((is32Bit && (max.compareTo(MAX_4_BYTE_INT) != 0)) - || (!is32Bit && (max.compareTo(MAX_LONG) != 0)))) { - invalidValues.add(max.add(BigInteger.ONE).toString()); - } - - if (unsigned - && ((is32Bit && (max.compareTo(MAX_4_BYTE_UNSIGNED_INT) != 0)) - || (!is32Bit && !uint64 && (max.compareTo(MAX_UNSIGNED_LONG) != 0)) - || (uint64 && (max.compareTo(MAX_UNSIGNED_LONG_64) != 0)))) { - invalidValues.add(max.add(BigInteger.ONE).toString()); + if ((is32Bit && (max.compareTo(MAX_4_BYTE_UNSIGNED_INT) != 0)) + || (!is32Bit && !uint64 && (max.compareTo(MAX_UNSIGNED_LONG) != 0)) + || (uint64 && (max.compareTo(MAX_UNSIGNED_LONG_64) != 0))) { + invalidValues.add(max.add(BigInteger.ONE).toString()); + } + } else { + if ((is32Bit && min.compareTo(MIN_4_BYTE_INT) != 0) + || (!is32Bit && min.compareTo(MIN_LONG) != 0)) { + invalidValues.add(min.subtract(BigInteger.ONE).toString()); + } + if ((is32Bit && (max.compareTo(MAX_4_BYTE_INT) != 0)) + || (!is32Bit && (max.compareTo(MAX_LONG) != 0))) { + invalidValues.add(max.add(BigInteger.ONE).toString()); + } } } diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOption.java b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOption.java index 3f4ad09b269..bd964e19ae0 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOption.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOption.java @@ -54,6 +54,16 @@ public abstract class JVMOption { */ protected boolean withRange; + /** + * Test valid min range value and additional small values + */ + protected boolean testMinRange; + + /** + * Test valid max range value and additional big values + */ + protected boolean testMaxRange; + /** * Prepend string which added before testing option to the command line */ @@ -64,6 +74,8 @@ public abstract class JVMOption { this.prepend = new ArrayList<>(); prependString = new StringBuilder(); withRange = false; + testMinRange = true; + testMaxRange = true; } /** @@ -135,6 +147,20 @@ public abstract class JVMOption { withRange = true; } + /** + * Exclude testing of min range value for this option + */ + public final void excludeTestMinRange() { + testMinRange = false; + } + + /** + * Exclude testing of max range value for this option + */ + public final void excludeTestMaxRange() { + testMaxRange = false; + } + /** * Set new minimum option value * From 7fe249f6dbca09cfb421728a6c0e68a22b958bc0 Mon Sep 17 00:00:00 2001 From: Hui Shi Date: Tue, 24 Nov 2015 09:02:26 +0000 Subject: [PATCH 067/260] 8143285: aarch64: Missing load acquire when checking if ConstantPoolCacheEntry is resolved Reviewed-by: roland, aph --- hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp index 8fe6b38f0c0..d463f059978 100644 --- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp @@ -189,10 +189,11 @@ void InterpreterMacroAssembler::get_cache_and_index_and_bytecode_at_bcp(Register get_cache_and_index_at_bcp(cache, index, bcp_offset, index_size); // We use a 32-bit load here since the layout of 64-bit words on // little-endian machines allow us that. - // n.b. unlike x86 cache alreeady includes the index offset - ldrw(bytecode, Address(cache, + // n.b. unlike x86 cache already includes the index offset + lea(bytecode, Address(cache, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset())); + ldarw(bytecode, bytecode); const int shift_count = (1 + byte_no) * BitsPerByte; ubfx(bytecode, bytecode, shift_count, BitsPerByte); } From 66a728fc2773184ca7b48f9d3ebad333f47b6601 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 24 Nov 2015 10:22:36 +0100 Subject: [PATCH 068/260] 8136681: Factor out IHOP calculation from G1CollectorPolicy Move out existing IHOP value calculation into an implementation of a new interface called G1IHOPControl. Prepare for changes to accomodate adaptive IHOP implementation. Reviewed-by: jmasa, mgerdin, ehelin --- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 19 +- .../src/share/vm/gc/g1/g1CollectedHeap.hpp | 4 + .../src/share/vm/gc/g1/g1CollectorPolicy.cpp | 224 ++++++++++++++---- .../src/share/vm/gc/g1/g1CollectorPolicy.hpp | 56 ++++- hotspot/src/share/vm/gc/g1/g1ErgoVerbose.cpp | 1 + hotspot/src/share/vm/gc/g1/g1ErgoVerbose.hpp | 1 + hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp | 112 +++++++++ hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp | 98 ++++++++ .../gc/g1/g1InitialMarkToMixedTimeTracker.hpp | 87 +++++++ hotspot/src/share/vm/prims/jni.cpp | 2 + 10 files changed, 551 insertions(+), 53 deletions(-) create mode 100644 hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp create mode 100644 hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp create mode 100644 hotspot/src/share/vm/gc/g1/g1InitialMarkToMixedTimeTracker.hpp diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index e1938d910af..3e635b292f5 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -402,6 +402,11 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first, return new_obj; } +size_t G1CollectedHeap::humongous_obj_size_in_regions(size_t word_size) { + assert(is_humongous(word_size), "Object of size " SIZE_FORMAT " must be humongous here", word_size); + return align_size_up_(word_size, HeapRegion::GrainWords) / HeapRegion::GrainWords; +} + // If could fit into free regions w/o expansion, try. // Otherwise, if can expand, do so. // Otherwise, if using ex regions might help, try with ex given back. @@ -411,7 +416,7 @@ HeapWord* G1CollectedHeap::humongous_obj_allocate(size_t word_size, AllocationCo verify_region_sets_optional(); uint first = G1_NO_HRM_INDEX; - uint obj_regions = (uint)(align_size_up_(word_size, HeapRegion::GrainWords) / HeapRegion::GrainWords); + uint obj_regions = (uint) humongous_obj_size_in_regions(word_size); if (obj_regions == 1) { // Only one region to allocate, try to use a fast path by directly allocating @@ -1011,6 +1016,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size, // collection hoping that there's enough space in the heap. result = humongous_obj_allocate(word_size, AllocationContext::current()); if (result != NULL) { + size_t size_in_regions = humongous_obj_size_in_regions(word_size); + g1_policy()->add_bytes_allocated_in_old_since_last_gc(size_in_regions * HeapRegion::GrainBytes); return result; } @@ -5234,6 +5241,8 @@ void G1CollectedHeap::post_evacuate_collection_set(EvacuationInfo& evacuation_in } void G1CollectedHeap::record_obj_copy_mem_stats() { + g1_policy()->add_bytes_allocated_in_old_since_last_gc(_old_evac_stats.allocated() * HeapWordSize); + _gc_tracer_stw->report_evacuation_statistics(create_g1_evac_summary(&_survivor_evac_stats), create_g1_evac_summary(&_old_evac_stats)); } @@ -5618,6 +5627,14 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& e cur->set_young_index_in_cset(-1); } cur->set_evacuation_failed(false); + // When moving a young gen region to old gen, we "allocate" that whole region + // there. This is in addition to any already evacuated objects. Notify the + // policy about that. + // Old gen regions do not cause an additional allocation: both the objects + // still in the region and the ones already moved are accounted for elsewhere. + if (cur->is_young()) { + policy->add_bytes_allocated_in_old_since_last_gc(HeapRegion::GrainBytes); + } // The region is now considered to be old. cur->set_old(); // Do some allocation statistics accounting. Regions that failed evacuation diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index 8acf26779e7..24cb48d3074 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -1343,6 +1343,10 @@ public: return (region_size / 2); } + // Returns the number of regions the humongous object of the given word size + // requires. + static size_t humongous_obj_size_in_regions(size_t word_size); + // Print the maximum heap capacity. virtual size_t max_capacity() const; diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index 2a5ec5e9366..b645876493e 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -28,6 +28,7 @@ #include "gc/g1/concurrentMarkThread.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" +#include "gc/g1/g1IHOPControl.hpp" #include "gc/g1/g1ErgoVerbose.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1Log.hpp" @@ -38,6 +39,7 @@ #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/debug.hpp" +#include "utilities/pair.hpp" // Different defaults for different number of GC threads // They were chosen by running GCOld and SPECjbb on debris with different @@ -148,7 +150,11 @@ G1CollectorPolicy::G1CollectorPolicy() : _recorded_survivor_tail(NULL), _survivors_age_table(true), - _gc_overhead_perc(0.0) { + _gc_overhead_perc(0.0), + + _bytes_allocated_in_old_since_last_gc(0), + _ihop_control(NULL), + _initial_mark_to_mixed() { // SurvRateGroups below must be initialized after the predictor because they // indirectly use it through this object passed to their constructor. @@ -288,6 +294,10 @@ G1CollectorPolicy::G1CollectorPolicy() : _collectionSetChooser = new CollectionSetChooser(); } +G1CollectorPolicy::~G1CollectorPolicy() { + delete _ihop_control; +} + double G1CollectorPolicy::get_new_prediction(TruncatedSeq const* seq) const { return _predictor.get_new_prediction(seq); } @@ -317,6 +327,8 @@ void G1CollectorPolicy::post_heap_initialize() { if (max_young_size != MaxNewSize) { FLAG_SET_ERGO(size_t, MaxNewSize, max_young_size); } + + _ihop_control = create_ihop_control(); } G1CollectorState* G1CollectorPolicy::collector_state() const { return _g1->collector_state(); } @@ -522,25 +534,26 @@ uint G1CollectorPolicy::calculate_young_list_desired_max_length() const { return _young_gen_sizer->max_desired_young_length(); } -void G1CollectorPolicy::update_young_list_max_and_target_length() { - update_young_list_max_and_target_length(get_new_prediction(_rs_lengths_seq)); +uint G1CollectorPolicy::update_young_list_max_and_target_length() { + return update_young_list_max_and_target_length(get_new_prediction(_rs_lengths_seq)); } -void G1CollectorPolicy::update_young_list_max_and_target_length(size_t rs_lengths) { - update_young_list_target_length(rs_lengths); +uint G1CollectorPolicy::update_young_list_max_and_target_length(size_t rs_lengths) { + uint unbounded_target_length = update_young_list_target_length(rs_lengths); update_max_gc_locker_expansion(); + return unbounded_target_length; } -void G1CollectorPolicy::update_young_list_target_length(size_t rs_lengths) { - _young_list_target_length = bounded_young_list_target_length(rs_lengths); +uint G1CollectorPolicy::update_young_list_target_length(size_t rs_lengths) { + YoungTargetLengths young_lengths = young_list_target_lengths(rs_lengths); + _young_list_target_length = young_lengths.first; + return young_lengths.second; } -void G1CollectorPolicy::update_young_list_target_length() { - update_young_list_target_length(get_new_prediction(_rs_lengths_seq)); -} +G1CollectorPolicy::YoungTargetLengths G1CollectorPolicy::young_list_target_lengths(size_t rs_lengths) const { + YoungTargetLengths result; -uint G1CollectorPolicy::bounded_young_list_target_length(size_t rs_lengths) const { - // Calculate the absolute and desired min bounds. + // Calculate the absolute and desired min bounds first. // This is how many young regions we already have (currently: the survivors). uint base_min_length = recorded_survivor_regions(); @@ -552,15 +565,7 @@ uint G1CollectorPolicy::bounded_young_list_target_length(size_t rs_lengths) cons desired_min_length = MAX2(desired_min_length, absolute_min_length); // Calculate the absolute and desired max bounds. - // We will try our best not to "eat" into the reserve. - uint absolute_max_length = 0; - if (_free_regions_at_end_of_collection > _reserve_regions) { - absolute_max_length = _free_regions_at_end_of_collection - _reserve_regions; - } uint desired_max_length = calculate_young_list_desired_max_length(); - if (desired_max_length > absolute_max_length) { - desired_max_length = absolute_max_length; - } uint young_list_target_length = 0; if (adaptive_young_list_length()) { @@ -581,6 +586,17 @@ uint G1CollectorPolicy::bounded_young_list_target_length(size_t rs_lengths) cons young_list_target_length = _young_list_fixed_length; } + result.second = young_list_target_length; + + // We will try our best not to "eat" into the reserve. + uint absolute_max_length = 0; + if (_free_regions_at_end_of_collection > _reserve_regions) { + absolute_max_length = _free_regions_at_end_of_collection - _reserve_regions; + } + if (desired_max_length > absolute_max_length) { + desired_max_length = absolute_max_length; + } + // Make sure we don't go over the desired max length, nor under the // desired min length. In case they clash, desired_min_length wins // which is why that test is second. @@ -595,7 +611,8 @@ uint G1CollectorPolicy::bounded_young_list_target_length(size_t rs_lengths) cons "we should be able to allocate at least one eden region"); assert(young_list_target_length >= absolute_min_length, "post-condition"); - return young_list_target_length; + result.first = young_list_target_length; + return result; } uint @@ -838,6 +855,10 @@ void G1CollectorPolicy::record_full_collection_end() { update_young_list_max_and_target_length(); update_rs_lengths_prediction(); _collectionSetChooser->clear(); + + _bytes_allocated_in_old_since_last_gc = 0; + + record_pause(FullGC, _full_collection_start_sec, end_sec); } void G1CollectorPolicy::record_stop_world_start() { @@ -895,7 +916,7 @@ void G1CollectorPolicy::record_concurrent_mark_remark_end() { _cur_mark_stop_world_time_ms += elapsed_time_ms; _prev_collection_pause_end_ms += elapsed_time_ms; - _mmu_tracker->add_pause(_mark_remark_start_sec, end_time_sec); + record_pause(Remark, _mark_remark_start_sec, end_time_sec); } void G1CollectorPolicy::record_concurrent_mark_cleanup_start() { @@ -906,6 +927,10 @@ void G1CollectorPolicy::record_concurrent_mark_cleanup_completed() { bool should_continue_with_reclaim = next_gc_should_be_mixed("request last young-only gc", "skip last young-only gc"); collector_state()->set_last_young_gc(should_continue_with_reclaim); + // We skip the marking phase. + if (!should_continue_with_reclaim) { + abort_time_to_mixed_tracking(); + } collector_state()->set_in_marking_window(false); } @@ -952,12 +977,13 @@ bool G1CollectorPolicy::need_to_start_conc_mark(const char* source, size_t alloc return false; } - size_t marking_initiating_used_threshold = - (_g1->capacity() / 100) * InitiatingHeapOccupancyPercent; + size_t marking_initiating_used_threshold = _ihop_control->get_conc_mark_start_threshold(); + size_t cur_used_bytes = _g1->non_young_capacity_bytes(); size_t alloc_byte_size = alloc_word_size * HeapWordSize; + size_t marking_request_bytes = cur_used_bytes + alloc_byte_size; - if ((cur_used_bytes + alloc_byte_size) > marking_initiating_used_threshold) { + if (marking_request_bytes > marking_initiating_used_threshold) { if (collector_state()->gcs_are_young() && !collector_state()->last_young_gc()) { ergo_verbose5(ErgoConcCycles, "request concurrent cycle initiation", @@ -969,7 +995,7 @@ bool G1CollectorPolicy::need_to_start_conc_mark(const char* source, size_t alloc cur_used_bytes, alloc_byte_size, marking_initiating_used_threshold, - (double) InitiatingHeapOccupancyPercent, + (double) marking_initiating_used_threshold / _g1->capacity() * 100, source); return true; } else { @@ -996,10 +1022,7 @@ bool G1CollectorPolicy::need_to_start_conc_mark(const char* source, size_t alloc void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t cards_scanned) { double end_time_sec = os::elapsedTime(); - assert(_cur_collection_pause_used_regions_at_start >= cset_region_length(), - "otherwise, the subtraction below does not make sense"); - size_t rs_size = - _cur_collection_pause_used_regions_at_start - cset_region_length(); + size_t cur_used_bytes = _g1->used(); assert(cur_used_bytes == _g1->recalculate_used(), "It should!"); bool last_pause_included_initial_mark = false; @@ -1013,6 +1036,8 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t } #endif // PRODUCT + record_pause(young_gc_pause_kind(), end_time_sec - pause_time_ms / 1000.0, end_time_sec); + last_pause_included_initial_mark = collector_state()->during_initial_mark_pause(); if (last_pause_included_initial_mark) { record_concurrent_mark_init_end(0.0); @@ -1020,19 +1045,16 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t maybe_start_marking(); } - _mmu_tracker->add_pause(end_time_sec - pause_time_ms/1000.0, end_time_sec); + double app_time_ms = (phase_times()->cur_collection_start_sec() * 1000.0 - _prev_collection_pause_end_ms); + if (app_time_ms < MIN_TIMER_GRANULARITY) { + // This usually happens due to the timer not having the required + // granularity. Some Linuxes are the usual culprits. + // We'll just set it to something (arbitrarily) small. + app_time_ms = 1.0; + } if (update_stats) { _trace_young_gen_time_data.record_end_collection(pause_time_ms, phase_times()); - // this is where we update the allocation rate of the application - double app_time_ms = - (phase_times()->cur_collection_start_sec() * 1000.0 - _prev_collection_pause_end_ms); - if (app_time_ms < MIN_TIMER_GRANULARITY) { - // This usually happens due to the timer not having the required - // granularity. Some Linuxes are the usual culprits. - // We'll just set it to something (arbitrarily) small. - app_time_ms = 1.0; - } // We maintain the invariant that all objects allocated by mutator // threads will be allocated out of eden regions. So, we can use // the eden region number allocated since the previous GC to @@ -1077,6 +1099,9 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t if (next_gc_should_be_mixed("start mixed GCs", "do not start mixed GCs")) { collector_state()->set_gcs_are_young(false); + } else { + // We aborted the mixed GC phase early. + abort_time_to_mixed_tracking(); } collector_state()->set_last_young_gc(false); @@ -1085,7 +1110,6 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t if (!collector_state()->last_gc_was_young()) { // This is a mixed GC. Here we decide whether to continue doing // mixed GCs or not. - if (!next_gc_should_be_mixed("continue mixed GCs", "do not continue mixed GCs")) { collector_state()->set_gcs_are_young(true); @@ -1177,9 +1201,18 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t collector_state()->set_in_marking_window(new_in_marking_window); collector_state()->set_in_marking_window_im(new_in_marking_window_im); _free_regions_at_end_of_collection = _g1->num_free_regions(); - update_young_list_max_and_target_length(); + // IHOP control wants to know the expected young gen length if it were not + // restrained by the heap reserve. Using the actual length would make the + // prediction too small and the limit the young gen every time we get to the + // predicted target occupancy. + size_t last_unrestrained_young_length = update_young_list_max_and_target_length(); update_rs_lengths_prediction(); + update_ihop_prediction(app_time_ms / 1000.0, + _bytes_allocated_in_old_since_last_gc, + last_unrestrained_young_length * HeapRegion::GrainBytes); + _bytes_allocated_in_old_since_last_gc = 0; + // Note that _mmu_tracker->max_gc_time() returns the time in seconds. double update_rs_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSetUpdatingPauseTimePercent / 100.0; @@ -1205,6 +1238,53 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t _collectionSetChooser->verify(); } +G1IHOPControl* G1CollectorPolicy::create_ihop_control() const { + return new G1StaticIHOPControl(InitiatingHeapOccupancyPercent, + G1CollectedHeap::heap()->max_capacity()); +} + +void G1CollectorPolicy::update_ihop_prediction(double mutator_time_s, + size_t mutator_alloc_bytes, + size_t young_gen_size) { + // Always try to update IHOP prediction. Even evacuation failures give information + // about e.g. whether to start IHOP earlier next time. + + // Avoid using really small application times that might create samples with + // very high or very low values. They may be caused by e.g. back-to-back gcs. + double const min_valid_time = 1e-6; + + bool report = false; + + double marking_to_mixed_time = -1.0; + if (!collector_state()->last_gc_was_young() && _initial_mark_to_mixed.has_result()) { + marking_to_mixed_time = _initial_mark_to_mixed.last_marking_time(); + assert(marking_to_mixed_time > 0.0, + "Initial mark to mixed time must be larger than zero but is %.3f", + marking_to_mixed_time); + if (marking_to_mixed_time > min_valid_time) { + _ihop_control->update_marking_length(marking_to_mixed_time); + report = true; + } + } + + // As an approximation for the young gc promotion rates during marking we use + // all of them. In many applications there are only a few if any young gcs during + // marking, which makes any prediction useless. This increases the accuracy of the + // prediction. + if (collector_state()->last_gc_was_young() && mutator_time_s > min_valid_time) { + _ihop_control->update_allocation_info(mutator_time_s, mutator_alloc_bytes, young_gen_size); + report = true; + } + + if (report) { + report_ihop_statistics(); + } +} + +void G1CollectorPolicy::report_ihop_statistics() { + _ihop_control->print(); +} + #define EXT_SIZE_FORMAT "%.1f%s" #define EXT_SIZE_PARAMS(bytes) \ byte_size_in_proper_unit((double)(bytes)), \ @@ -1216,7 +1296,6 @@ void G1CollectorPolicy::record_heap_size_info_at_start(bool full) { _survivor_used_bytes_before_gc = young_list->survivor_used_bytes(); _heap_capacity_bytes_before_gc = _g1->capacity(); _heap_used_bytes_before_gc = _g1->used(); - _cur_collection_pause_used_regions_at_start = _g1->num_used_regions(); _eden_capacity_bytes_before_gc = (_young_list_target_length * HeapRegion::GrainBytes) - _survivor_used_bytes_before_gc; @@ -1717,8 +1796,7 @@ uint G1CollectorPolicy::calculate_parallel_work_chunk_size(uint n_workers, uint return MAX2(n_regions / (n_workers * overpartition_factor), min_chunk_size); } -void -G1CollectorPolicy::record_concurrent_mark_cleanup_end() { +void G1CollectorPolicy::record_concurrent_mark_cleanup_end() { _collectionSetChooser->clear(); WorkGang* workers = _g1->workers(); @@ -1737,7 +1815,8 @@ G1CollectorPolicy::record_concurrent_mark_cleanup_end() { _concurrent_mark_cleanup_times_ms->add(elapsed_time_ms); _cur_mark_stop_world_time_ms += elapsed_time_ms; _prev_collection_pause_end_ms += elapsed_time_ms; - _mmu_tracker->add_pause(_mark_cleanup_start_sec, end_sec); + + record_pause(Cleanup, _mark_cleanup_start_sec, end_sec); } // Add the heap region at the head of the non-incremental collection set @@ -1953,6 +2032,59 @@ void G1CollectorPolicy::maybe_start_marking() { } } +G1CollectorPolicy::PauseKind G1CollectorPolicy::young_gc_pause_kind() const { + assert(!collector_state()->full_collection(), "must be"); + if (collector_state()->during_initial_mark_pause()) { + assert(collector_state()->last_gc_was_young(), "must be"); + assert(!collector_state()->last_young_gc(), "must be"); + return InitialMarkGC; + } else if (collector_state()->last_young_gc()) { + assert(!collector_state()->during_initial_mark_pause(), "must be"); + assert(collector_state()->last_gc_was_young(), "must be"); + return LastYoungGC; + } else if (!collector_state()->last_gc_was_young()) { + assert(!collector_state()->during_initial_mark_pause(), "must be"); + assert(!collector_state()->last_young_gc(), "must be"); + return MixedGC; + } else { + assert(collector_state()->last_gc_was_young(), "must be"); + assert(!collector_state()->during_initial_mark_pause(), "must be"); + assert(!collector_state()->last_young_gc(), "must be"); + return YoungOnlyGC; + } +} + +void G1CollectorPolicy::record_pause(PauseKind kind, double start, double end) { + // Manage the MMU tracker. For some reason it ignores Full GCs. + if (kind != FullGC) { + _mmu_tracker->add_pause(start, end); + } + // Manage the mutator time tracking from initial mark to first mixed gc. + switch (kind) { + case FullGC: + abort_time_to_mixed_tracking(); + break; + case Cleanup: + case Remark: + case YoungOnlyGC: + case LastYoungGC: + _initial_mark_to_mixed.add_pause(end - start); + break; + case InitialMarkGC: + _initial_mark_to_mixed.record_initial_mark_end(end); + break; + case MixedGC: + _initial_mark_to_mixed.record_mixed_gc_start(start); + break; + default: + ShouldNotReachHere(); + } +} + +void G1CollectorPolicy::abort_time_to_mixed_tracking() { + _initial_mark_to_mixed.reset(); +} + bool G1CollectorPolicy::next_gc_should_be_mixed(const char* true_action_str, const char* false_action_str) const { CollectionSetChooser* cset_chooser = _collectionSetChooser; diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp index 416d695f30d..07d92cf9afc 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp @@ -29,9 +29,11 @@ #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1InCSetState.hpp" +#include "gc/g1/g1InitialMarkToMixedTimeTracker.hpp" #include "gc/g1/g1MMUTracker.hpp" #include "gc/g1/g1Predictions.hpp" #include "gc/shared/collectorPolicy.hpp" +#include "utilities/pair.hpp" // A G1CollectorPolicy makes policy decisions that determine the // characteristics of the collector. Examples include: @@ -40,6 +42,7 @@ class HeapRegion; class CollectionSetChooser; +class G1IHOPControl; // TraceYoungGenTime collects data on _both_ young and mixed evacuation pauses // (the latter may contain non-young regions - i.e. regions that are @@ -163,6 +166,15 @@ public: class G1CollectorPolicy: public CollectorPolicy { private: + G1IHOPControl* _ihop_control; + + G1IHOPControl* create_ihop_control() const; + // Update the IHOP control with necessary statistics. + void update_ihop_prediction(double mutator_time_s, + size_t mutator_alloc_bytes, + size_t young_gen_size); + void report_ihop_statistics(); + G1Predictions _predictor; double get_new_prediction(TruncatedSeq const* seq) const; @@ -182,7 +194,6 @@ class G1CollectorPolicy: public CollectorPolicy { CollectionSetChooser* _collectionSetChooser; double _full_collection_start_sec; - uint _cur_collection_pause_used_regions_at_start; // These exclude marking times. TruncatedSeq* _recent_gc_times_ms; @@ -271,9 +282,17 @@ class G1CollectorPolicy: public CollectorPolicy { size_t _pending_cards; + // The amount of allocated bytes in old gen during the last mutator and the following + // young GC phase. + size_t _bytes_allocated_in_old_since_last_gc; + + G1InitialMarkToMixedTimeTracker _initial_mark_to_mixed; public: const G1Predictions& predictor() const { return _predictor; } + // Add the given number of bytes to the total number of allocated bytes in the old gen. + void add_bytes_allocated_in_old_since_last_gc(size_t bytes) { _bytes_allocated_in_old_since_last_gc += bytes; } + // Accessors void set_region_eden(HeapRegion* hr, int young_index_in_cset) { @@ -473,16 +492,18 @@ private: double _mark_remark_start_sec; double _mark_cleanup_start_sec; - void update_young_list_max_and_target_length(); - void update_young_list_max_and_target_length(size_t rs_lengths); + // Updates the internal young list maximum and target lengths. Returns the + // unbounded young list target length. + uint update_young_list_max_and_target_length(); + uint update_young_list_max_and_target_length(size_t rs_lengths); // Update the young list target length either by setting it to the // desired fixed value or by calculating it using G1's pause // prediction model. If no rs_lengths parameter is passed, predict // the RS lengths using the prediction model, otherwise use the // given rs_lengths as the prediction. - void update_young_list_target_length(); - void update_young_list_target_length(size_t rs_lengths); + // Returns the unbounded young list target length. + uint update_young_list_target_length(size_t rs_lengths); // Calculate and return the minimum desired young list target // length. This is the minimum desired young list length according @@ -505,7 +526,10 @@ private: uint desired_min_length, uint desired_max_length) const; - uint bounded_young_list_target_length(size_t rs_lengths) const; + // Result of the bounded_young_list_target_length() method, containing both the + // bounded as well as the unbounded young list target lengths in this order. + typedef Pair YoungTargetLengths; + YoungTargetLengths young_list_target_lengths(size_t rs_lengths) const; void update_rs_lengths_prediction(); void update_rs_lengths_prediction(size_t prediction); @@ -536,10 +560,30 @@ private: // Sets up marking if proper conditions are met. void maybe_start_marking(); + + // The kind of STW pause. + enum PauseKind { + FullGC, + YoungOnlyGC, + MixedGC, + LastYoungGC, + InitialMarkGC, + Cleanup, + Remark + }; + + // Calculate PauseKind from internal state. + PauseKind young_gc_pause_kind() const; + // Record the given STW pause with the given start and end times (in s). + void record_pause(PauseKind kind, double start, double end); + // Indicate that we aborted marking before doing any mixed GCs. + void abort_time_to_mixed_tracking(); public: G1CollectorPolicy(); + virtual ~G1CollectorPolicy(); + virtual G1CollectorPolicy* as_g1_policy() { return this; } G1CollectorState* collector_state() const; diff --git a/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.cpp b/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.cpp index f984848b0cb..72a2217b0d5 100644 --- a/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.cpp @@ -57,6 +57,7 @@ const char* G1ErgoVerbose::to_string(int tag) { case ErgoConcCycles: return "Concurrent Cycles"; case ErgoMixedGCs: return "Mixed GCs"; case ErgoTiming: return "Timing"; + case ErgoIHOP: return "IHOP"; default: ShouldNotReachHere(); // Keep the Windows compiler happy diff --git a/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.hpp b/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.hpp index c36fe98521d..8021f46beaf 100644 --- a/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ErgoVerbose.hpp @@ -71,6 +71,7 @@ typedef enum { ErgoConcCycles, ErgoMixedGCs, ErgoTiming, + ErgoIHOP, ErgoHeuristicNum } ErgoHeuristic; diff --git a/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp b/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp new file mode 100644 index 00000000000..3574b478ecf --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1ErgoVerbose.hpp" +#include "gc/g1/g1IHOPControl.hpp" + +G1IHOPControl::G1IHOPControl(double initial_ihop_percent, size_t target_occupancy) : + _initial_ihop_percent(initial_ihop_percent), + _target_occupancy(target_occupancy), + _last_allocated_bytes(0), + _last_allocation_time_s(0.0) +{ + assert(_initial_ihop_percent >= 0.0 && _initial_ihop_percent <= 100.0, "Initial IHOP value must be between 0 and 100 but is %.3f", initial_ihop_percent); +} + +void G1IHOPControl::update_allocation_info(double allocation_time_s, size_t allocated_bytes, size_t additional_buffer_size) { + assert(allocation_time_s >= 0.0, "Allocation time must be positive but is %.3f", allocation_time_s); + + _last_allocation_time_s = allocation_time_s; + _last_allocated_bytes = allocated_bytes; +} + +void G1IHOPControl::print() { + size_t cur_conc_mark_start_threshold = get_conc_mark_start_threshold(); + ergo_verbose6(ErgoIHOP, + "basic information", + ergo_format_reason("value update") + ergo_format_byte_perc("threshold") + ergo_format_byte("target occupancy") + ergo_format_byte("current occupancy") + ergo_format_double("recent old gen allocation rate") + ergo_format_double("recent marking phase length"), + cur_conc_mark_start_threshold, + cur_conc_mark_start_threshold * 100.0 / _target_occupancy, + _target_occupancy, + G1CollectedHeap::heap()->used(), + _last_allocation_time_s > 0.0 ? _last_allocated_bytes / _last_allocation_time_s : 0.0, + last_marking_length_s()); +} + +G1StaticIHOPControl::G1StaticIHOPControl(double ihop_percent, size_t target_occupancy) : + G1IHOPControl(ihop_percent, target_occupancy), + _last_marking_length_s(0.0) { + assert(_target_occupancy > 0, "Target occupancy must be larger than zero."); +} + +#ifndef PRODUCT +static void test_update(G1IHOPControl* ctrl, double alloc_time, size_t alloc_amount, size_t young_size, double mark_time) { + for (int i = 0; i < 100; i++) { + ctrl->update_allocation_info(alloc_time, alloc_amount, young_size); + ctrl->update_marking_length(mark_time); + } +} + +void G1StaticIHOPControl::test() { + size_t const initial_ihop = 45; + + G1StaticIHOPControl ctrl(initial_ihop, 100); + + size_t threshold = ctrl.get_conc_mark_start_threshold(); + assert(threshold == initial_ihop, + "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold); + + ctrl.update_allocation_info(100.0, 100, 100); + threshold = ctrl.get_conc_mark_start_threshold(); + assert(threshold == initial_ihop, + "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold); + + ctrl.update_marking_length(1000.0); + threshold = ctrl.get_conc_mark_start_threshold(); + assert(threshold == initial_ihop, + "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold); + + // Whatever we pass, the IHOP value must stay the same. + test_update(&ctrl, 2, 10, 10, 3); + threshold = ctrl.get_conc_mark_start_threshold(); + assert(threshold == initial_ihop, + "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold); + + test_update(&ctrl, 12, 10, 10, 3); + threshold = ctrl.get_conc_mark_start_threshold(); + assert(threshold == initial_ihop, + "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold); +} + +void IHOP_test() { + G1StaticIHOPControl::test(); +} +#endif diff --git a/hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp b/hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp new file mode 100644 index 00000000000..cc71d8d4efa --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_G1_G1IHOPCONTROL_HPP +#define SHARE_VM_GC_G1_G1IHOPCONTROL_HPP + +#include "memory/allocation.hpp" + +// Base class for algorithms that calculate the heap occupancy at which +// concurrent marking should start. This heap usage threshold should be relative +// to old gen size. +class G1IHOPControl : public CHeapObj { + protected: + // The initial IHOP value relative to the target occupancy. + double _initial_ihop_percent; + // The target maximum occupancy of the heap. + size_t _target_occupancy; + + // Most recent complete mutator allocation period in seconds. + double _last_allocation_time_s; + // Amount of bytes allocated during _last_allocation_time_s. + size_t _last_allocated_bytes; + + // Initialize an instance with the initial IHOP value in percent and the target + // occupancy. The target occupancy is the number of bytes when marking should + // be finished and reclaim started. + G1IHOPControl(double initial_ihop_percent, size_t target_occupancy); + + // Most recent time from the end of the initial mark to the start of the first + // mixed gc. + virtual double last_marking_length_s() const = 0; + public: + virtual ~G1IHOPControl() { } + + // Get the current non-young occupancy at which concurrent marking should start. + virtual size_t get_conc_mark_start_threshold() = 0; + + // Update information about time during which allocations in the Java heap occurred, + // how large these allocations were in bytes, and an additional buffer. + // The allocations should contain any amount of space made unusable for further + // allocation, e.g. any waste caused by TLAB allocation, space at the end of + // humongous objects that can not be used for allocation, etc. + // Together with the target occupancy, this additional buffer should contain the + // difference between old gen size and total heap size at the start of reclamation, + // and space required for that reclamation. + virtual void update_allocation_info(double allocation_time_s, size_t allocated_bytes, size_t additional_buffer_size); + // Update the time spent in the mutator beginning from the end of initial mark to + // the first mixed gc. + virtual void update_marking_length(double marking_length_s) = 0; + + virtual void print(); +}; + +// The returned concurrent mark starting occupancy threshold is a fixed value +// relative to the maximum heap size. +class G1StaticIHOPControl : public G1IHOPControl { + // Most recent mutator time between the end of initial mark to the start of the + // first mixed gc. + double _last_marking_length_s; + protected: + double last_marking_length_s() const { return _last_marking_length_s; } + public: + G1StaticIHOPControl(double ihop_percent, size_t target_occupancy); + + size_t get_conc_mark_start_threshold() { return (size_t) (_initial_ihop_percent * _target_occupancy / 100.0); } + + virtual void update_marking_length(double marking_length_s) { + assert(marking_length_s > 0.0, "Marking length must be larger than zero but is %.3f", marking_length_s); + _last_marking_length_s = marking_length_s; + } + +#ifndef PRODUCT + static void test(); +#endif +}; + +#endif // SHARE_VM_GC_G1_G1IHOPCONTROL_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1InitialMarkToMixedTimeTracker.hpp b/hotspot/src/share/vm/gc/g1/g1InitialMarkToMixedTimeTracker.hpp new file mode 100644 index 00000000000..625e07311d4 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1InitialMarkToMixedTimeTracker.hpp @@ -0,0 +1,87 @@ +/* + * 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_G1INITIALMARKTOMIXEDTIMETRACKER_HPP +#define SHARE_VM_GC_G1_G1INITIALMARKTOMIXEDTIMETRACKER_HPP + +#include "utilities/globalDefinitions.hpp" +#include "utilities/debug.hpp" + +// Used to track time from the end of initial mark to the first mixed GC. +// After calling the initial mark/mixed gc notifications, the result can be +// obtained in last_marking_time() once, after which the tracking resets. +// Any pauses recorded by add_pause() will be subtracted from that results. +class G1InitialMarkToMixedTimeTracker VALUE_OBJ_CLASS_SPEC { +private: + bool _active; + double _initial_mark_end_time; + double _mixed_start_time; + double _total_pause_time; + + double wall_time() const { + return _mixed_start_time - _initial_mark_end_time; + } +public: + G1InitialMarkToMixedTimeTracker() { reset(); } + + // Record initial mark pause end, starting the time tracking. + void record_initial_mark_end(double end_time) { + assert(!_active, "Initial mark out of order."); + _initial_mark_end_time = end_time; + _active = true; + } + + // Record the first mixed gc pause start, ending the time tracking. + void record_mixed_gc_start(double start_time) { + if (_active) { + _mixed_start_time = start_time; + _active = false; + } + } + + double last_marking_time() { + assert(has_result(), "Do not have all measurements yet."); + double result = (_mixed_start_time - _initial_mark_end_time) - _total_pause_time; + reset(); + return result; + } + + void reset() { + _active = false; + _total_pause_time = 0.0; + _initial_mark_end_time = -1.0; + _mixed_start_time = -1.0; + } + + void add_pause(double time) { + if (_active) { + _total_pause_time += time; + } + } + + // Returns whether we have a result that can be retrieved. + bool has_result() const { return _mixed_start_time > 0.0 && _initial_mark_end_time > 0.0; } +}; + +#endif // SHARE_VM_GC_G1_G1INITIALMARKTOMIXEDTIMETRACKER_HPP diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 508cdd55af5..bb74bc023cc 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -3889,6 +3889,7 @@ void TestG1BiasedArray_test(); void TestBufferingOopClosure_test(); void TestCodeCacheRemSet_test(); void FreeRegionList_test(); +void IHOP_test(); void test_memset_with_concurrent_readers(); void TestPredictions_test(); void WorkerDataArray_test(); @@ -3937,6 +3938,7 @@ void execute_internal_vm_tests() { run_unit_test(TestCodeCacheRemSet_test()); if (UseG1GC) { run_unit_test(FreeRegionList_test()); + run_unit_test(IHOP_test()); } run_unit_test(test_memset_with_concurrent_readers()); run_unit_test(TestPredictions_test()); From 48264e46869fb2e98d4fd12162939fcddff60987 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 24 Nov 2015 10:35:52 +0100 Subject: [PATCH 069/260] 8136678: Implement adaptive sizing algorithm for IHOP Add adaptive sizing for IHOP that maximizes throughput (starts marking as late as possible). This functionality is enabled using a new -XX:+G1AdaptiveIHOP switch (default: false). Reviewed-by: mgerdin, jmasa, pliden --- .../src/share/vm/gc/g1/g1CollectorPolicy.cpp | 12 +- hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp | 176 ++++++++++++++++++ hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp | 52 ++++++ .../src/share/vm/gc/g1/g1RemSetSummary.cpp | 8 - hotspot/src/share/vm/gc/g1/g1_globals.hpp | 10 + .../share/vm/utilities/globalDefinitions.hpp | 7 + 6 files changed, 255 insertions(+), 10 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index b645876493e..2a69d6ae890 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -1239,8 +1239,16 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t } G1IHOPControl* G1CollectorPolicy::create_ihop_control() const { - return new G1StaticIHOPControl(InitiatingHeapOccupancyPercent, - G1CollectedHeap::heap()->max_capacity()); + if (G1UseAdaptiveIHOP) { + return new G1AdaptiveIHOPControl(InitiatingHeapOccupancyPercent, + G1CollectedHeap::heap()->max_capacity(), + &_predictor, + G1ReservePercent, + G1HeapWastePercent); + } else { + return new G1StaticIHOPControl(InitiatingHeapOccupancyPercent, + G1CollectedHeap::heap()->max_capacity()); + } } void G1CollectorPolicy::update_ihop_prediction(double mutator_time_s, diff --git a/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp b/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp index 3574b478ecf..29d48777101 100644 --- a/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp +++ b/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp @@ -26,6 +26,7 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ErgoVerbose.hpp" #include "gc/g1/g1IHOPControl.hpp" +#include "gc/g1/g1Predictions.hpp" G1IHOPControl::G1IHOPControl(double initial_ihop_percent, size_t target_occupancy) : _initial_ihop_percent(initial_ihop_percent), @@ -105,6 +106,181 @@ void G1StaticIHOPControl::test() { assert(threshold == initial_ihop, "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold); } +#endif + +G1AdaptiveIHOPControl::G1AdaptiveIHOPControl(double ihop_percent, + size_t initial_target_occupancy, + G1Predictions const* predictor, + size_t heap_reserve_percent, + size_t heap_waste_percent) : + G1IHOPControl(ihop_percent, initial_target_occupancy), + _predictor(predictor), + _marking_times_s(10, 0.95), + _allocation_rate_s(10, 0.95), + _last_unrestrained_young_size(0), + _heap_reserve_percent(heap_reserve_percent), + _heap_waste_percent(heap_waste_percent) +{ +} + +size_t G1AdaptiveIHOPControl::actual_target_threshold() const { + // The actual target threshold takes the heap reserve and the expected waste in + // free space into account. + // _heap_reserve is that part of the total heap capacity that is reserved for + // eventual promotion failure. + // _heap_waste is the amount of space will never be reclaimed in any + // heap, so can not be used for allocation during marking and must always be + // considered. + + double safe_total_heap_percentage = MIN2((double)(_heap_reserve_percent + _heap_waste_percent), 100.0); + + return MIN2( + G1CollectedHeap::heap()->max_capacity() * (100.0 - safe_total_heap_percentage) / 100.0, + _target_occupancy * (100.0 - _heap_waste_percent) / 100.0 + ); +} + +bool G1AdaptiveIHOPControl::have_enough_data_for_prediction() const { + return ((size_t)_marking_times_s.num() >= G1AdaptiveIHOPNumInitialSamples) && + ((size_t)_allocation_rate_s.num() >= G1AdaptiveIHOPNumInitialSamples); +} + +size_t G1AdaptiveIHOPControl::get_conc_mark_start_threshold() { + if (have_enough_data_for_prediction()) { + double pred_marking_time = _predictor->get_new_prediction(&_marking_times_s); + double pred_promotion_rate = _predictor->get_new_prediction(&_allocation_rate_s); + + size_t predicted_needed_bytes_during_marking = + (pred_marking_time * pred_promotion_rate + + _last_unrestrained_young_size); // In reality we would need the maximum size of the young gen during marking. This is a conservative estimate. + + size_t internal_threshold = actual_target_threshold(); + size_t predicted_initiating_threshold = predicted_needed_bytes_during_marking < internal_threshold ? + internal_threshold - predicted_needed_bytes_during_marking : + 0; + return predicted_initiating_threshold; + } else { + // Use the initial value. + return _initial_ihop_percent * _target_occupancy / 100.0; + } +} + +void G1AdaptiveIHOPControl::update_allocation_info(double allocation_time_s, size_t allocated_bytes, size_t additional_buffer_size) { + assert(allocation_time_s >= 0.0, "Allocation time must be positive but is %.3f", allocation_time_s); + double allocation_rate = (double) allocated_bytes / allocation_time_s; + _allocation_rate_s.add(allocation_rate); + + _last_allocation_bytes = allocated_bytes; + _last_unrestrained_young_size = additional_buffer_size; +} + +void G1AdaptiveIHOPControl::update_marking_length(double marking_length_s) { + assert(marking_length_s >= 0.0, "Marking length must be larger than zero but is %.3f", marking_length_s); + _marking_times_s.add(marking_length_s); +} + +void G1AdaptiveIHOPControl::print() { + ergo_verbose6(ErgoIHOP, + "basic information", + ergo_format_reason("value update") + ergo_format_byte_perc("threshold") + ergo_format_byte("target occupancy") + ergo_format_byte("current occupancy") + ergo_format_double("recent old gen allocation rate") + ergo_format_double("recent marking phase length"), + get_conc_mark_start_threshold(), + percent_of(get_conc_mark_start_threshold(), _target_occupancy), + _target_occupancy, + G1CollectedHeap::heap()->used(), + _allocation_rate_s.last(), + _marking_times_s.last() + ); + size_t actual_target = actual_target_threshold(); + ergo_verbose6(ErgoIHOP, + "adaptive IHOP information", + ergo_format_reason("value update") + ergo_format_byte_perc("threshold") + ergo_format_byte("internal target occupancy") + ergo_format_double("predicted old gen allocation rate") + ergo_format_double("predicted marking phase length") + ergo_format_str("prediction active"), + get_conc_mark_start_threshold(), + percent_of(get_conc_mark_start_threshold(), actual_target), + actual_target, + _predictor->get_new_prediction(&_allocation_rate_s), + _predictor->get_new_prediction(&_marking_times_s), + have_enough_data_for_prediction() ? "true" : "false" + ); +} + +#ifndef PRODUCT +void G1AdaptiveIHOPControl::test() { + size_t const initial_threshold = 45; + size_t const young_size = 10; + size_t const target_size = 100; + + // The final IHOP value is always + // target_size - (young_size + alloc_amount/alloc_time * marking_time) + + G1Predictions pred(0.95); + G1AdaptiveIHOPControl ctrl(initial_threshold, target_size, &pred, 0, 0); + + // First "load". + size_t const alloc_time1 = 2; + size_t const alloc_amount1 = 10; + size_t const marking_time1 = 2; + size_t const settled_ihop1 = target_size - (young_size + alloc_amount1/alloc_time1 * marking_time1); + + size_t threshold; + threshold = ctrl.get_conc_mark_start_threshold(); + assert(threshold == initial_threshold, + "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_threshold, threshold); + for (size_t i = 0; i < G1AdaptiveIHOPNumInitialSamples - 1; i++) { + ctrl.update_allocation_info(alloc_time1, alloc_amount1, young_size); + ctrl.update_marking_length(marking_time1); + // Not enough data yet. + threshold = ctrl.get_conc_mark_start_threshold(); + assert(threshold == initial_threshold, + "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_threshold, threshold); + } + + test_update(&ctrl, alloc_time1, alloc_amount1, young_size, marking_time1); + + threshold = ctrl.get_conc_mark_start_threshold(); + assert(threshold == settled_ihop1, + "Expected IHOP threshold to settle at " SIZE_FORMAT " but is " SIZE_FORMAT, settled_ihop1, threshold); + + // Second "load". A bit higher allocation rate. + size_t const alloc_time2 = 2; + size_t const alloc_amount2 = 30; + size_t const marking_time2 = 2; + size_t const settled_ihop2 = target_size - (young_size + alloc_amount2/alloc_time2 * marking_time2); + + test_update(&ctrl, alloc_time2, alloc_amount2, young_size, marking_time2); + + threshold = ctrl.get_conc_mark_start_threshold(); + assert(threshold < settled_ihop1, + "Expected IHOP threshold to settle at a value lower than " SIZE_FORMAT " but is " SIZE_FORMAT, settled_ihop1, threshold); + + // Third "load". Very high (impossible) allocation rate. + size_t const alloc_time3 = 1; + size_t const alloc_amount3 = 50; + size_t const marking_time3 = 2; + size_t const settled_ihop3 = 0; + + test_update(&ctrl, alloc_time3, alloc_amount3, young_size, marking_time3); + threshold = ctrl.get_conc_mark_start_threshold(); + + assert(threshold == settled_ihop3, + "Expected IHOP threshold to settle at " SIZE_FORMAT " but is " SIZE_FORMAT, settled_ihop3, threshold); + + // And back to some arbitrary value. + test_update(&ctrl, alloc_time2, alloc_amount2, young_size, marking_time2); + + threshold = ctrl.get_conc_mark_start_threshold(); + assert(threshold > settled_ihop3, + "Expected IHOP threshold to settle at value larger than " SIZE_FORMAT " but is " SIZE_FORMAT, settled_ihop3, threshold); +} void IHOP_test() { G1StaticIHOPControl::test(); diff --git a/hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp b/hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp index cc71d8d4efa..ee9c27213ea 100644 --- a/hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp +++ b/hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp @@ -26,6 +26,9 @@ #define SHARE_VM_GC_G1_G1IHOPCONTROL_HPP #include "memory/allocation.hpp" +#include "utilities/numberSeq.hpp" + +class G1Predictions; // Base class for algorithms that calculate the heap occupancy at which // concurrent marking should start. This heap usage threshold should be relative @@ -95,4 +98,53 @@ class G1StaticIHOPControl : public G1IHOPControl { #endif }; +// This algorithm tries to return a concurrent mark starting occupancy value that +// makes sure that during marking the given target occupancy is never exceeded, +// based on predictions of current allocation rate and time periods between +// initial mark and the first mixed gc. +class G1AdaptiveIHOPControl : public G1IHOPControl { + size_t _heap_reserve_percent; // Percentage of maximum heap capacity we should avoid to touch + size_t _heap_waste_percent; // Percentage of free heap that should be considered as waste. + + const G1Predictions * _predictor; + + TruncatedSeq _marking_times_s; + TruncatedSeq _allocation_rate_s; + + size_t _last_allocation_bytes; // Most recent mutator allocation since last GC. + // The most recent unrestrained size of the young gen. This is used as an additional + // factor in the calculation of the threshold, as the threshold is based on + // non-young gen occupancy at the end of GC. For the IHOP threshold, we need to + // consider the young gen size during that time too. + // Since we cannot know what young gen sizes are used in the future, we will just + // use the current one. We expect that this one will be one with a fairly large size, + // as there is no marking or mixed gc that could impact its size too much. + size_t _last_unrestrained_young_size; + + bool have_enough_data_for_prediction() const; + + // The "actual" target threshold the algorithm wants to keep during and at the + // end of marking. This is typically lower than the requested threshold, as the + // algorithm needs to consider restrictions by the environment. + size_t actual_target_threshold() const; + protected: + virtual double last_marking_length_s() const { return _marking_times_s.last(); } + public: + G1AdaptiveIHOPControl(double ihop_percent, + size_t initial_target_occupancy, + G1Predictions const* predictor, + size_t heap_reserve_percent, // The percentage of total heap capacity that should not be tapped into. + size_t heap_waste_percent); // The percentage of the free space in the heap that we think is not usable for allocation. + + virtual size_t get_conc_mark_start_threshold(); + + virtual void update_allocation_info(double allocation_time_s, size_t allocated_bytes, size_t additional_buffer_size); + virtual void update_marking_length(double marking_length_s); + + virtual void print(); +#ifndef PRODUCT + static void test(); +#endif +}; + #endif // SHARE_VM_GC_G1_G1IHOPCONTROL_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1RemSetSummary.cpp b/hotspot/src/share/vm/gc/g1/g1RemSetSummary.cpp index 474ce953482..2a9c9332770 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSetSummary.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSetSummary.cpp @@ -125,14 +125,6 @@ void G1RemSetSummary::subtract_from(G1RemSetSummary* other) { _sampling_thread_vtime = other->sampling_thread_vtime() - _sampling_thread_vtime; } -static double percent_of(size_t numerator, size_t denominator) { - if (denominator != 0) { - return (double)numerator / denominator * 100.0f; - } else { - return 0.0f; - } -} - static size_t round_to_K(size_t value) { return value / K; } diff --git a/hotspot/src/share/vm/gc/g1/g1_globals.hpp b/hotspot/src/share/vm/gc/g1/g1_globals.hpp index a23edc0a5da..6f7ac1fe840 100644 --- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp @@ -33,6 +33,16 @@ #define G1_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct, manageable, product_rw, range, constraint) \ \ + product(bool, G1UseAdaptiveIHOP, false, \ + "Adaptively adjust InitiatingHeapOccupancyPercent from the " \ + "initial value.") \ + \ + experimental(size_t, G1AdaptiveIHOPNumInitialSamples, 3, \ + "How many completed time periods from initial mark to first " \ + "mixed gc are required to use the input values for prediction " \ + "of the optimal occupancy to start marking.") \ + range(1, max_intx) \ + \ product(uintx, G1ConfidencePercent, 50, \ "Confidence level for MMU/pause predictions") \ range(0, 100) \ diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 5d8ea9b5129..2d6436ebece 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -565,6 +565,13 @@ inline double fabsd(double value) { return fabs(value); } +// Returns numerator/denominator as percentage value from 0 to 100. If denominator +// is zero, return 0.0. +template +inline double percent_of(T numerator, T denominator) { + return denominator != 0 ? (double)numerator / denominator * 100.0 : 0.0; +} + //---------------------------------------------------------------------------------------------------- // Special casts // Cast floats into same-size integers and vice-versa w/o changing bit-pattern From 5b86ad79e5dad512ae31dab7e075c0f558dfc762 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Tue, 24 Nov 2015 12:18:25 +0100 Subject: [PATCH 070/260] 8142336: Convert the SA agent build to modular build-infra makefiles Reviewed-by: ihse, sla, dsamersoff, twisti --- hotspot/make/Makefile | 4 +- hotspot/make/aix/Makefile | 9 - hotspot/make/aix/makefiles/buildtree.make | 14 +- hotspot/make/aix/makefiles/defs.make | 8 - hotspot/make/aix/makefiles/rules.make | 2 - hotspot/make/aix/makefiles/sa.make | 112 ------------ hotspot/make/aix/makefiles/saproc.make | 117 ------------- hotspot/make/aix/makefiles/top.make | 9 +- hotspot/make/aix/makefiles/vm.make | 9 +- hotspot/make/bsd/Makefile | 9 - hotspot/make/bsd/makefiles/buildtree.make | 14 +- hotspot/make/bsd/makefiles/defs.make | 72 ++------ hotspot/make/bsd/makefiles/rules.make | 2 - hotspot/make/bsd/makefiles/sa.make | 138 --------------- hotspot/make/bsd/makefiles/top.make | 9 +- hotspot/make/bsd/makefiles/vm.make | 17 +- .../make/gensrc/Gensrc-jdk.hotspot.agent.gmk | 47 +++++ hotspot/make/lib/Lib-jdk.hotspot.agent.gmk | 130 ++++++++++++++ hotspot/make/linux/Makefile | 9 - hotspot/make/linux/makefiles/buildtree.make | 14 +- hotspot/make/linux/makefiles/defs.make | 20 --- hotspot/make/linux/makefiles/rules.make | 2 - hotspot/make/linux/makefiles/sa.make | 115 ------------ hotspot/make/linux/makefiles/saproc.make | 127 -------------- hotspot/make/linux/makefiles/top.make | 9 +- hotspot/make/linux/makefiles/vm.make | 9 +- hotspot/make/sa.files | 133 -------------- hotspot/make/solaris/Makefile | 9 - hotspot/make/solaris/makefiles/buildtree.make | 14 +- hotspot/make/solaris/makefiles/defs.make | 10 -- hotspot/make/solaris/makefiles/rules.make | 2 - hotspot/make/solaris/makefiles/sa.make | 104 ----------- hotspot/make/solaris/makefiles/saproc.make | 151 ---------------- hotspot/make/solaris/makefiles/top.make | 9 +- hotspot/make/solaris/makefiles/vm.make | 9 +- hotspot/make/windows/build.make | 38 +--- hotspot/make/windows/build_vm_def.sh | 14 -- hotspot/make/windows/makefiles/debug.make | 6 +- hotspot/make/windows/makefiles/defs.make | 30 ---- hotspot/make/windows/makefiles/fastdebug.make | 6 +- hotspot/make/windows/makefiles/generated.make | 5 +- hotspot/make/windows/makefiles/product.make | 5 +- .../windows/makefiles/projectcreator.make | 6 +- hotspot/make/windows/makefiles/sa.make | 165 ------------------ hotspot/make/windows/makefiles/vm.make | 7 +- 45 files changed, 230 insertions(+), 1520 deletions(-) delete mode 100644 hotspot/make/aix/makefiles/sa.make delete mode 100644 hotspot/make/aix/makefiles/saproc.make delete mode 100644 hotspot/make/bsd/makefiles/sa.make create mode 100644 hotspot/make/gensrc/Gensrc-jdk.hotspot.agent.gmk create mode 100644 hotspot/make/lib/Lib-jdk.hotspot.agent.gmk delete mode 100644 hotspot/make/linux/makefiles/sa.make delete mode 100644 hotspot/make/linux/makefiles/saproc.make delete mode 100644 hotspot/make/sa.files delete mode 100644 hotspot/make/solaris/makefiles/sa.make delete mode 100644 hotspot/make/solaris/makefiles/saproc.make delete mode 100644 hotspot/make/windows/makefiles/sa.make diff --git a/hotspot/make/Makefile b/hotspot/make/Makefile index cf1a4167e18..91f5a9ae76e 100644 --- a/hotspot/make/Makefile +++ b/hotspot/make/Makefile @@ -44,9 +44,7 @@ # ALT_EXPORT_PATH Directory to export hotspot build to # ALT_JDK_IMPORT_PATH Current JDK build (only for create_jdk rules) # ALT_JDK_TARGET_IMPORT_PATH Current JDK build when cross-compiling -# ALT_BUILD_WIN_SA Building SA on Windows is disabled by default. -# Set ALT_BUILD_WIN_SA=1 to enable building SA on -# Windows. +# # Version strings and numbers: # JDK_VERSION Current JDK version (e.g. 1.6.0) # PREVIOUS_JDK_VERSION Previous (bootdir) JDK version (e.g. 1.5.0) diff --git a/hotspot/make/aix/Makefile b/hotspot/make/aix/Makefile index bbb92c9d75d..e8e679268f6 100644 --- a/hotspot/make/aix/Makefile +++ b/hotspot/make/aix/Makefile @@ -46,15 +46,6 @@ # # make REMOTE="rsh -l me myotherlinuxbox" -# Along with VM, Serviceability Agent (SA) is built for SA/JDI binding. -# JDI binding on SA produces two binaries: -# 1. sa-jdi.jar - This is built before building libjvm.so -# Please refer to ./makefiles/sa.make -# 2. libsa.so - Native library for SA - This is built after -# libjsig.so (signal interposition library) -# Please refer to ./makefiles/vm.make -# If $(GAMMADIR)/agent dir is not present, SA components are not built. - # No tests on Aix. TEST_IN_BUILD=false diff --git a/hotspot/make/aix/makefiles/buildtree.make b/hotspot/make/aix/makefiles/buildtree.make index aac5e3f2a8d..70755aa0c8e 100644 --- a/hotspot/make/aix/makefiles/buildtree.make +++ b/hotspot/make/aix/makefiles/buildtree.make @@ -50,7 +50,6 @@ # adlc.make - # trace.make - generate tracing event and type definitions # jvmti.make - generate JVMTI bindings from the spec (JSR-163) -# sa.make - generate SA jar file and natives # # The makefiles are split this way so that "make foo" will run faster by not # having to read the dependency files for the vm. @@ -125,7 +124,7 @@ SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS)) # For dependencies and recursive makes. BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make -BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make trace.make sa.make +BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make trace.make BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \ SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT) @@ -212,7 +211,6 @@ flags.make: $(BUILDTREE_MAKE) ../shared_dirs.lst echo "TARGET = $(TARGET)"; \ echo "HS_BUILD_VER = $(HS_BUILD_VER)"; \ echo "JRE_RELEASE_VER = $(JRE_RELEASE_VERSION)"; \ - echo "SA_BUILD_VERSION = $(HS_BUILD_VER)"; \ echo "HOTSPOT_BUILD_USER = $(HOTSPOT_BUILD_USER)"; \ echo "HOTSPOT_VM_DISTRO = $(HOTSPOT_VM_DISTRO)"; \ echo "OPENJDK = $(OPENJDK)"; \ @@ -351,16 +349,6 @@ trace.make: $(BUILDTREE_MAKE) echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \ ) > $@ -sa.make: $(BUILDTREE_MAKE) - @echo $(LOG_INFO) Creating $@ ... - $(QUIETLY) ( \ - $(BUILDTREE_COMMENT); \ - echo; \ - echo include flags.make; \ - echo; \ - echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \ - ) > $@ - FORCE: .PHONY: all FORCE diff --git a/hotspot/make/aix/makefiles/defs.make b/hotspot/make/aix/makefiles/defs.make index f902830eeb2..a8ce94d12fb 100644 --- a/hotspot/make/aix/makefiles/defs.make +++ b/hotspot/make/aix/makefiles/defs.make @@ -219,11 +219,3 @@ ifeq ($(JVM_VARIANT_CLIENT),true) # endif # endif endif - -# Serviceability Binaries -# No SA Support for PPC or zero -ADD_SA_BINARIES/ppc = -ADD_SA_BINARIES/ppc64 = -ADD_SA_BINARIES/zero = - -EXPORT_LIST += $(ADD_SA_BINARIES/$(HS_ARCH)) diff --git a/hotspot/make/aix/makefiles/rules.make b/hotspot/make/aix/makefiles/rules.make index 2c4c38658c6..effca45effa 100644 --- a/hotspot/make/aix/makefiles/rules.make +++ b/hotspot/make/aix/makefiles/rules.make @@ -103,8 +103,6 @@ BOOT_JAVA_HOME = $(JAVA_HOME) else # take from the PATH, if ALT_BOOTDIR, BOOTDIR and JAVA_HOME are not defined -# note that this is to support hotspot build without SA. To build -# SA along with hotspot, you need to define ALT_BOOTDIR, BOOTDIR or JAVA_HOME RUN.JAVA = java RUN.JAVAP = javap diff --git a/hotspot/make/aix/makefiles/sa.make b/hotspot/make/aix/makefiles/sa.make deleted file mode 100644 index ffd5edb00ca..00000000000 --- a/hotspot/make/aix/makefiles/sa.make +++ /dev/null @@ -1,112 +0,0 @@ -# -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. -# Copyright 2012, 2013 SAP AG. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -# This makefile (sa.make) is included from the sa.make in the -# build directories. - -# This makefile is used to build Serviceability Agent java code -# and generate JNI header file for native methods. - -include $(GAMMADIR)/make/aix/makefiles/rules.make - -include $(GAMMADIR)/make/defs.make - -AGENT_DIR = $(GAMMADIR)/agent - -include $(GAMMADIR)/make/sa.files - -TOPDIR = $(shell echo `pwd`) -GENERATED = $(TOPDIR)/../generated - -# tools.jar is needed by the JDI - SA binding -SA_CLASSPATH = $(BOOT_JAVA_HOME)/lib/tools.jar - -# TODO: if it's a modules image, check if SA module is installed. -MODULELIB_PATH= $(BOOT_JAVA_HOME)/lib/modules - -AGENT_FILES_LIST := $(GENERATED)/agent.classes.list - -SA_CLASSDIR = $(GENERATED)/saclasses - -SA_BUILD_VERSION_PROP = "sun.jvm.hotspot.runtime.VM.saBuildVersion=$(SA_BUILD_VERSION)" - -SA_PROPERTIES = $(SA_CLASSDIR)/sa.properties - -# if $(AGENT_DIR) does not exist, we don't build SA -# also, we don't build SA on Itanium, PowerPC, ARM or zero. - -all: - if [ -d $(AGENT_DIR) -a "$(SRCARCH)" != "ia64" \ - -a "$(SRCARCH)" != "arm" \ - -a "$(SRCARCH)" != "ppc" \ - -a "$(SRCARCH)" != "zero" ] ; then \ - $(MAKE) -f sa.make $(GENERATED)/sa-jdi.jar; \ - fi - -$(GENERATED)/sa-jdi.jar: $(AGENT_FILES) - $(QUIETLY) echo $(LOG_INFO) "Making $@" - $(QUIETLY) if [ "$(BOOT_JAVA_HOME)" = "" ]; then \ - echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ - exit 1; \ - fi - $(QUIETLY) if [ ! -f $(SA_CLASSPATH) -a ! -d $(MODULELIB_PATH) ] ; then \ - echo "Missing $(SA_CLASSPATH) file. Use 1.6.0 or later version of JDK";\ - echo ""; \ - exit 1; \ - fi - $(QUIETLY) if [ ! -d $(SA_CLASSDIR) ] ; then \ - mkdir -p $(SA_CLASSDIR); \ - fi -# Note: When indented, make tries to execute the '$(shell' comment. -# In some environments, cmd processors have limited line length. -# To prevent the javac invocation in the next block from using -# a very long cmd line, we use javac's @file-list option. We -# generate the file lists using make's built-in 'foreach' control -# flow which also avoids cmd processor line length issues. Since -# the 'foreach' is done as part of make's macro expansion phase, -# the initialization of the lists is also done in the same phase -# using '$(shell rm ...' instead of using the more traditional -# 'rm ...' rule. - $(shell rm -rf $(AGENT_FILES_LIST)) -# gnumake 3.78.1 does not accept the *'s that -# are in AGENT_FILES, so use the shell to expand them. -# Be extra carefull to not produce too long command lines in the shell! - $(foreach file,$(AGENT_FILES),$(shell ls -1 $(file) >> $(AGENT_FILES_LIST))) - $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -h $(GENERATED) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES_LIST) - $(QUIETLY) $(REMOTE) $(COMPILE.RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer - $(QUIETLY) echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) - $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql/sa.js - $(QUIETLY) $(CP) $(AGENT_SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql - $(QUIETLY) mkdir -p $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources - $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources/* - $(QUIETLY) $(CP) $(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources/ - $(QUIETLY) $(CP) -r $(AGENT_SRC_DIR)/images/* $(SA_CLASSDIR)/ - $(QUIETLY) $(REMOTE) $(RUN.JAR) cf $@ -C $(SA_CLASSDIR)/ . - $(QUIETLY) $(REMOTE) $(RUN.JAR) uf $@ -C $(AGENT_SRC_DIR) META-INF/services/com.sun.jdi.connect.Connector - -clean: - rm -rf $(SA_CLASSDIR) - rm -rf $(GENERATED)/sa-jdi.jar - rm -rf $(AGENT_FILES_LIST) diff --git a/hotspot/make/aix/makefiles/saproc.make b/hotspot/make/aix/makefiles/saproc.make deleted file mode 100644 index 509d8f621e4..00000000000 --- a/hotspot/make/aix/makefiles/saproc.make +++ /dev/null @@ -1,117 +0,0 @@ -# -# Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. -# Copyright 2012, 2013 SAP AG. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# -include $(GAMMADIR)/make/defs.make - -# Rules to build serviceability agent library, used by vm.make - -# libsaproc.so: serviceability agent - -SAPROC = saproc -LIBSAPROC = lib$(SAPROC).so - -LIBSAPROC_DEBUGINFO = lib$(SAPROC).debuginfo -LIBSAPROC_DIZ = lib$(SAPROC).diz - -AGENT_DIR = $(GAMMADIR)/agent - -SASRCDIR = $(AGENT_DIR)/src/os/$(Platform_os_family) - -SASRCFILES = $(SASRCDIR)/salibelf.c \ - $(SASRCDIR)/symtab.c \ - $(SASRCDIR)/libproc_impl.c \ - $(SASRCDIR)/ps_proc.c \ - $(SASRCDIR)/ps_core.c \ - $(SASRCDIR)/LinuxDebuggerLocal.c \ - -SAMAPFILE = $(SASRCDIR)/mapfile - -DEST_SAPROC = $(JDK_LIBDIR)/$(LIBSAPROC) -DEST_SAPROC_DEBUGINFO = $(JDK_LIBDIR)/$(LIBSAPROC_DEBUGINFO) -DEST_SAPROC_DIZ = $(JDK_LIBDIR)/$(LIBSAPROC_DIZ) - -# DEBUG_BINARIES overrides everything, use full -g debug information -ifeq ($(DEBUG_BINARIES), true) - SA_DEBUG_CFLAGS = -g -endif - -# if $(AGENT_DIR) does not exist, we don't build SA -# also, we don't build SA on Itanium, PPC, ARM or zero. - -ifneq ($(wildcard $(AGENT_DIR)),) -ifneq ($(filter-out ia64 arm ppc zero,$(SRCARCH)),) - BUILDLIBSAPROC = $(LIBSAPROC) -endif -endif - - -SA_LFLAGS = $(MAPFLAG:FILENAME=$(SAMAPFILE)) $(LDFLAGS_HASH_STYLE) - -$(LIBSAPROC): $(SASRCFILES) $(SAMAPFILE) - $(QUIETLY) if [ "$(BOOT_JAVA_HOME)" = "" ]; then \ - echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ - exit 1; \ - fi - @echo $(LOG_INFO) Making SA debugger back-end... - $(QUIETLY) $(CC) -D$(BUILDARCH) -D_GNU_SOURCE \ - -D_FILE_OFFSET_BITS=64 \ - $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ - $(BIN_UTILS) \ - -I$(SASRCDIR) \ - -I$(GENERATED) \ - -I$(BOOT_JAVA_HOME)/include \ - -I$(BOOT_JAVA_HOME)/include/$(Platform_os_family) \ - $(SASRCFILES) \ - $(SA_LFLAGS) \ - $(SA_DEBUG_CFLAGS) \ - -o $@ \ - -lthread_db -ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBSAPROC_DEBUGINFO) - $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBSAPROC_DEBUGINFO) $@ - ifeq ($(STRIP_POLICY),all_strip) - $(QUIETLY) $(STRIP) $@ - else - ifeq ($(STRIP_POLICY),min_strip) - $(QUIETLY) $(STRIP) -g $@ - # implied else here is no stripping at all - endif - endif - ifeq ($(ZIP_DEBUGINFO_FILES),1) - $(ZIPEXE) -q -y $(LIBSAPROC_DIZ) $(LIBSAPROC_DEBUGINFO) - $(RM) $(LIBSAPROC_DEBUGINFO) - endif -endif - -install_saproc: $(BUILDLIBSAPROC) - $(QUIETLY) if [ -e $(LIBSAPROC) ] ; then \ - echo "Copying $(LIBSAPROC) to $(DEST_SAPROC)"; \ - test -f $(LIBSAPROC_DEBUGINFO) && \ - $(CP) -f $(LIBSAPROC_DEBUGINFO) $(DEST_SAPROC_DEBUGINFO); \ - test -f $(LIBSAPROC_DIZ) && \ - $(CP) -f $(LIBSAPROC_DIZ) $(DEST_SAPROC_DIZ); \ - $(CP) -f $(LIBSAPROC) $(DEST_SAPROC) && echo "Done"; \ - fi - -.PHONY: install_saproc diff --git a/hotspot/make/aix/makefiles/top.make b/hotspot/make/aix/makefiles/top.make index bfe3c530955..fa9107c039d 100644 --- a/hotspot/make/aix/makefiles/top.make +++ b/hotspot/make/aix/makefiles/top.make @@ -28,7 +28,6 @@ # It also: # -builds and runs adlc via adlc.make # -generates JVMTI source and docs via jvmti.make (JSR-163) -# -generate sa-jdi.jar (JDI binding to core files) # It assumes the following flags are set: # CFLAGS Platform_file, Src_Dirs_I, Src_Dirs_V, SYSDEFS, AOUT, Obj_Files @@ -86,7 +85,7 @@ default: vm_build_preliminaries the_vm @echo All done. # This is an explicit dependency for the sake of parallel makes. -vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) trace_stuff jvmti_stuff sa_stuff +vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) trace_stuff jvmti_stuff @# We need a null action here, so implicit rules don't get consulted. $(Cached_plat): $(Plat_File) @@ -104,10 +103,6 @@ jvmti_stuff: $(Cached_plat) $(adjust-mflags) trace_stuff: jvmti_stuff $(Cached_plat) $(adjust-mflags) @$(MAKE) -f trace.make $(MFLAGS-adjusted) -# generate SA jar files and native header -sa_stuff: - @$(MAKE) -f sa.make $(MFLAGS-adjusted) - # and the VM: must use other makefile with dependencies included # We have to go to great lengths to get control over the -jN argument @@ -146,7 +141,7 @@ realclean: rm -fr $(GENERATED) .PHONY: default vm_build_preliminaries -.PHONY: lists ad_stuff jvmti_stuff sa_stuff the_vm clean realclean +.PHONY: lists ad_stuff jvmti_stuff the_vm clean realclean .PHONY: checks check_os_version install .NOTPARALLEL: diff --git a/hotspot/make/aix/makefiles/vm.make b/hotspot/make/aix/makefiles/vm.make index 11bb0294ede..e2c32f65eaa 100644 --- a/hotspot/make/aix/makefiles/vm.make +++ b/hotspot/make/aix/makefiles/vm.make @@ -61,7 +61,7 @@ Src_Dirs_I += $(GENERATED) # The order is important for the precompiled headers to work. INCLUDES += $(PRECOMPILED_HEADER_DIR:%=-I%) $(Src_Dirs_I:%=-I%) -# SYMFLAG is used by {jsig,saproc}.make +# SYMFLAG is used by jsig.make ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) # always build with debug info when we can create .debuginfo files SYMFLAG = -g @@ -359,13 +359,10 @@ install_jvm: $(LIBJVM) # Signal interposition library include $(MAKEFILES_DIR)/jsig.make -# Serviceability agent -include $(MAKEFILES_DIR)/saproc.make - #---------------------------------------------------------------------- -build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) $(BUILDLIBSAPROC) +build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) -install: install_jvm install_jsig install_saproc +install: install_jvm install_jsig .PHONY: default build install install_jvm diff --git a/hotspot/make/bsd/Makefile b/hotspot/make/bsd/Makefile index 4d45841475e..0eef9c08f58 100644 --- a/hotspot/make/bsd/Makefile +++ b/hotspot/make/bsd/Makefile @@ -45,15 +45,6 @@ # # make REMOTE="rsh -l me myotherlinuxbox" -# Along with VM, Serviceability Agent (SA) is built for SA/JDI binding. -# JDI binding on SA produces two binaries: -# 1. sa-jdi.jar - This is built before building libjvm.so -# Please refer to ./makefiles/sa.make -# 2. libsa.so - Native library for SA - This is built after -# libjsig.so (signal interposition library) -# Please refer to ./makefiles/vm.make -# If $(GAMMADIR)/agent dir is not present, SA components are not built. - ifeq ($(GAMMADIR),) include ../../make/defs.make else diff --git a/hotspot/make/bsd/makefiles/buildtree.make b/hotspot/make/bsd/makefiles/buildtree.make index e48d6aba104..0e2a80fec5e 100644 --- a/hotspot/make/bsd/makefiles/buildtree.make +++ b/hotspot/make/bsd/makefiles/buildtree.make @@ -49,7 +49,6 @@ # adlc.make - # trace.make - generate tracing event and type definitions # jvmti.make - generate JVMTI bindings from the spec (JSR-163) -# sa.make - generate SA jar file and natives # # The makefiles are split this way so that "make foo" will run faster by not # having to read the dependency files for the vm. @@ -130,7 +129,7 @@ SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS)) BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make # dtrace.make is used on BSD versions that implement Dtrace (like MacOS X) -BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make trace.make sa.make dtrace.make +BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make trace.make dtrace.make BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \ SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT) @@ -218,7 +217,6 @@ flags.make: $(BUILDTREE_MAKE) ../shared_dirs.lst echo "TARGET = $(TARGET)"; \ echo "HS_BUILD_VER = $(HS_BUILD_VER)"; \ echo "JRE_RELEASE_VER = $(JRE_RELEASE_VERSION)"; \ - echo "SA_BUILD_VERSION = $(HS_BUILD_VER)"; \ echo "HOTSPOT_BUILD_USER = $(HOTSPOT_BUILD_USER)"; \ echo "HOTSPOT_VM_DISTRO = $(HOTSPOT_VM_DISTRO)"; \ echo "OPENJDK = $(OPENJDK)"; \ @@ -360,16 +358,6 @@ trace.make: $(BUILDTREE_MAKE) echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \ ) > $@ -sa.make: $(BUILDTREE_MAKE) - @echo $(LOG_INFO) Creating $@ ... - $(QUIETLY) ( \ - $(BUILDTREE_COMMENT); \ - echo; \ - echo include flags.make; \ - echo; \ - echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \ - ) > $@ - dtrace.make: $(BUILDTREE_MAKE) @echo $(LOG_INFO) Creating $@ ... $(QUIETLY) ( \ diff --git a/hotspot/make/bsd/makefiles/defs.make b/hotspot/make/bsd/makefiles/defs.make index a418eeb8e1d..f168eacb50a 100644 --- a/hotspot/make/bsd/makefiles/defs.make +++ b/hotspot/make/bsd/makefiles/defs.make @@ -188,13 +188,13 @@ ifeq ($(JDK6_OR_EARLIER),0) ifneq ($(BUILD_FLAVOR),) # FULL_DEBUG_SYMBOLS not created for individual static libraries ifeq ($(STATIC_BUILD),false) - ifeq ($(BUILD_FLAVOR), product) - FULL_DEBUG_SYMBOLS ?= 1 - ENABLE_FULL_DEBUG_SYMBOLS = $(FULL_DEBUG_SYMBOLS) - else - # debug variants always get Full Debug Symbols (if available) - ENABLE_FULL_DEBUG_SYMBOLS = 1 - endif + ifeq ($(BUILD_FLAVOR), product) + FULL_DEBUG_SYMBOLS ?= 1 + ENABLE_FULL_DEBUG_SYMBOLS = $(FULL_DEBUG_SYMBOLS) + else + # debug variants always get Full Debug Symbols (if available) + ENABLE_FULL_DEBUG_SYMBOLS = 1 + endif endif $(eval $(call print_info, "ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS)")) # since objcopy is optional, we set ZIP_DEBUGINFO_FILES later @@ -260,11 +260,11 @@ JDK_INCLUDE_SUBDIR=bsd # Library suffix ifneq ($(STATIC_BUILD),true) - ifeq ($(OS_VENDOR),Darwin) - LIBRARY_SUFFIX=dylib - else - LIBRARY_SUFFIX=so - endif +ifeq ($(OS_VENDOR),Darwin) + LIBRARY_SUFFIX=dylib +else + LIBRARY_SUFFIX=so +endif else LIBRARY_SUFFIX=a endif @@ -275,7 +275,7 @@ EXPORT_LIST += $(EXPORT_DOCS_DIR)/platform/jvmti/jvmti.html # jsig library not needed for static builds ifneq ($(STATIC_BUILD),true) # client and server subdirectories have symbolic links to ../libjsig.so - EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libjsig.$(LIBRARY_SUFFIX) +EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libjsig.$(LIBRARY_SUFFIX) endif ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) @@ -342,47 +342,6 @@ ifeq ($(JVM_VARIANT_MINIMAL1),true) endif endif -# Serviceability Binaries -# No SA Support for PPC, IA64, ARM or zero -ADD_SA_BINARIES/x86 = $(EXPORT_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) \ - $(EXPORT_LIB_DIR)/sa-jdi.jar - -ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - ifeq ($(ZIP_DEBUGINFO_FILES),1) - ADD_SA_BINARIES/x86 += $(EXPORT_LIB_ARCH_DIR)/libsaproc.diz - else - ifeq ($(OS_VENDOR), Darwin) - ADD_SA_BINARIES/x86 += $(EXPORT_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX).dSYM - else - ADD_SA_BINARIES/x86 += $(EXPORT_LIB_ARCH_DIR)/libsaproc.debuginfo - endif - endif -endif - -ADD_SA_BINARIES/sparc = $(EXPORT_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) \ - $(EXPORT_LIB_DIR)/sa-jdi.jar -ADD_SA_BINARIES/universal = $(EXPORT_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) \ - $(EXPORT_LIB_DIR)/sa-jdi.jar - -ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - ifeq ($(ZIP_DEBUGINFO_FILES),1) - ADD_SA_BINARIES/universal += $(EXPORT_LIB_ARCH_DIR)/libsaproc.diz - else - ifeq ($(OS_VENDOR), Darwin) - ADD_SA_BINARIES/universal += $(EXPORT_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX).dSYM - else - ADD_SA_BINARIES/universal += $(EXPORT_LIB_ARCH_DIR)/libsaproc.debuginfo - endif - endif -endif - -ADD_SA_BINARIES/ppc = -ADD_SA_BINARIES/ia64 = -ADD_SA_BINARIES/arm = -ADD_SA_BINARIES/zero = - -EXPORT_LIST += $(ADD_SA_BINARIES/$(HS_ARCH)) - # Universal build settings ifeq ($(OS_VENDOR), Darwin) # Build universal binaries by default on Mac OS X @@ -409,9 +368,8 @@ ifeq ($(OS_VENDOR), Darwin) # Binaries to 'universalize' if built ifneq ($(STATIC_BUILD),true) - UNIVERSAL_LIPO_LIST += $(EXPORT_LIB_DIR)/libjsig.$(LIBRARY_SUFFIX) + UNIVERSAL_LIPO_LIST += $(EXPORT_LIB_DIR)/libjsig.$(LIBRARY_SUFFIX) endif - UNIVERSAL_LIPO_LIST += $(EXPORT_LIB_DIR)/libsaproc.$(LIBRARY_SUFFIX) UNIVERSAL_LIPO_LIST += $(EXPORT_LIB_DIR)/server/libjvm.$(LIBRARY_SUFFIX) UNIVERSAL_LIPO_LIST += $(EXPORT_LIB_DIR)/client/libjvm.$(LIBRARY_SUFFIX) @@ -430,12 +388,10 @@ ifeq ($(OS_VENDOR), Darwin) UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/server/libjvm.diz UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/client/libjvm.diz UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/libjsig.diz - UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/libsaproc.diz else UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/server/libjvm.$(LIBRARY_SUFFIX).dSYM UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/client/libjvm.$(LIBRARY_SUFFIX).dSYM UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/libjsig.$(LIBRARY_SUFFIX).dSYM - UNIVERSAL_COPY_LIST += $(EXPORT_LIB_DIR)/libsaproc.$(LIBRARY_SUFFIX).dSYM endif endif diff --git a/hotspot/make/bsd/makefiles/rules.make b/hotspot/make/bsd/makefiles/rules.make index d2334a70ffb..bb36f19a473 100644 --- a/hotspot/make/bsd/makefiles/rules.make +++ b/hotspot/make/bsd/makefiles/rules.make @@ -107,8 +107,6 @@ BOOT_JAVA_HOME = $(JAVA_HOME) else # take from the PATH, if ALT_BOOTDIR, BOOTDIR and JAVA_HOME are not defined -# note that this is to support hotspot build without SA. To build -# SA along with hotspot, you need to define ALT_BOOTDIR, BOOTDIR or JAVA_HOME RUN.JAVA = java RUN.JAVAP = javap diff --git a/hotspot/make/bsd/makefiles/sa.make b/hotspot/make/bsd/makefiles/sa.make deleted file mode 100644 index 0b8f9511260..00000000000 --- a/hotspot/make/bsd/makefiles/sa.make +++ /dev/null @@ -1,138 +0,0 @@ -# -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please 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 makefile (sa.make) is included from the sa.make in the -# build directories. - -define print_info - ifneq ($$(LOG_LEVEL), warn) - $$(shell echo >&2 "INFO: $1") - endif -endef - -# This makefile is used to build Serviceability Agent java code -# and generate JNI header file for native methods. - -include $(GAMMADIR)/make/bsd/makefiles/rules.make - -AGENT_DIR = $(GAMMADIR)/agent - -include $(GAMMADIR)/make/sa.files - --include $(HS_ALT_MAKE)/bsd/makefiles/sa.make - -TOPDIR = $(shell echo `pwd`) -GENERATED = $(TOPDIR)/../generated - -# SA-JDI depends on the standard JDI classes. -# Default SA_CLASSPATH location: -DEF_SA_CLASSPATH=$(BOOT_JAVA_HOME)/lib/tools.jar -ifeq ($(ALT_SA_CLASSPATH),) - # no alternate specified; see if default exists - SA_CLASSPATH=$(shell test -f $(DEF_SA_CLASSPATH) && echo $(DEF_SA_CLASSPATH)) - ifeq ($(SA_CLASSPATH),) - # the default doesn't exist - ifeq ($(OS_VENDOR), Darwin) - # A JDK from Apple doesn't have tools.jar; the JDI classes are - # are in the regular classes.jar file. - APPLE_JAR=$(BOOT_JAVA_HOME)/bundle/Classes/classes.jar - SA_CLASSPATH=$(shell test -f $(APPLE_JAR) && echo $(APPLE_JAR)) - endif - endif -else - $(eval $(call print_info, "ALT_SA_CLASSPATH=$(ALT_SA_CLASSPATH)")) - SA_CLASSPATH=$(shell test -f $(ALT_SA_CLASSPATH) && echo $(ALT_SA_CLASSPATH)) -endif - -ifneq ($(SA_CLASSPATH),) - SA_CLASSPATH_ARG := -classpath $(SA_CLASSPATH) -endif - -# TODO: if it's a modules image, check if SA module is installed. -MODULELIB_PATH= $(BOOT_JAVA_HOME)/lib/modules - -AGENT_FILES_LIST := $(GENERATED)/agent.classes.list - -SA_CLASSDIR = $(GENERATED)/saclasses - -SA_BUILD_VERSION_PROP = "sun.jvm.hotspot.runtime.VM.saBuildVersion=$(SA_BUILD_VERSION)" - -SA_PROPERTIES = $(SA_CLASSDIR)/sa.properties - -# if $(AGENT_DIR) does not exist, we don't build SA -# also, we don't build SA on Itanium, PowerPC, ARM or zero. - -all: - if [ -d $(AGENT_DIR) -a "$(SRCARCH)" != "ia64" \ - -a "$(SRCARCH)" != "arm" \ - -a "$(SRCARCH)" != "ppc" \ - -a "$(SRCARCH)" != "zero" ] ; then \ - $(MAKE) -f sa.make $(GENERATED)/sa-jdi.jar; \ - fi - -$(GENERATED)/sa-jdi.jar: $(AGENT_FILES) - $(QUIETLY) echo $(LOG_INFO) "Making $@" - $(QUIETLY) if [ "$(BOOT_JAVA_HOME)" = "" ]; then \ - echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ - exit 1; \ - fi - $(QUIETLY) if [ ! -f "$(SA_CLASSPATH)" -a ! -d $(MODULELIB_PATH) ] ; then \ - echo "Cannot find JDI classes. Use 1.6.0 or later version of JDK."; \ - echo ""; \ - exit 1; \ - fi - $(QUIETLY) if [ ! -d $(SA_CLASSDIR) ] ; then \ - mkdir -p $(SA_CLASSDIR); \ - fi -# Note: When indented, make tries to execute the '$(shell' comment. -# In some environments, cmd processors have limited line length. -# To prevent the javac invocation in the next block from using -# a very long cmd line, we use javac's @file-list option. We -# generate the file lists using make's built-in 'foreach' control -# flow which also avoids cmd processor line length issues. Since -# the 'foreach' is done as part of make's macro expansion phase, -# the initialization of the lists is also done in the same phase -# using '$(shell rm ...' instead of using the more traditional -# 'rm ...' rule. - $(shell rm -rf $(AGENT_FILES_LIST)) -# gnumake 3.78.1 does not accept the *'s that -# are in AGENT_FILES, so use the shell to expand them. -# Be extra carefull to not produce too long command lines in the shell! - $(foreach file,$(AGENT_FILES),$(shell ls -1 $(file) >> $(AGENT_FILES_LIST))) - $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -h $(GENERATED) $(SA_CLASSPATH_ARG) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES_LIST) - $(QUIETLY) $(REMOTE) $(COMPILE.RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer - $(QUIETLY) echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) - $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql/sa.js - $(QUIETLY) $(CP) $(AGENT_SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql - $(QUIETLY) mkdir -p $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources - $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources/* - $(QUIETLY) $(CP) $(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources/ - $(QUIETLY) $(CP) -r $(AGENT_SRC_DIR)/images/* $(SA_CLASSDIR)/ - $(QUIETLY) $(REMOTE) $(RUN.JAR) cf $@ -C $(SA_CLASSDIR)/ . - $(QUIETLY) $(REMOTE) $(RUN.JAR) uf $@ -C $(AGENT_SRC_DIR) META-INF/services/com.sun.jdi.connect.Connector - -clean: - rm -rf $(SA_CLASSDIR) - rm -rf $(GENERATED)/sa-jdi.jar - rm -rf $(AGENT_FILES_LIST) diff --git a/hotspot/make/bsd/makefiles/top.make b/hotspot/make/bsd/makefiles/top.make index 1df2d37fc67..47394d64a95 100644 --- a/hotspot/make/bsd/makefiles/top.make +++ b/hotspot/make/bsd/makefiles/top.make @@ -28,7 +28,6 @@ # It also: # -builds and runs adlc via adlc.make # -generates JVMTI source and docs via jvmti.make (JSR-163) -# -generate sa-jdi.jar (JDI binding to core files) # It assumes the following flags are set: # CFLAGS Platform_file, Src_Dirs_I, Src_Dirs_V, SYSDEFS, AOUT, Obj_Files @@ -86,7 +85,7 @@ default: vm_build_preliminaries the_vm @echo All done. # This is an explicit dependency for the sake of parallel makes. -vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) jvmti_stuff trace_stuff sa_stuff dtrace_stuff +vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) jvmti_stuff trace_stuff dtrace_stuff @# We need a null action here, so implicit rules don't get consulted. $(Cached_plat): $(Plat_File) @@ -113,10 +112,6 @@ dtrace_stuff: @# We need a null action here, so implicit rules don't get consulted. endif -# generate SA jar files and native header -sa_stuff: - @$(MAKE) -f sa.make $(MFLAGS-adjusted) - # and the VM: must use other makefile with dependencies included # We have to go to great lengths to get control over the -jN argument @@ -155,7 +150,7 @@ realclean: rm -fr $(GENERATED) .PHONY: default vm_build_preliminaries -.PHONY: lists ad_stuff jvmti_stuff sa_stuff the_vm clean realclean +.PHONY: lists ad_stuff jvmti_stuff the_vm clean realclean .PHONY: checks check_os_version install .NOTPARALLEL: diff --git a/hotspot/make/bsd/makefiles/vm.make b/hotspot/make/bsd/makefiles/vm.make index 71012e96193..f868a807eaa 100644 --- a/hotspot/make/bsd/makefiles/vm.make +++ b/hotspot/make/bsd/makefiles/vm.make @@ -60,7 +60,7 @@ Src_Dirs_I += $(GENERATED) # The order is important for the precompiled headers to work. INCLUDES += $(PRECOMPILED_HEADER_DIR:%=-I%) $(Src_Dirs_I:%=-I%) -# SYMFLAG is used by {jsig,saproc}.make +# SYMFLAG is used by jsig.make ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) # always build with debug info when we can create .dSYM/.debuginfo files SYMFLAG = -g @@ -299,9 +299,9 @@ else ifeq ($(OS_VENDOR), Darwin) ifneq ($(STATIC_BUILD),true) - LFLAGS_VM += -Xlinker -rpath -Xlinker @loader_path/. - LFLAGS_VM += -Xlinker -rpath -Xlinker @loader_path/.. - LFLAGS_VM += -Xlinker -install_name -Xlinker @rpath/$(@F) + LFLAGS_VM += -Xlinker -rpath -Xlinker @loader_path/. + LFLAGS_VM += -Xlinker -rpath -Xlinker @loader_path/.. + LFLAGS_VM += -Xlinker -install_name -Xlinker @rpath/$(@F) endif else LFLAGS_VM += -Wl,-z,defs @@ -421,19 +421,16 @@ endif # Signal interposition library include $(MAKEFILES_DIR)/jsig.make -# Serviceability agent -include $(MAKEFILES_DIR)/saproc.make - #---------------------------------------------------------------------- ifeq ($(OS_VENDOR), Darwin) # no libjvm_db for macosx -build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(BUILDLIBSAPROC) dtraceCheck $(EXPORTED_SYMBOLS) +build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) dtraceCheck $(EXPORTED_SYMBOLS) echo "Doing vm.make build:" else -build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) $(BUILDLIBSAPROC) $(EXPORTED_SYMBOLS) +build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) $(EXPORTED_SYMBOLS) endif -install: install_jvm install_jsig install_saproc +install: install_jvm install_jsigs .PHONY: default build install install_jvm diff --git a/hotspot/make/gensrc/Gensrc-jdk.hotspot.agent.gmk b/hotspot/make/gensrc/Gensrc-jdk.hotspot.agent.gmk new file mode 100644 index 00000000000..706804b87c5 --- /dev/null +++ b/hotspot/make/gensrc/Gensrc-jdk.hotspot.agent.gmk @@ -0,0 +1,47 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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. +# + +default: all + +include $(SPEC) +include MakeBase.gmk + +################################################################################ + +SA_PROPERTIES := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.hotspot.agent/sa.properties + +SA_BUILD_VERSION_PROP_NAME := "sun.jvm.hotspot.runtime.VM.saBuildVersion" + +$(SA_PROPERTIES): $(call DependOnVariable, FULL_VERSION) + $(MKDIR) -p $(@D) + $(ECHO) "$(SA_BUILD_VERSION_PROP_NAME)=$(FULL_VERSION)" > $@ + +TARGETS += $(SA_PROPERTIES) + +################################################################################ + +all: $(TARGETS) + +.PHONY: all default diff --git a/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk b/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk new file mode 100644 index 00000000000..1b9cba88c99 --- /dev/null +++ b/hotspot/make/lib/Lib-jdk.hotspot.agent.gmk @@ -0,0 +1,130 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. 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 NativeCompilation.gmk + +$(eval $(call IncludeCustomExtension, hotspot, lib/Lib-jdk.hotspot.agent.gmk)) + +################################################################################ + +SA_TOPDIR := $(HOTSPOT_TOPDIR)/agent + +# SA has a slightly different OS naming scheme +ifeq ($(OPENJDK_TARGET_OS), windows) + SA_TARGET_OS := win32 +else ifeq ($(OPENJDK_TARGET_OS), macosx) + SA_TARGET_OS := bsd +else + SA_TARGET_OS := $(OPENJDK_TARGET_OS) +endif + +# Defaults for most platforms +SA_TOOLCHAIN := TOOLCHAIN_DEFAULT +SA_NAME := saproc +SA_SRC += $(SA_TOPDIR)/src/share/native $(SA_TOPDIR)/src/os/$(SA_TARGET_OS) +SA_MAPFILE := $(SA_TOPDIR)/src/os/$(OPENJDK_TARGET_OS)/mapfile +SA_INCLUDES := \ + $(addprefix -I, $(SA_SRC)) \ + -I$(SUPPORT_OUTPUTDIR)/headers/jdk.hotspot.agent \ + -I$(HOTSPOT_TOPDIR)/src/os/$(OPENJDK_TARGET_OS) \ + # + +ifeq ($(OPENJDK_TARGET_CPU), x86_64) + SA_MACHINE_FLAG_windows := -machine:AMD64 +else ifeq ($(OPENJDK_TARGET_CPU), x86) + SA_MACHINE_FLAG_linux := -march=i586 + SA_MACHINE_FLAG_windows := -machine:I386 +endif + +ifeq ($(OPENJDK_TARGET_OS), linux) + SA_CFLAGS := $(CFLAGS_JDKLIB) -D_FILE_OFFSET_BITS=64 \ + $(SA_MACHINE_FLAG_linux) + SA_LDFLAGS := $(LDFLAGS_JDKLIB) $(SA_MACHINE_FLAG_linux) + SA_LIBS := -lthread_db $(LIBDL) + +else ifeq ($(OPENJDK_TARGET_OS), solaris) + SA_TOOLCHAIN := TOOLCHAIN_LINK_CXX + SA_MAPFILE := $(SA_TOPDIR)/src/os/solaris/proc/mapfile + COMMON_CFLAGS := -I$(SA_TOPDIR)/src/os/$(OPENJDK_TARGET_OS)/proc \ + -DSOLARIS_11_B159_OR_LATER + SA_CFLAGS := $(CFLAGS_JDKLIB) $(COMMON_CFLAGS) + SA_CXXFLAGS := $(CXXFLAGS_JDKLIB) $(COMMON_CFLAGS) + SA_LDFLAGS := $(subst -z defs,, $(LDFLAGS_JDKLIB)) \ + -mt $(LDFLAGS_CXX_JDK) + SA_LIBS := -ldl -ldemangle -lthread -lc + +else ifeq ($(OPENJDK_TARGET_OS), macosx) + SA_EXCLUDE_FILES := BsdDebuggerLocal.c ps_proc.c salibelf.c StubDebuggerLocal.c + SA_CFLAGS := $(CFLAGS_JDKLIB) \ + -Damd64 -D_GNU_SOURCE -mno-omit-leaf-frame-pointer \ + -mstack-alignment=1 -fPIC + SA_LDFLAGS := $(LDFLAGS_JDKLIB) + SA_LIBS := -framework Foundation -framework JavaNativeFoundation \ + -framework Security -framework CoreFoundation + +else ifeq ($(OPENJDK_TARGET_OS), windows) + SA_NAME := sawindbg + COMMON_CFLAGS := -D_WINDOWS -D_DEBUG -D_CONSOLE -D_MBCS -EHsc -FD + SA_CFLAGS := $(subst -DWIN32_LEAN_AND_MEAN,, $(CFLAGS_JDKLIB)) \ + $(COMMON_CFLAGS) + SA_CXXFLAGS := $(subst -DWIN32_LEAN_AND_MEAN,, $(CXXFLAGS_JDKLIB)) \ + $(COMMON_CFLAGS) + SA_LDFLAGS := $(LDFLAGS_JDKLIB) \ + $(SA_MACHINE_FLAG_windows) -manifest \ + -subsystem:console -map + SA_LIBS := dbgeng.lib + ifeq ($(OPENJDK_TARGET_CPU), x86_64) + SA_CXXFLAGS += -DWIN64 + else + SA_CXXFLAGS += -RTC1 -ZI + SA_LDFLAGS += -SAFESEH + endif +endif + +################################################################################ + +$(eval $(call SetupNativeCompilation, BUILD_LIBSA, \ + TOOLCHAIN := $(SA_TOOLCHAIN), \ + OPTIMIZATION := NONE, \ + DISABLED_WARNINGS_microsoft := 4267, \ + DISABLED_WARNINGS_gcc := sign-compare, \ + DISABLED_WARNINGS_CXX_solstudio := truncwarn unknownpragma, \ + LIBRARY := $(SA_NAME), \ + OUTPUT_DIR := $(call FindLibDirForModule, $(MODULE)), \ + SRC := $(SA_SRC), \ + EXCLUDE_FILES := test.c saproc_audit.cpp $(SA_EXCLUDE_FILES), \ + CFLAGS := $(SA_INCLUDES) $(SA_CFLAGS) $(SA_CUSTOM_CFLAGS), \ + CXXFLAGS := $(SA_INCLUDES) $(SA_CXXFLAGS) $(SA_CUSTOM_CXXFLAGS), \ + LDFLAGS := $(SA_LDFLAGS) $(SA_CUSTOM_LDFLAGS), \ + LIBS := $(SA_LIBS), \ + MAPFILE := $(SA_MAPFILE), \ + OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libsa, \ + DEBUG_SYMBOLS := true, \ + STRIP_SYMBOLS := true, \ +)) + +TARGETS += $(BUILD_LIBSA) + +################################################################################ diff --git a/hotspot/make/linux/Makefile b/hotspot/make/linux/Makefile index a447f5482cc..03c6393541e 100644 --- a/hotspot/make/linux/Makefile +++ b/hotspot/make/linux/Makefile @@ -45,15 +45,6 @@ # # make REMOTE="rsh -l me myotherlinuxbox" -# Along with VM, Serviceability Agent (SA) is built for SA/JDI binding. -# JDI binding on SA produces two binaries: -# 1. sa-jdi.jar - This is built before building libjvm.so -# Please refer to ./makefiles/sa.make -# 2. libsa.so - Native library for SA - This is built after -# libjsig.so (signal interposition library) -# Please refer to ./makefiles/vm.make -# If $(GAMMADIR)/agent dir is not present, SA components are not built. - ifeq ($(GAMMADIR),) include ../../make/defs.make else diff --git a/hotspot/make/linux/makefiles/buildtree.make b/hotspot/make/linux/makefiles/buildtree.make index 723f44e1f85..e60aae410ce 100644 --- a/hotspot/make/linux/makefiles/buildtree.make +++ b/hotspot/make/linux/makefiles/buildtree.make @@ -49,7 +49,6 @@ # adlc.make - # trace.make - generate tracing event and type definitions # jvmti.make - generate JVMTI bindings from the spec (JSR-163) -# sa.make - generate SA jar file and natives # # The makefiles are split this way so that "make foo" will run faster by not # having to read the dependency files for the vm. @@ -127,7 +126,7 @@ SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS)) # For dependencies and recursive makes. BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make -BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make trace.make sa.make dtrace.make +BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make trace.make dtrace.make BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \ SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT) @@ -219,7 +218,6 @@ flags.make: $(BUILDTREE_MAKE) ../shared_dirs.lst echo "TARGET = $(TARGET)"; \ echo "HS_BUILD_VER = $(HS_BUILD_VER)"; \ echo "JRE_RELEASE_VER = $(JRE_RELEASE_VERSION)"; \ - echo "SA_BUILD_VERSION = $(HS_BUILD_VER)"; \ echo "HOTSPOT_BUILD_USER = $(HOTSPOT_BUILD_USER)"; \ echo "HOTSPOT_VM_DISTRO = $(HOTSPOT_VM_DISTRO)"; \ echo "OPENJDK = $(OPENJDK)"; \ @@ -358,16 +356,6 @@ trace.make: $(BUILDTREE_MAKE) echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \ ) > $@ -sa.make: $(BUILDTREE_MAKE) - @echo $(LOG_INFO) Creating $@ ... - $(QUIETLY) ( \ - $(BUILDTREE_COMMENT); \ - echo; \ - echo include flags.make; \ - echo; \ - echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \ - ) > $@ - dtrace.make: $(BUILDTREE_MAKE) @echo $(LOG_INFO) Creating $@ ... $(QUIETLY) ( \ diff --git a/hotspot/make/linux/makefiles/defs.make b/hotspot/make/linux/makefiles/defs.make index 472621ffbea..dad86a239b9 100644 --- a/hotspot/make/linux/makefiles/defs.make +++ b/hotspot/make/linux/makefiles/defs.make @@ -293,24 +293,4 @@ ifeq ($(JVM_VARIANT_MINIMAL1),true) endif endif -# Serviceability Binaries - -ADD_SA_BINARIES/DEFAULT = $(EXPORT_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) \ - $(EXPORT_LIB_DIR)/sa-jdi.jar - -ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - ifeq ($(ZIP_DEBUGINFO_FILES),1) - ADD_SA_BINARIES/DEFAULT += $(EXPORT_LIB_ARCH_DIR)/libsaproc.diz - else - ADD_SA_BINARIES/DEFAULT += $(EXPORT_LIB_ARCH_DIR)/libsaproc.debuginfo - endif -endif - -ADD_SA_BINARIES/$(HS_ARCH) = $(ADD_SA_BINARIES/DEFAULT) - -# No SA Support for zero -ADD_SA_BINARIES/zero = - -include $(HS_ALT_MAKE)/linux/makefiles/defs.make - -EXPORT_LIST += $(ADD_SA_BINARIES/$(HS_ARCH)) diff --git a/hotspot/make/linux/makefiles/rules.make b/hotspot/make/linux/makefiles/rules.make index 596d5f423bd..82b952d2988 100644 --- a/hotspot/make/linux/makefiles/rules.make +++ b/hotspot/make/linux/makefiles/rules.make @@ -103,8 +103,6 @@ BOOT_JAVA_HOME = $(JAVA_HOME) else # take from the PATH, if ALT_BOOTDIR, BOOTDIR and JAVA_HOME are not defined -# note that this is to support hotspot build without SA. To build -# SA along with hotspot, you need to define ALT_BOOTDIR, BOOTDIR or JAVA_HOME RUN.JAVA = java RUN.JAVAP = javap diff --git a/hotspot/make/linux/makefiles/sa.make b/hotspot/make/linux/makefiles/sa.make deleted file mode 100644 index 0e9404928ef..00000000000 --- a/hotspot/make/linux/makefiles/sa.make +++ /dev/null @@ -1,115 +0,0 @@ -# -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please 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 makefile (sa.make) is included from the sa.make in the -# build directories. - -# This makefile is used to build Serviceability Agent java code -# and generate JNI header file for native methods. - -include $(GAMMADIR)/make/linux/makefiles/rules.make - -include $(GAMMADIR)/make/defs.make -include $(GAMMADIR)/make/altsrc.make - -AGENT_DIR = $(GAMMADIR)/agent - -include $(GAMMADIR)/make/sa.files - --include $(HS_ALT_MAKE)/linux/makefiles/sa.make - - -TOPDIR = $(shell echo `pwd`) -GENERATED = $(TOPDIR)/../generated - -# tools.jar is needed by the JDI - SA binding -SA_CLASSPATH = $(BOOT_JAVA_HOME)/lib/tools.jar - -# TODO: if it's a modules image, check if SA module is installed. -MODULELIB_PATH= $(BOOT_JAVA_HOME)/lib/modules - -AGENT_FILES_LIST := $(GENERATED)/agent.classes.list - -SA_CLASSDIR = $(GENERATED)/saclasses - -SA_BUILD_VERSION_PROP = "sun.jvm.hotspot.runtime.VM.saBuildVersion=$(SA_BUILD_VERSION)" - -SA_PROPERTIES = $(SA_CLASSDIR)/sa.properties - -# if $(AGENT_DIR) does not exist, we don't build SA -# also, we don't build SA on Itanium or zero. - -all: - if [ -d $(AGENT_DIR) -a "$(SRCARCH)" != "ia64" \ - -a "$(SRCARCH)" != "zero" ] ; then \ - $(MAKE) -f sa.make $(GENERATED)/sa-jdi.jar; \ - fi - -$(GENERATED)/sa-jdi.jar:: $(AGENT_FILES) - $(QUIETLY) echo $(LOG_INFO) "Making $@" - $(QUIETLY) if [ "$(BOOT_JAVA_HOME)" = "" ]; then \ - echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ - exit 1; \ - fi - $(QUIETLY) if [ ! -f $(SA_CLASSPATH) -a ! -d $(MODULELIB_PATH) ] ; then \ - echo "Missing $(SA_CLASSPATH) file. Use 1.6.0 or later version of JDK";\ - echo ""; \ - exit 1; \ - fi - $(QUIETLY) if [ ! -d $(SA_CLASSDIR) ] ; then \ - mkdir -p $(SA_CLASSDIR); \ - fi -# Note: When indented, make tries to execute the '$(shell' comment. -# In some environments, cmd processors have limited line length. -# To prevent the javac invocation in the next block from using -# a very long cmd line, we use javac's @file-list option. We -# generate the file lists using make's built-in 'foreach' control -# flow which also avoids cmd processor line length issues. Since -# the 'foreach' is done as part of make's macro expansion phase, -# the initialization of the lists is also done in the same phase -# using '$(shell rm ...' instead of using the more traditional -# 'rm ...' rule. - $(shell rm -rf $(AGENT_FILES_LIST)) -# gnumake 3.78.1 does not accept the *'s that -# are in AGENT_FILES, so use the shell to expand them. -# Be extra carefull to not produce too long command lines in the shell! - $(foreach file,$(AGENT_FILES),$(shell ls -1 $(file) >> $(AGENT_FILES_LIST))) - $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -h $(GENERATED) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES_LIST) - $(QUIETLY) $(REMOTE) $(COMPILE.RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer - $(QUIETLY) echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) - $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql/sa.js - $(QUIETLY) $(CP) $(AGENT_SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql - $(QUIETLY) mkdir -p $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources - $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources/* - $(QUIETLY) $(CP) $(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources/ - $(QUIETLY) $(CP) -r $(AGENT_SRC_DIR)/images/* $(SA_CLASSDIR)/ - $(QUIETLY) $(REMOTE) $(RUN.JAR) cf $@ -C $(SA_CLASSDIR)/ . - $(QUIETLY) $(REMOTE) $(RUN.JAR) uf $@ -C $(AGENT_SRC_DIR) META-INF/services/com.sun.jdi.connect.Connector - -clean: - rm -rf $(SA_CLASSDIR) - rm -rf $(GENERATED)/sa-jdi.jar - rm -rf $(AGENT_FILES_LIST) - --include $(HS_ALT_MAKE)/linux/makefiles/sa-rules.make diff --git a/hotspot/make/linux/makefiles/saproc.make b/hotspot/make/linux/makefiles/saproc.make deleted file mode 100644 index 15bdba1d396..00000000000 --- a/hotspot/make/linux/makefiles/saproc.make +++ /dev/null @@ -1,127 +0,0 @@ -# -# Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please 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 $(GAMMADIR)/make/defs.make -include $(GAMMADIR)/make/altsrc.make - -# Rules to build serviceability agent library, used by vm.make - -# libsaproc.so: serviceability agent - -SAPROC = saproc -LIBSAPROC = lib$(SAPROC).so - -LIBSAPROC_DEBUGINFO = lib$(SAPROC).debuginfo -LIBSAPROC_DIZ = lib$(SAPROC).diz - -AGENT_DIR = $(GAMMADIR)/agent - -SASRCDIR = $(AGENT_DIR)/src/os/$(Platform_os_family) - -SASRCFILES = $(SASRCDIR)/salibelf.c \ - $(SASRCDIR)/symtab.c \ - $(SASRCDIR)/libproc_impl.c \ - $(SASRCDIR)/ps_proc.c \ - $(SASRCDIR)/ps_core.c \ - $(SASRCDIR)/LinuxDebuggerLocal.c \ - $(AGENT_DIR)/src/share/native/sadis.c - --include $(HS_ALT_MAKE)/linux/makefiles/saproc.make - -SAMAPFILE = $(SASRCDIR)/mapfile - -DEST_SAPROC = $(JDK_LIBDIR)/$(LIBSAPROC) -DEST_SAPROC_DEBUGINFO = $(JDK_LIBDIR)/$(LIBSAPROC_DEBUGINFO) -DEST_SAPROC_DIZ = $(JDK_LIBDIR)/$(LIBSAPROC_DIZ) - -# DEBUG_BINARIES overrides everything, use full -g debug information -ifeq ($(DEBUG_BINARIES), true) - SA_DEBUG_CFLAGS = -g -endif - -# if $(AGENT_DIR) does not exist, we don't build SA -# also, we don't build SA on Itanium or zero. - -ifneq ($(wildcard $(AGENT_DIR)),) -ifneq ($(filter-out ia64 zero,$(SRCARCH)),) - BUILDLIBSAPROC = $(LIBSAPROC) -endif -endif - -ifneq ($(ALT_SASRCDIR),) -ALT_SAINCDIR=-I$(ALT_SASRCDIR) -DALT_SASRCDIR -else -ALT_SAINCDIR= -endif -SA_LFLAGS = $(MAPFLAG:FILENAME=$(SAMAPFILE)) $(LDFLAGS_HASH_STYLE) - -SAARCH ?= $(BUILDARCH) - -$(LIBSAPROC): $(SASRCFILES) $(SAMAPFILE) - $(QUIETLY) if [ "$(BOOT_JAVA_HOME)" = "" ]; then \ - echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ - exit 1; \ - fi - @echo $(LOG_INFO) Making SA debugger back-end... - $(QUIETLY) $(CC) -D$(SAARCH) -D_GNU_SOURCE \ - -D_FILE_OFFSET_BITS=64 \ - $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ - -I$(SASRCDIR) \ - -I$(GENERATED) \ - -I$(BOOT_JAVA_HOME)/include \ - -I$(BOOT_JAVA_HOME)/include/$(Platform_os_family) \ - $(ALT_SAINCDIR) \ - $(SASRCFILES) \ - $(SA_LFLAGS) \ - $(SA_DEBUG_CFLAGS) \ - $(EXTRA_CFLAGS) \ - -o $@ \ - -lthread_db -ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBSAPROC_DEBUGINFO) - $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBSAPROC_DEBUGINFO) $@ - ifeq ($(STRIP_POLICY),all_strip) - $(QUIETLY) $(STRIP) $@ - else - ifeq ($(STRIP_POLICY),min_strip) - $(QUIETLY) $(STRIP) -g $@ - # implied else here is no stripping at all - endif - endif - ifeq ($(ZIP_DEBUGINFO_FILES),1) - $(ZIPEXE) -q -y $(LIBSAPROC_DIZ) $(LIBSAPROC_DEBUGINFO) - $(RM) $(LIBSAPROC_DEBUGINFO) - endif -endif - -install_saproc: $(BUILDLIBSAPROC) - $(QUIETLY) if [ -e $(LIBSAPROC) ] ; then \ - echo "Copying $(LIBSAPROC) to $(DEST_SAPROC)"; \ - test ! -f $(LIBSAPROC_DEBUGINFO) || \ - $(CP) -f $(LIBSAPROC_DEBUGINFO) $(DEST_SAPROC_DEBUGINFO); \ - test ! -f $(LIBSAPROC_DIZ) || \ - $(CP) -f $(LIBSAPROC_DIZ) $(DEST_SAPROC_DIZ); \ - $(CP) -f $(LIBSAPROC) $(DEST_SAPROC) && echo "Done"; \ - fi - -.PHONY: install_saproc diff --git a/hotspot/make/linux/makefiles/top.make b/hotspot/make/linux/makefiles/top.make index 7659a3da2d6..d798d42851e 100644 --- a/hotspot/make/linux/makefiles/top.make +++ b/hotspot/make/linux/makefiles/top.make @@ -28,7 +28,6 @@ # It also: # -builds and runs adlc via adlc.make # -generates JVMTI source and docs via jvmti.make (JSR-163) -# -generate sa-jdi.jar (JDI binding to core files) # It assumes the following flags are set: # CFLAGS Platform_file, Src_Dirs_I, Src_Dirs_V, SYSDEFS, AOUT, Obj_Files @@ -86,7 +85,7 @@ default: vm_build_preliminaries the_vm @echo All done. # This is an explicit dependency for the sake of parallel makes. -vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) trace_stuff jvmti_stuff sa_stuff dtrace_stuff +vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) trace_stuff jvmti_stuff dtrace_stuff @# We need a null action here, so implicit rules don't get consulted. $(Cached_plat): $(Plat_File) @@ -104,10 +103,6 @@ jvmti_stuff: $(Cached_plat) $(adjust-mflags) trace_stuff: jvmti_stuff $(Cached_plat) $(adjust-mflags) @$(MAKE) -f trace.make $(MFLAGS-adjusted) -# generate SA jar files and native header -sa_stuff: - @$(MAKE) -f sa.make $(MFLAGS-adjusted) - dtrace_stuff: $(Cached_plat) $(adjust-mflags) @$(MAKE) -f dtrace.make dtrace_gen_headers $(MFLAGS-adjusted) GENERATED=$(GENERATED) @@ -149,7 +144,7 @@ realclean: rm -fr $(GENERATED) .PHONY: default vm_build_preliminaries -.PHONY: lists ad_stuff jvmti_stuff sa_stuff the_vm clean realclean +.PHONY: lists ad_stuff jvmti_stuff the_vm clean realclean .PHONY: checks check_os_version install .NOTPARALLEL: diff --git a/hotspot/make/linux/makefiles/vm.make b/hotspot/make/linux/makefiles/vm.make index 6f1cbe4e035..6c52118e37f 100644 --- a/hotspot/make/linux/makefiles/vm.make +++ b/hotspot/make/linux/makefiles/vm.make @@ -62,7 +62,7 @@ Src_Dirs_I += $(GENERATED) # The order is important for the precompiled headers to work. INCLUDES += $(PRECOMPILED_HEADER_DIR:%=-I%) $(Src_Dirs_I:%=-I%) -# SYMFLAG is used by {jsig,saproc}.make +# SYMFLAG is used by jsig.make ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) # always build with debug info when we can create .debuginfo files SYMFLAG = -g @@ -396,13 +396,10 @@ install_jvm: $(LIBJVM) # Signal interposition library include $(MAKEFILES_DIR)/jsig.make -# Serviceability agent -include $(MAKEFILES_DIR)/saproc.make - #---------------------------------------------------------------------- -build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) $(BUILDLIBSAPROC) dtraceCheck +build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) dtraceCheck -install: install_jvm install_jsig install_saproc +install: install_jvm install_jsig .PHONY: default build install install_jvm $(HS_ALT_MAKE)/$(Platform_os_family)/makefiles/$(BUILDARCH).make $(HS_ALT_MAKE)/$(Platform_os_family)/makefiles/vm.make diff --git a/hotspot/make/sa.files b/hotspot/make/sa.files deleted file mode 100644 index 7fb15bb29b8..00000000000 --- a/hotspot/make/sa.files +++ /dev/null @@ -1,133 +0,0 @@ -# -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please 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 filelist macro is included in platform specific sa.make -# included all packages/*.java. package list can be generated by -# $(GAMMADIR)/agent/make/build-pkglist. - -# define AGENT_DIR before including this file in sa.make - -AGENT_SRC_DIR = $(AGENT_DIR)/src/share/classes - -# Splitted the set of files into two sets because on linux plaform -# listing or compiling all the files results in 'Argument list too long' error. - -AGENT_FILES = \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/asm/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/asm/sparc/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/c1/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/ci/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/classfile/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/code/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/compiler/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/amd64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/aarch64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/bsd/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/bsd/amd64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/bsd/x86/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/basic/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/dummy/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/ia64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/amd64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/ia64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/ppc64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/aarch64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/x86/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/sparc/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/posix/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/posix/elf/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/ppc64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/amd64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/ppc64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/aarch64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/sparc/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/x86/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/amd64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/ppc64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/sparc/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/x86/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/aarch64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/sparc/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/win32/coff/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/amd64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/ia64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/x86/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windows/x86/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windows/amd64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/x86/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/gc/cms/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/gc/g1/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/gc/parallel/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/gc/serial/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/gc/shared/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/interpreter/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/jdi/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/memory/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/oops/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/opto/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/prims/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/amd64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/aarch64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/bsd/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/bsd_amd64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/bsd_x86/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_amd64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_aarch64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_x86/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_sparc/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_ppc64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/posix/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_amd64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_sparc/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_x86/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/sparc/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/x86/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/win32_amd64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/win32_x86/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/ppc64/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/jcore/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/soql/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/types/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/types/basic/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/utilities/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/utilities/memo/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/utilities/soql/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/action/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/classbrowser/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/table/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/tree/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/treetable/*.java \ -$(AGENT_SRC_DIR)/com/sun/java/swing/action/*.java \ -$(AGENT_SRC_DIR)/com/sun/java/swing/ui/*.java diff --git a/hotspot/make/solaris/Makefile b/hotspot/make/solaris/Makefile index f8fb06c8725..eb9bd2ab875 100644 --- a/hotspot/make/solaris/Makefile +++ b/hotspot/make/solaris/Makefile @@ -36,15 +36,6 @@ # or BOOTDIR has to be set. We do *not* search javac, javah, rmic etc. # from the PATH. -# Along with VM, Serviceability Agent (SA) is built for SA/JDI binding. -# JDI binding on SA produces two binaries: -# 1. sa-jdi.jar - This is built before building libjvm.so -# Please refer to ./makefiles/sa.make -# 2. libsaproc.so - Native library for SA - This is built after -# libjsig.so (signal interposition library) -# Please refer to ./makefiles/vm.make -# If $(GAMMADIR)/agent dir is not present, SA components are not built. - ifeq ($(GAMMADIR),) include ../../make/defs.make else diff --git a/hotspot/make/solaris/makefiles/buildtree.make b/hotspot/make/solaris/makefiles/buildtree.make index b1586d41132..dde03b5963f 100644 --- a/hotspot/make/solaris/makefiles/buildtree.make +++ b/hotspot/make/solaris/makefiles/buildtree.make @@ -49,7 +49,6 @@ # adlc.make - # trace.make - generate tracing event and type definitions # jvmti.make - generate JVMTI bindings from the spec (JSR-163) -# sa.make - generate SA jar file and natives # # The makefiles are split this way so that "make foo" will run faster by not # having to read the dependency files for the vm. @@ -117,7 +116,7 @@ SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS)) # For dependencies and recursive makes. BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make -BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make trace.make sa.make dtrace.make +BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make trace.make dtrace.make BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \ ARCH=$(ARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT) @@ -205,7 +204,6 @@ flags.make: $(BUILDTREE_MAKE) ../shared_dirs.lst echo "TARGET = $(TARGET)"; \ echo "HS_BUILD_VER = $(HS_BUILD_VER)"; \ echo "JRE_RELEASE_VER = $(JRE_RELEASE_VERSION)"; \ - echo "SA_BUILD_VERSION = $(HS_BUILD_VER)"; \ echo "HOTSPOT_BUILD_USER = $(HOTSPOT_BUILD_USER)"; \ echo "HOTSPOT_VM_DISTRO = $(HOTSPOT_VM_DISTRO)"; \ echo "OPENJDK = $(OPENJDK)"; \ @@ -344,16 +342,6 @@ trace.make: $(BUILDTREE_MAKE) echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \ ) > $@ -sa.make: $(BUILDTREE_MAKE) - @echo $(LOG_INFO) Creating $@ ... - $(QUIETLY) ( \ - $(BUILDTREE_COMMENT); \ - echo; \ - echo include flags.make; \ - echo; \ - echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \ - ) > $@ - dtrace.make: $(BUILDTREE_MAKE) @echo $(LOG_INFO) Creating $@ ... $(QUIETLY) ( \ diff --git a/hotspot/make/solaris/makefiles/defs.make b/hotspot/make/solaris/makefiles/defs.make index 8fa75e904d7..0ef3996d3dc 100644 --- a/hotspot/make/solaris/makefiles/defs.make +++ b/hotspot/make/solaris/makefiles/defs.make @@ -294,13 +294,3 @@ ifeq ($(JVM_VARIANT_CLIENT),true) endif endif endif - -EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libsaproc.$(LIBRARY_SUFFIX) -ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - ifeq ($(ZIP_DEBUGINFO_FILES),1) - EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libsaproc.diz - else - EXPORT_LIST += $(EXPORT_LIB_ARCH_DIR)/libsaproc.debuginfo - endif -endif -EXPORT_LIST += $(EXPORT_LIB_DIR)/sa-jdi.jar diff --git a/hotspot/make/solaris/makefiles/rules.make b/hotspot/make/solaris/makefiles/rules.make index e809b49f691..a35b9dacd8c 100644 --- a/hotspot/make/solaris/makefiles/rules.make +++ b/hotspot/make/solaris/makefiles/rules.make @@ -95,8 +95,6 @@ BOOT_JAVA_HOME = $(JAVA_HOME) else # take from the PATH, if ALT_BOOTDIR, BOOTDIR and JAVA_HOME are not defined -# note that this is to support hotspot build without SA. To build -# SA along with hotspot, you need to define ALT_BOOTDIR, BOOTDIR or JAVA_HOME RUN.JAVA = java RUN.JAVAP = javap diff --git a/hotspot/make/solaris/makefiles/sa.make b/hotspot/make/solaris/makefiles/sa.make deleted file mode 100644 index c2b9331d57d..00000000000 --- a/hotspot/make/solaris/makefiles/sa.make +++ /dev/null @@ -1,104 +0,0 @@ -# -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please 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 makefile (sa.make) is included from the sa.make in the -# build directories. - -# This makefile is used to build Serviceability Agent java code -# and generate JNI header file for native methods. - -include $(GAMMADIR)/make/solaris/makefiles/rules.make -include $(GAMMADIR)/make/defs.make -AGENT_DIR = $(GAMMADIR)/agent -include $(GAMMADIR)/make/sa.files - --include $(HS_ALT_MAKE)/solaris/makefiles/sa.make - -GENERATED = ../generated - -# tools.jar is needed by the JDI - SA binding -SA_CLASSPATH = $(BOOT_JAVA_HOME)/lib/tools.jar - -# TODO: if it's a modules image, check if SA module is installed. -MODULELIB_PATH= $(BOOT_JAVA_HOME)/lib/modules - -AGENT_FILES_LIST := $(GENERATED)/agent.classes.list - -SA_CLASSDIR = $(GENERATED)/saclasses - -SA_BUILD_VERSION_PROP = "sun.jvm.hotspot.runtime.VM.saBuildVersion=$(SA_BUILD_VERSION)" - -SA_PROPERTIES = $(SA_CLASSDIR)/sa.properties - -# if $(AGENT_DIR) does not exist, we don't build SA. -all: - $(QUIETLY) if [ -d $(AGENT_DIR) ] ; then \ - $(MAKE) -f sa.make $(GENERATED)/sa-jdi.jar; \ - fi - -$(GENERATED)/sa-jdi.jar: $(AGENT_FILES) - $(QUIETLY) echo $(LOG_INFO) "Making $@"; - $(QUIETLY) if [ "$(BOOT_JAVA_HOME)" = "" ]; then \ - echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ - exit 1; \ - fi - $(QUIETLY) if [ ! -f $(SA_CLASSPATH) -a ! -d $(MODULELIB_PATH) ] ; then \ - echo "Missing $(SA_CLASSPATH) file. Use 1.6.0 or later version of JDK";\ - echo ""; \ - exit 1; \ - fi - $(QUIETLY) if [ ! -d $(SA_CLASSDIR) ] ; then \ - mkdir -p $(SA_CLASSDIR); \ - fi -# Note: When indented, make tries to execute the '$(shell' comment. -# In some environments, cmd processors have limited line length. -# To prevent the javac invocation in the next block from using -# a very long cmd line, we use javac's @file-list option. We -# generate the file lists using make's built-in 'foreach' control -# flow which also avoids cmd processor line length issues. Since -# the 'foreach' is done as part of make's macro expansion phase, -# the initialization of the lists is also done in the same phase -# using '$(shell rm ...' instead of using the more traditional -# 'rm ...' rule. - $(shell rm -rf $(AGENT_FILES_LIST)) -# gnumake 3.78.1 does not accept the *'s that -# are in AGENT_FILES, so use the shell to expand them. -# Be extra carefull to not produce too long command lines in the shell! - $(foreach file,$(AGENT_FILES),$(shell ls -1 $(file) >> $(AGENT_FILES_LIST))) - $(QUIETLY) $(COMPILE.JAVAC) -h $(GENERATED) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES_LIST) - $(QUIETLY) $(COMPILE.RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer - $(QUIETLY) echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) - $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql/sa.js - $(QUIETLY) $(CP) $(AGENT_SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql - $(QUIETLY) mkdir -p $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources - $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources/* - $(QUIETLY) $(CP) $(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources/ - $(QUIETLY) $(CP) -r $(AGENT_SRC_DIR)/images/* $(SA_CLASSDIR)/ - $(QUIETLY) $(RUN.JAR) cf $@ -C $(SA_CLASSDIR)/ . - $(QUIETLY) $(RUN.JAR) uf $@ -C $(AGENT_SRC_DIR) META-INF/services/com.sun.jdi.connect.Connector - -clean: - rm -rf $(SA_CLASSDIR) - rm -rf $(GENERATED)/sa-jdi.jar - rm -rf $(AGENT_FILES_LIST) diff --git a/hotspot/make/solaris/makefiles/saproc.make b/hotspot/make/solaris/makefiles/saproc.make deleted file mode 100644 index 3daecc4f20c..00000000000 --- a/hotspot/make/solaris/makefiles/saproc.make +++ /dev/null @@ -1,151 +0,0 @@ -# -# Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -# Rules to build serviceability agent library, used by vm.make - -# libsaproc.so: serviceability agent - -SAPROC = saproc -SADIS = sadis -LIBSAPROC = lib$(SAPROC).so -SADISOBJ = $(SADIS).o - -LIBSAPROC_DEBUGINFO = lib$(SAPROC).debuginfo -LIBSAPROC_DIZ = lib$(SAPROC).diz - -AGENT_DIR = $(GAMMADIR)/agent - -SASRCDIR = $(AGENT_DIR)/src/os/$(Platform_os_family)/proc - -SASRCFILES = $(SASRCDIR)/saproc.cpp - -SADISSRCFILES = $(AGENT_DIR)/src/share/native/sadis.c - -SAMAPFILE = $(SASRCDIR)/mapfile - -DEST_SAPROC = $(JDK_LIBDIR)/$(LIBSAPROC) -DEST_SAPROC_DEBUGINFO = $(JDK_LIBDIR)/$(LIBSAPROC_DEBUGINFO) -DEST_SAPROC_DIZ = $(JDK_LIBDIR)/$(LIBSAPROC_DIZ) - -# if $(AGENT_DIR) does not exist, we don't build SA - -ifneq ($(wildcard $(AGENT_DIR)),) - BUILDLIBSAPROC = $(LIBSAPROC) -endif - -SA_LFLAGS = $(MAPFLAG:FILENAME=$(SAMAPFILE)) - -ifdef USE_GCC -SA_LFLAGS += -D_REENTRANT -else -SA_LFLAGS += -mt -xnolib -norunpath -endif - -# The libproc Pstack_iter() interface changed in Nevada-B159. -# Use 'uname -r -v' to determine the Solaris version as per -# Solaris Nevada team request. This logic needs to match: -# agent/src/os/solaris/proc/saproc.cpp: set_has_newer_Pstack_iter(): -# - skip SunOS 4 or older -# - skip Solaris 10 or older -# - skip two digit internal Nevada builds -# - skip three digit internal Nevada builds thru 149 -# - skip internal Nevada builds 150-158 -# - if not skipped, print define for Nevada-B159 or later -SOLARIS_11_B159_OR_LATER := \ -$(shell uname -r -v \ - | sed -n \ - -e '/^[0-4]\. /b' \ - -e '/^5\.[0-9] /b' \ - -e '/^5\.10 /b' \ - -e '/ snv_[0-9][0-9]$$/b' \ - -e '/ snv_[01][0-4][0-9]$$/b' \ - -e '/ snv_15[0-8]$$/b' \ - -e 's/.*/-DSOLARIS_11_B159_OR_LATER/' \ - -e 'p' \ - ) - -# Uncomment the following to simulate building on Nevada-B159 or later -# when actually building on Nevada-B158 or earlier: -#SOLARIS_11_B159_OR_LATER=-DSOLARIS_11_B159_OR_LATER - -$(SADISOBJ): $(SADISSRCFILES) - $(QUIETLY) $(CC) \ - $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ - -I$(SASRCDIR) \ - -I$(GENERATED) \ - -I$(BOOT_JAVA_HOME)/include \ - -I$(BOOT_JAVA_HOME)/include/$(Platform_os_family) \ - $(SOLARIS_11_B159_OR_LATER) \ - $(EXTRA_CFLAGS) \ - $(SADISSRCFILES) \ - -c -o $(SADISOBJ) - -$(LIBSAPROC): $(SASRCFILES) $(SADISOBJ) $(SAMAPFILE) - $(QUIETLY) if [ "$(BOOT_JAVA_HOME)" = "" ]; then \ - echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ - exit 1; \ - fi - @echo $(LOG_INFO) Making SA debugger back-end... - $(QUIETLY) $(CXX) \ - $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ - -I$(SASRCDIR) \ - -I$(GENERATED) \ - -I$(BOOT_JAVA_HOME)/include \ - -I$(BOOT_JAVA_HOME)/include/$(Platform_os_family) \ - $(SOLARIS_11_B159_OR_LATER) \ - $(EXTRA_CXXFLAGS) $(EXTRA_LDFLAGS) \ - $(SADISOBJ) \ - $(SASRCFILES) \ - $(SA_LFLAGS) \ - -o $@ \ - -ldl -ldemangle -lthread -lc - -ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBSAPROC_DEBUGINFO) - $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBSAPROC_DEBUGINFO) $@ - ifeq ($(STRIP_POLICY),all_strip) - $(QUIETLY) $(STRIP) $@ - else - ifeq ($(STRIP_POLICY),min_strip) - $(QUIETLY) $(STRIP) -x $@ - # implied else here is no stripping at all - endif - endif - ifeq ($(ZIP_DEBUGINFO_FILES),1) - $(ZIPEXE) -q -y $(LIBSAPROC_DIZ) $(LIBSAPROC_DEBUGINFO) - $(RM) $(LIBSAPROC_DEBUGINFO) - endif -endif - -install_saproc: $(BULDLIBSAPROC) - $(QUIETLY) if [ -f $(LIBSAPROC) ] ; then \ - echo "Copying $(LIBSAPROC) to $(DEST_SAPROC)"; \ - test ! -f $(LIBSAPROC_DEBUGINFO) || \ - $(CP) -f $(LIBSAPROC_DEBUGINFO) $(DEST_SAPROC_DEBUGINFO); \ - test ! -f $(LIBSAPROC_DIZ) || \ - $(CP) -f $(LIBSAPROC_DIZ) $(DEST_SAPROC_DIZ); \ - $(CP) -f $(LIBSAPROC) $(DEST_SAPROC) && echo "Done"; \ - fi - -.PHONY: install_saproc diff --git a/hotspot/make/solaris/makefiles/top.make b/hotspot/make/solaris/makefiles/top.make index 9b3bfa3ddbc..0786477af79 100644 --- a/hotspot/make/solaris/makefiles/top.make +++ b/hotspot/make/solaris/makefiles/top.make @@ -28,7 +28,6 @@ # It also: # -builds and runs adlc via adlc.make # -generates JVMTI source and docs via jvmti.make (JSR-163) -# -generate sa-jdi.jar (JDI binding to core files) # It assumes the following flags are set: # CFLAGS Platform_file, Src_Dirs_I, Src_Dirs_V, SYSDEFS, AOUT, Jvm_Obj_Files @@ -79,7 +78,7 @@ default: vm_build_preliminaries the_vm @echo All done. # This is an explicit dependency for the sake of parallel makes. -vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) jvmti_stuff trace_stuff sa_stuff dtrace_stuff +vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) jvmti_stuff trace_stuff dtrace_stuff @# We need a null action here, so implicit rules don't get consulted. $(Cached_plat): $(Plat_File) @@ -97,10 +96,6 @@ jvmti_stuff: $(Cached_plat) $(adjust-mflags) trace_stuff: jvmti_stuff $(Cached_plat) $(adjust-mflags) @$(MAKE) -f trace.make $(MFLAGS-adjusted) -# generate SA jar files and native header -sa_stuff: - @$(MAKE) -f sa.make $(MFLAGS-adjusted) - dtrace_stuff: $(Cached_plat) $(adjust-mflags) @$(MAKE) -f dtrace.make dtrace_gen_headers $(MFLAGS-adjusted) GENERATED=$(GENERATED) @@ -140,7 +135,7 @@ realclean: rm -fr $(GENERATED) .PHONY: default vm_build_preliminaries -.PHONY: lists ad_stuff jvmti_stuff trace_stuff sa_stuff the_vm clean realclean +.PHONY: lists ad_stuff jvmti_stuff trace_stuff the_vm clean realclean .PHONY: checks check_os_version install .NOTPARALLEL: diff --git a/hotspot/make/solaris/makefiles/vm.make b/hotspot/make/solaris/makefiles/vm.make index 799a3dbee69..875d176cc2a 100644 --- a/hotspot/make/solaris/makefiles/vm.make +++ b/hotspot/make/solaris/makefiles/vm.make @@ -55,7 +55,7 @@ VPATH += $(Src_Dirs_V:%=%:) Src_Dirs_I += $(GENERATED) INCLUDES += $(Src_Dirs_I:%=-I%) -# SYMFLAG is used by {dtrace,jsig,saproc}.make. +# SYMFLAG is used by {dtrace,jsig}.make. ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) # always build with debug info when we can create .debuginfo files # and disable 'lazy debug info' so the .so has everything. @@ -341,13 +341,10 @@ install_jvm: $(LIBJVM) # Signal interposition library include $(MAKEFILES_DIR)/jsig.make -# Serviceability agent -include $(MAKEFILES_DIR)/saproc.make - #---------------------------------------------------------------------- -build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) $(LIBJVM_DTRACE) $(BUILDLIBSAPROC) dtraceCheck +build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) $(LIBJVM_DTRACE) dtraceCheck -install: install_jvm install_jsig install_saproc +install: install_jvm install_jsig .PHONY: default build install install_jvm diff --git a/hotspot/make/windows/build.make b/hotspot/make/windows/build.make index cd4ae4fa938..564675333f1 100644 --- a/hotspot/make/windows/build.make +++ b/hotspot/make/windows/build.make @@ -30,14 +30,6 @@ # Note: Running nmake or build.bat from the Windows command shell requires # that "sh" be accessible on the PATH. An MKS install does this. -# SA components are built if BUILD_WIN_SA=1 is specified. -# See notes in README. This produces files: -# 1. sa-jdi.jar - This is built before building jvm.dll -# 2. sawindbg.dll - Native library for SA - This is built after jvm.dll -# - Also, .lib, .map, .pdb. -# -# Please refer to ./makefiles/sa.make - # If we haven't set an ARCH yet use x86 # create.bat and build.bat will set it, if used. !ifndef ARCH @@ -202,30 +194,6 @@ OPENJDK=true !endif !endif -# We don't support SA on ia64, and we can't -# build it if we are using a version of Vis Studio -# older than .Net 2003. -# SA_INCLUDE and SA_LIB are hold-overs from a previous -# implementation in which we could build SA using -# Debugging Tools For Windows, in which the .h/.lib files -# and the .dlls are in different places than -# they are for Vis Studio .Net 2003. -# If that code ever needs to be resurrected, these vars -# can be set here. They are used in makefiles/sa.make. - -checkSA:: - -!if "$(BUILD_WIN_SA)" != "1" -checkSA:: - @echo Not building SA: BUILD_WIN_SA != 1 - -!elseif "$(ARCH)" == "ia64" -BUILD_WIN_SA = 0 -checkSA:: - @echo Not building SA: ARCH = ia64 - -!endif # ! "$(BUILD_WIN_SA)" != "1" - ######################################################################### defaultTarget: product @@ -282,10 +250,6 @@ $(variantDir)\local.make: checks @ echo HS_COPYRIGHT=$(HOTSPOT_VM_COPYRIGHT) >> $@ @ echo HS_NAME=$(PRODUCT_NAME) $(JDK_MKTG_VERSION) >> $@ @ echo HS_BUILD_VER=$(HS_BUILD_VER) >> $@ - @ echo BUILD_WIN_SA=$(BUILD_WIN_SA) >> $@ - @ echo SA_BUILD_VERSION=$(HS_BUILD_VER) >> $@ - @ echo SA_INCLUDE=$(SA_INCLUDE) >> $@ - @ echo SA_LIB=$(SA_LIB) >> $@ @ echo JDK_VER=$(JDK_VER) >> $@ @ echo JDK_DOTVER=$(JDK_DOTVER) >> $@ @ echo JRE_RELEASE_VER=$(JRE_RELEASE_VER) >> $@ @@ -304,7 +268,7 @@ $(variantDir)\local.make: checks @ if "$(MV)" NEQ "" echo MV=$(MV) >> $@ @ if "$(ZIPEXE)" NEQ "" echo ZIPEXE=$(ZIPEXE) >> $@ -checks: checkVariant checkWorkSpace checkSA +checks: checkVariant checkWorkSpace checkVariant: @ if "$(Variant)"=="" echo Need to specify "Variant=[tiered|compiler2|compiler1|core]" && false diff --git a/hotspot/make/windows/build_vm_def.sh b/hotspot/make/windows/build_vm_def.sh index 05298eaa3f3..7224970058a 100644 --- a/hotspot/make/windows/build_vm_def.sh +++ b/hotspot/make/windows/build_vm_def.sh @@ -54,20 +54,6 @@ RM="$MKS_HOME/rm.exe" DUMPBIN="link.exe /dump" export VS_UNICODE_OUTPUT= -if [ "$1" = "-nosa" ]; then - echo EXPORTS > vm.def - echo "" - echo "***" - echo "*** Not building SA: BUILD_WIN_SA != 1" - echo "*** C++ Vtables NOT included in vm.def" - echo "*** This jvm.dll will NOT work properly with SA." - echo "***" - echo "*** When in doubt, set BUILD_WIN_SA=1, clean and rebuild." - echo "***" - echo "" - exit -fi - echo "EXPORTS" > vm1.def # When called from IDE the first param should contain the link version, otherwise may be nill diff --git a/hotspot/make/windows/makefiles/debug.make b/hotspot/make/windows/makefiles/debug.make index f4e54fc52fb..024881bfe43 100644 --- a/hotspot/make/windows/makefiles/debug.make +++ b/hotspot/make/windows/makefiles/debug.make @@ -19,13 +19,12 @@ # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# +# # HS_INTERNAL_NAME=jvm HS_FNAME=$(HS_INTERNAL_NAME).dll AOUT=$(HS_FNAME) -SAWINDBG=sawindbg.dll GENERATED=../generated # Allow the user to turn off precompiled headers from the command line. @@ -33,7 +32,7 @@ GENERATED=../generated BUILD_PCH_FILE=_build_pch_file.obj !endif -default:: $(BUILD_PCH_FILE) $(AOUT) checkAndBuildSA +default:: $(BUILD_PCH_FILE) $(AOUT) !include ../local.make !include compile.make @@ -67,4 +66,3 @@ $(AOUT): $(Res_Files) $(Obj_Files) vm.def !endif !include $(WorkSpace)/make/windows/makefiles/shared.make -!include $(WorkSpace)/make/windows/makefiles/sa.make diff --git a/hotspot/make/windows/makefiles/defs.make b/hotspot/make/windows/makefiles/defs.make index 5deb916e49c..86c7a32e808 100644 --- a/hotspot/make/windows/makefiles/defs.make +++ b/hotspot/make/windows/makefiles/defs.make @@ -236,21 +236,6 @@ else ifeq ($(USING_MINGW), true) ABS_OS_MAKEFILE := $(subst /,\\,$(shell $(CD) $(HS_MAKE_DIR)/$(OSNAME);$(PWD))/build.make) endif -# Disable building SA on windows until we are sure -# we want to release it. If we build it here, -# the SDK makefiles will copy it over and put it into -# the created image. -BUILD_WIN_SA = 1 -ifneq ($(ALT_BUILD_WIN_SA),) - BUILD_WIN_SA = $(ALT_BUILD_WIN_SA) -endif - -ifeq ($(BUILD_WIN_SA), 1) - ifeq ($(ARCH),ia64) - BUILD_WIN_SA = 0 - endif -endif - EXPORT_SERVER_DIR = $(EXPORT_BIN_DIR)/server EXPORT_CLIENT_DIR = $(EXPORT_BIN_DIR)/client @@ -281,21 +266,6 @@ endif EXPORT_LIST += $(EXPORT_LIB_DIR)/jvm.lib -ifeq ($(BUILD_WIN_SA), 1) - EXPORT_LIST += $(EXPORT_BIN_DIR)/sawindbg.$(LIBRARY_SUFFIX) - ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - ifeq ($(ZIP_DEBUGINFO_FILES),1) - EXPORT_LIST += $(EXPORT_BIN_DIR)/sawindbg.diz - else - EXPORT_LIST += $(EXPORT_BIN_DIR)/sawindbg.pdb - EXPORT_LIST += $(EXPORT_BIN_DIR)/sawindbg.map - endif - endif - EXPORT_LIST += $(EXPORT_LIB_DIR)/sa-jdi.jar - # Must pass this down to nmake. - MAKE_ARGS += BUILD_WIN_SA=1 -endif - # Propagate compiler and tools paths from configure to nmake. # Need to make sure they contain \\ and not /. ifneq ($(SPEC),) diff --git a/hotspot/make/windows/makefiles/fastdebug.make b/hotspot/make/windows/makefiles/fastdebug.make index e3138d0cb2f..34353b39271 100644 --- a/hotspot/make/windows/makefiles/fastdebug.make +++ b/hotspot/make/windows/makefiles/fastdebug.make @@ -19,13 +19,12 @@ # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# +# # HS_INTERNAL_NAME=jvm HS_FNAME=$(HS_INTERNAL_NAME).dll AOUT=$(HS_FNAME) -SAWINDBG=sawindbg.dll GENERATED=../generated # Allow the user to turn off precompiled headers from the command line. @@ -33,7 +32,7 @@ GENERATED=../generated BUILD_PCH_FILE=_build_pch_file.obj !endif -default:: $(BUILD_PCH_FILE) $(AOUT) checkAndBuildSA +default:: $(BUILD_PCH_FILE) $(AOUT) !include ../local.make !include compile.make @@ -66,4 +65,3 @@ $(AOUT): $(Res_Files) $(Obj_Files) vm.def !endif !include $(WorkSpace)/make/windows/makefiles/shared.make -!include $(WorkSpace)/make/windows/makefiles/sa.make diff --git a/hotspot/make/windows/makefiles/generated.make b/hotspot/make/windows/makefiles/generated.make index aaaa8e7c2b6..e376c7499cb 100644 --- a/hotspot/make/windows/makefiles/generated.make +++ b/hotspot/make/windows/makefiles/generated.make @@ -19,7 +19,7 @@ # Please 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 ../local.make @@ -34,9 +34,6 @@ JvmtiOutDir=jvmtifiles TraceOutDir=tracefiles !include $(WorkSpace)/make/windows/makefiles/trace.make -# Pick up rules for building SA -!include $(WorkSpace)/make/windows/makefiles/sa.make - AdlcOutDir=adfiles !if ("$(Variant)" == "compiler2") || ("$(Variant)" == "tiered") diff --git a/hotspot/make/windows/makefiles/product.make b/hotspot/make/windows/makefiles/product.make index c1ce35a163c..667101b0f21 100644 --- a/hotspot/make/windows/makefiles/product.make +++ b/hotspot/make/windows/makefiles/product.make @@ -19,7 +19,7 @@ # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# +# # HS_INTERNAL_NAME=jvm @@ -32,7 +32,7 @@ GENERATED=../generated BUILD_PCH_FILE=_build_pch_file.obj !endif -default:: $(BUILD_PCH_FILE) $(AOUT) checkAndBuildSA +default:: $(BUILD_PCH_FILE) $(AOUT) !include ../local.make !include compile.make @@ -69,4 +69,3 @@ $(AOUT): $(Res_Files) $(Obj_Files) vm.def !endif !include $(WorkSpace)/make/windows/makefiles/shared.make -!include $(WorkSpace)/make/windows/makefiles/sa.make diff --git a/hotspot/make/windows/makefiles/projectcreator.make b/hotspot/make/windows/makefiles/projectcreator.make index 180851d835e..97f04611464 100644 --- a/hotspot/make/windows/makefiles/projectcreator.make +++ b/hotspot/make/windows/makefiles/projectcreator.make @@ -90,10 +90,6 @@ ProjectCreatorIDEOptions = \ -disablePch getThread_windows_$(Platform_arch).cpp \ -disablePch_compiler2 opcodes.cpp -!if "$(BUILD_WIN_SA)" != "1" -BUILD_VM_DEF_FLAG=-nosa -!endif - # Common options for the IDE builds for c1, and c2 ProjectCreatorIDEOptions=\ $(ProjectCreatorIDEOptions) \ @@ -106,7 +102,7 @@ ProjectCreatorIDEOptions=\ -jdkTargetRoot $(HOTSPOTJDKDIST) \ -define ALIGN_STACK_FRAMES \ -define VM_LITTLE_ENDIAN \ - -prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) set JAVA_HOME=$(HOTSPOTJDKDIST) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(BUILD_VM_DEF_FLAG) $(LD_VER)" \ + -prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) set JAVA_HOME=$(HOTSPOTJDKDIST) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(LD_VER)" \ -ignoreFile jsig.c \ -ignoreFile jvmtiEnvRecommended.cpp \ -ignoreFile jvmtiEnvStub.cpp \ diff --git a/hotspot/make/windows/makefiles/sa.make b/hotspot/make/windows/makefiles/sa.make deleted file mode 100644 index 2e41a022534..00000000000 --- a/hotspot/make/windows/makefiles/sa.make +++ /dev/null @@ -1,165 +0,0 @@ -# -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please 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 makefile is used to build Serviceability Agent code -# and generate JNI header file for native methods. - -AGENT_DIR = $(WorkSpace)/agent -checkAndBuildSA:: - -!if "$(BUILD_WIN_SA)" != "1" -# Already warned about this in build.make -!else - -# This first part is used to build sa-jdi.jar -!include $(WorkSpace)/make/windows/makefiles/rules.make -!include $(WorkSpace)/make/sa.files - -GENERATED = ../generated - -HS_COMMON_SRC_REL = src - -!if "$(OPENJDK)" != "true" -HS_ALT_SRC_REL=src/closed -HS_ALT_SRC = $(WorkSpace)/$(HS_ALT_SRC_REL) -!ifndef HS_ALT_MAKE -HS_ALT_MAKE=$(WorkSpace)/make/closed -!endif -!endif - -HS_COMMON_SRC = $(WorkSpace)/$(HS_COMMON_SRC_REL) - -!ifdef HS_ALT_MAKE -!include $(HS_ALT_MAKE)/windows/makefiles/sa.make -!endif - -# tools.jar is needed by the JDI - SA binding -SA_CLASSPATH = $(BOOT_JAVA_HOME)/lib/tools.jar - -SA_CLASSDIR = $(GENERATED)/saclasses - -SA_BUILD_VERSION_PROP = sun.jvm.hotspot.runtime.VM.saBuildVersion=$(SA_BUILD_VERSION) - -SA_PROPERTIES = $(SA_CLASSDIR)/sa.properties - -default:: $(GENERATED)/sa-jdi.jar - -# Remove the space between $(SA_BUILD_VERSION_PROP) and > below as it adds a white space -# at the end of SA version string and causes a version mismatch with the target VM version. - -$(GENERATED)/sa-jdi.jar: $(AGENT_FILES) - $(QUIETLY) mkdir -p $(SA_CLASSDIR) - @echo ...Building sa-jdi.jar into $(SA_CLASSDIR) - @echo ...$(COMPILE_JAVAC) -classpath $(SA_CLASSPATH) -d $(SA_CLASSDIR) .... - @$(COMPILE_JAVAC) -h $(GENERATED) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES) - $(COMPILE_RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer - $(QUIETLY) echo $(SA_BUILD_VERSION_PROP)> $(SA_PROPERTIES) - $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql/sa.js - $(QUIETLY) $(CP) $(AGENT_SRC_DIR)/sun/jvm/hotspot/utilities/soql/sa.js $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql - $(QUIETLY) rm -rf $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources - $(QUIETLY) mkdir $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources - $(QUIETLY) $(CP) $(AGENT_SRC_DIR)/sun/jvm/hotspot/ui/resources/*.png $(SA_CLASSDIR)/sun/jvm/hotspot/ui/resources - $(QUIETLY) $(CP) -r $(AGENT_SRC_DIR)/images/* $(SA_CLASSDIR) - $(RUN_JAR) cf $@ -C $(SA_CLASSDIR) . - $(RUN_JAR) uf $@ -C $(AGENT_SRC_DIR) META-INF/services/com.sun.jdi.connect.Connector - - - -# This second part is used to build sawindbg.dll -# We currently build it the same way for product, debug, and fastdebug. - -SAWINDBG=sawindbg.dll - -# Resource file containing VERSIONINFO -SA_Res_Files=.\version.sares - -checkAndBuildSA:: $(SAWINDBG) - -# These do not need to be optimized (don't run a lot of code) and it -# will be useful to have the assertion checks in place - -!if "$(BUILDARCH)" == "ia64" -SA_CFLAGS = -nologo $(MS_RUNTIME_OPTION) -W3 $(GX_OPTION) -Od -D "WIN32" -D "WIN64" -D "_WINDOWS" -D "_DEBUG" -D "_CONSOLE" -D "_MBCS" -FD -c -!elseif "$(BUILDARCH)" == "amd64" -SA_CFLAGS = -nologo $(MS_RUNTIME_OPTION) -W3 $(GX_OPTION) -Od -D "WIN32" -D "WIN64" -D "_WINDOWS" -D "_DEBUG" -D "_CONSOLE" -D "_MBCS" -FD -c -!else -SA_CFLAGS = -nologo $(MS_RUNTIME_OPTION) -W3 $(GX_OPTION) -Od -D "WIN32" -D "_WINDOWS" -D "_DEBUG" -D "_CONSOLE" -D "_MBCS" -FD -RTC1 -c -!if "$(ENABLE_FULL_DEBUG_SYMBOLS)" == "1" -SA_CFLAGS = $(SA_CFLAGS) -ZI -!endif -!endif -!if "$(MT)" != "" -SA_LD_FLAGS = -manifest $(SA_LD_FLAGS) -!endif - -SASRCFILES = $(AGENT_DIR)/src/os/win32/windbg/sawindbg.cpp \ - $(AGENT_DIR)/src/share/native/sadis.c - -SA_LFLAGS = $(SA_LD_FLAGS) -nologo -subsystem:console -machine:$(MACHINE) -!if "$(ENABLE_FULL_DEBUG_SYMBOLS)" == "1" -SA_LFLAGS = $(SA_LFLAGS) -map -debug -!endif -!if "$(BUILDARCH)" == "i486" -SA_LFLAGS = /SAFESEH $(SA_LFLAGS) -!endif - -SA_CFLAGS = $(SA_CFLAGS) $(MP_FLAG) - -# Note that we do not keep sawindbj.obj around as it would then -# get included in the dumpbin command in build_vm_def.sh - -# Force resources to be rebuilt every time -$(SA_Res_Files): FORCE - -# In VS2005 or VS2008 the link command creates a .manifest file that we want -# to insert into the linked artifact so we do not need to track it separately. -# Use ";#2" for .dll and ";#1" for .exe in the MT command below: -$(SAWINDBG): $(SASRCFILES) $(SA_Res_Files) - set INCLUDE=$(SA_INCLUDE)$(INCLUDE) - $(CXX) @<< - -I"$(BootStrapDir)/include" -I"$(BootStrapDir)/include/win32" - -I"$(GENERATED)" $(SA_CFLAGS) - $(SASRCFILES) - -out:$*.obj -<< - set LIB=$(SA_LIB)$(LIB) - $(LD) -out:$@ -DLL sawindbg.obj sadis.obj dbgeng.lib $(SA_LFLAGS) $(SA_Res_Files) -!if "$(MT)" != "" - $(MT) -manifest $(@F).manifest -outputresource:$(@F);#2 -!endif -!if "$(ENABLE_FULL_DEBUG_SYMBOLS)" == "1" -!if "$(ZIP_DEBUGINFO_FILES)" == "1" - $(ZIPEXE) -q $*.diz $*.map $*.pdb - $(RM) $*.map $*.pdb -!endif -!endif - -@rm -f $*.obj - -{$(COMMONSRC)\os\windows\vm}.rc.sares: - @$(RC) $(RC_FLAGS) /D "HS_FNAME=$(SAWINDBG)" /fo"$@" $< - -cleanall : - rm -rf $(GENERATED)/saclasses - rm -rf $(GENERATED)/sa-jdi.jar -!endif diff --git a/hotspot/make/windows/makefiles/vm.make b/hotspot/make/windows/makefiles/vm.make index 9381c5b097d..957cb86776a 100644 --- a/hotspot/make/windows/makefiles/vm.make +++ b/hotspot/make/windows/makefiles/vm.make @@ -408,10 +408,5 @@ _build_pch_file.obj: @echo #include "precompiled.hpp" > ../generated/_build_pch_file.cpp $(CXX) $(CXX_FLAGS) /Fp"vm.pch" /Yc"precompiled.hpp" /c ../generated/_build_pch_file.cpp -!if "$(BUILD_WIN_SA)" != "1" -BUILD_VM_DEF_FLAG=-nosa -!endif - vm.def: $(Obj_Files) - sh $(WorkSpace)/make/windows/build_vm_def.sh $(BUILD_VM_DEF_FLAG) - + sh $(WorkSpace)/make/windows/build_vm_def.sh From e09cadb438309ad516fc0fa82bf66ff4a5dd203b Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Tue, 24 Nov 2015 11:49:44 +0000 Subject: [PATCH 071/260] 8140687: Move @Contended to the jdk.internal.vm.annotation package Reviewed-by: alanb, dholmes, psandoz, shade --- hotspot/src/share/vm/classfile/classFileParser.cpp | 6 +++--- hotspot/src/share/vm/classfile/classFileParser.hpp | 4 ++-- hotspot/src/share/vm/classfile/vmSymbols.hpp | 2 +- hotspot/test/runtime/contended/Basic.java | 2 +- hotspot/test/runtime/contended/DefaultValue.java | 2 +- hotspot/test/runtime/contended/HasNonStatic.java | 2 +- hotspot/test/runtime/contended/Inheritance1.java | 2 +- hotspot/test/runtime/contended/OopMaps.java | 2 +- hotspot/test/runtime/contended/OopMapsSameGroup.java | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index c9296533878..aa788362bc7 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -1693,7 +1693,7 @@ void ClassFileParser::parse_annotations(u1* buffer, int limit, if (id == AnnotationCollector::_unknown) continue; coll->set_annotation(id); - if (id == AnnotationCollector::_sun_misc_Contended) { + if (id == AnnotationCollector::_jdk_internal_vm_annotation_Contended) { // @Contended can optionally specify the contention group. // // Contended group defines the equivalence class over the fields: @@ -1767,10 +1767,10 @@ ClassFileParser::AnnotationCollector::annotation_index(ClassLoaderData* loader_d if (_location != _in_field) break; // only allow for fields if (!privileged) break; // only allow in privileged code return _field_Stable; - case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_misc_Contended_signature): + case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_Contended_signature): if (_location != _in_field && _location != _in_class) break; // only allow for fields and classes if (!EnableContended || (RestrictContended && !privileged)) break; // honor privileges - return _sun_misc_Contended; + return _jdk_internal_vm_annotation_Contended; default: break; } return AnnotationCollector::_unknown; diff --git a/hotspot/src/share/vm/classfile/classFileParser.hpp b/hotspot/src/share/vm/classfile/classFileParser.hpp index fc9b7a0c179..ec7ea19cba2 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.hpp +++ b/hotspot/src/share/vm/classfile/classFileParser.hpp @@ -131,7 +131,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { _method_LambdaForm_Compiled, _method_LambdaForm_Hidden, _method_HotSpotIntrinsicCandidate, - _sun_misc_Contended, + _jdk_internal_vm_annotation_Contended, _field_Stable, _annotation_LIMIT }; @@ -164,7 +164,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { void set_contended_group(u2 group) { _contended_group = group; } u2 contended_group() const { return _contended_group; } - bool is_contended() const { return has_annotation(_sun_misc_Contended); } + bool is_contended() const { return has_annotation(_jdk_internal_vm_annotation_Contended); } void set_stable(bool stable) { set_annotation(_field_Stable); } bool is_stable() const { return has_annotation(_field_Stable); } diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 9b4470f82d8..dc31c3b3527 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -210,7 +210,7 @@ template(java_util_concurrent_atomic_AtomicLongFieldUpdater_CASUpdater, "java/util/concurrent/atomic/AtomicLongFieldUpdater$CASUpdater") \ template(java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater, "java/util/concurrent/atomic/AtomicLongFieldUpdater$LockedUpdater") \ template(java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl, "java/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl") \ - template(sun_misc_Contended_signature, "Lsun/misc/Contended;") \ + template(jdk_internal_vm_annotation_Contended_signature, "Ljdk/internal/vm/annotation/Contended;") \ \ /* class symbols needed by intrinsics */ \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, template, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) \ diff --git a/hotspot/test/runtime/contended/Basic.java b/hotspot/test/runtime/contended/Basic.java index ddc685e4ff2..3ce7eb20e82 100644 --- a/hotspot/test/runtime/contended/Basic.java +++ b/hotspot/test/runtime/contended/Basic.java @@ -36,7 +36,7 @@ import java.util.regex.Pattern; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import sun.misc.Unsafe; -import sun.misc.Contended; +import jdk.internal.vm.annotation.Contended; /* * @test diff --git a/hotspot/test/runtime/contended/DefaultValue.java b/hotspot/test/runtime/contended/DefaultValue.java index 05cc698f3ef..a121c7a63e9 100644 --- a/hotspot/test/runtime/contended/DefaultValue.java +++ b/hotspot/test/runtime/contended/DefaultValue.java @@ -36,7 +36,7 @@ import java.util.regex.Pattern; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import sun.misc.Unsafe; -import sun.misc.Contended; +import jdk.internal.vm.annotation.Contended; /* * @test diff --git a/hotspot/test/runtime/contended/HasNonStatic.java b/hotspot/test/runtime/contended/HasNonStatic.java index 6ff21826428..33878fa6115 100644 --- a/hotspot/test/runtime/contended/HasNonStatic.java +++ b/hotspot/test/runtime/contended/HasNonStatic.java @@ -36,7 +36,7 @@ import java.util.regex.Pattern; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import sun.misc.Unsafe; -import sun.misc.Contended; +import jdk.internal.vm.annotation.Contended; /* * @test diff --git a/hotspot/test/runtime/contended/Inheritance1.java b/hotspot/test/runtime/contended/Inheritance1.java index e6cf2bd1a7f..3ea318c40dc 100644 --- a/hotspot/test/runtime/contended/Inheritance1.java +++ b/hotspot/test/runtime/contended/Inheritance1.java @@ -36,7 +36,7 @@ import java.util.regex.Pattern; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import sun.misc.Unsafe; -import sun.misc.Contended; +import jdk.internal.vm.annotation.Contended; /* * @test diff --git a/hotspot/test/runtime/contended/OopMaps.java b/hotspot/test/runtime/contended/OopMaps.java index 2501ec1f06f..5e1b39c8271 100644 --- a/hotspot/test/runtime/contended/OopMaps.java +++ b/hotspot/test/runtime/contended/OopMaps.java @@ -36,7 +36,7 @@ import java.util.regex.Pattern; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import sun.misc.Unsafe; -import sun.misc.Contended; +import jdk.internal.vm.annotation.Contended; /* * @test diff --git a/hotspot/test/runtime/contended/OopMapsSameGroup.java b/hotspot/test/runtime/contended/OopMapsSameGroup.java index d17ae1ee9f6..af441a576b9 100644 --- a/hotspot/test/runtime/contended/OopMapsSameGroup.java +++ b/hotspot/test/runtime/contended/OopMapsSameGroup.java @@ -36,7 +36,7 @@ import java.util.regex.Pattern; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import sun.misc.Unsafe; -import sun.misc.Contended; +import jdk.internal.vm.annotation.Contended; /* * @test From f6343b0f69f91961765e49a5341d8e1f85560faf Mon Sep 17 00:00:00 2001 From: David Lindholm Date: Tue, 24 Nov 2015 14:03:42 +0100 Subject: [PATCH 072/260] 8143587: G1 crashes with humongous object of size that almost fills a heap region Reviewed-by: mgerdin, brutisso --- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 64 ++++++++++-------- .../TestHumongousAllocNearlyFullRegion.java | 65 +++++++++++++++++++ 2 files changed, 103 insertions(+), 26 deletions(-) create mode 100644 hotspot/test/gc/g1/TestHumongousAllocNearlyFullRegion.java diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index e1938d910af..c5f5793700a 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -301,8 +301,8 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first, assert(is_humongous(word_size), "word_size should be humongous"); assert(num_regions * HeapRegion::GrainWords >= word_size, "pre-condition"); - // Index of last region in the series + 1. - uint last = first + num_regions; + // Index of last region in the series. + uint last = first + num_regions - 1; // We need to initialize the region(s) we just discovered. This is // a bit tricky given that it can happen concurrently with @@ -339,23 +339,30 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first, // thread to calculate the object size incorrectly. Copy::fill_to_words(new_obj, oopDesc::header_size(), 0); - size_t fill_size = word_size_sum - word_size; - if (fill_size >= min_fill_size()) { - fill_with_objects(obj_top, fill_size); - } else { - fill_size = 0; + // How many words we use for filler objects. + size_t word_fill_size = word_size_sum - word_size; + + // How many words memory we "waste" which cannot hold a filler object. + size_t words_not_fillable = 0; + + if (word_fill_size >= min_fill_size()) { + fill_with_objects(obj_top, word_fill_size); + } else if (word_fill_size > 0) { + // We have space to fill, but we cannot fit an object there. + words_not_fillable = word_fill_size; + word_fill_size = 0; } // We will set up the first region as "starts humongous". This // will also update the BOT covering all the regions to reflect // that there is a single object that starts at the bottom of the // first region. - first_hr->set_starts_humongous(obj_top, fill_size); + first_hr->set_starts_humongous(obj_top, word_fill_size); first_hr->set_allocation_context(context); // Then, if there are any, we will set up the "continues // humongous" regions. HeapRegion* hr = NULL; - for (uint i = first + 1; i < last; ++i) { + for (uint i = first + 1; i <= last; ++i) { hr = region_at(i); hr->set_continues_humongous(first_hr); hr->set_allocation_context(context); @@ -370,33 +377,38 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first, // object header and the BOT initialization. OrderAccess::storestore(); - // Now that the BOT and the object header have been initialized, - // we can update top of the "starts humongous" region. - first_hr->set_top(first_hr->end()); - if (_hr_printer.is_active()) { - _hr_printer.alloc(G1HRPrinter::StartsHumongous, first_hr, first_hr->end()); - } - // Now, we will update the top fields of the "continues humongous" - // regions. - hr = NULL; - for (uint i = first + 1; i < last; ++i) { + // regions except the last one. + for (uint i = first; i < last; ++i) { hr = region_at(i); hr->set_top(hr->end()); - if (_hr_printer.is_active()) { - _hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, hr->end()); - } } - assert(hr == NULL || (hr->bottom() < obj_top && obj_top <= hr->end()), + hr = region_at(last); + // If we cannot fit a filler object, we must set top to the end + // of the humongous object, otherwise we cannot iterate the heap + // and the BOT will not be complete. + hr->set_top(hr->end() - words_not_fillable); + + assert(hr->bottom() < obj_top && obj_top <= hr->end(), "obj_top should be in last region"); check_bitmaps("Humongous Region Allocation", first_hr); - increase_used(word_size_sum * HeapWordSize); + assert(words_not_fillable == 0 || + first_hr->bottom() + word_size_sum - words_not_fillable == hr->top(), + "Miscalculation in humongous allocation"); - for (uint i = first; i < last; ++i) { - _humongous_set.add(region_at(i)); + increase_used((word_size_sum - words_not_fillable) * HeapWordSize); + + for (uint i = first; i <= last; ++i) { + hr = region_at(i); + _humongous_set.add(hr); + if (i == first) { + _hr_printer.alloc(G1HRPrinter::StartsHumongous, hr, hr->top()); + } else { + _hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, hr->top()); + } } return new_obj; diff --git a/hotspot/test/gc/g1/TestHumongousAllocNearlyFullRegion.java b/hotspot/test/gc/g1/TestHumongousAllocNearlyFullRegion.java new file mode 100644 index 00000000000..2e5a470f18d --- /dev/null +++ b/hotspot/test/gc/g1/TestHumongousAllocNearlyFullRegion.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 TestHumongousAllocNearlyFullRegion + * @bug 8143587 + * @summary G1: humongous object allocations should work even when there is + * not enough space in the heapRegion to fit a filler object. + * @library /testlibrary + * @run driver TestHumongousAllocNearlyFullRegion + */ + +import jdk.test.lib.*; + +public class TestHumongousAllocNearlyFullRegion { + // Heap sizes < 224 MB are increased to 224 MB if vm_page_size == 64K to + // fulfill alignment constraints. + private static final int heapSize = 224; // MB + private static final int heapRegionSize = 1; // MB + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseG1GC", + "-Xms" + heapSize + "m", + "-Xmx" + heapSize + "m", + "-XX:G1HeapRegionSize=" + heapRegionSize + "m", + "-XX:+PrintGC", + HumongousObjectAllocator.class.getName()); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("GC pause (G1 Humongous Allocation) (young) (initial-mark)"); + output.shouldHaveExitValue(0); + } + + static class HumongousObjectAllocator { + public static void main(String [] args) { + for (int i = 0; i < heapSize; i++) { + // 131069 is the number of longs it takes to fill a heapRegion except + // for 8 bytes on 64 bit. + long[] largeObect = new long[131069]; + } + } + } +} + From 402195fa550b9600c9064b48f6577b713e2f0c19 Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Tue, 24 Nov 2015 15:46:45 +0100 Subject: [PATCH 073/260] 8142495: Move G1ParEvacuateFollowersClosure to header file Reviewed-by: sjohanss, brutisso --- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 36 ------------------- .../src/share/vm/gc/g1/g1CollectedHeap.hpp | 36 +++++++++++++++++++ 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index e1938d910af..9fcaf427939 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -4101,42 +4101,6 @@ void G1CollectedHeap::preserve_mark_during_evac_failure(uint worker_id, oop obj, } } -class G1ParEvacuateFollowersClosure : public VoidClosure { -private: - double _start_term; - double _term_time; - size_t _term_attempts; - - void start_term_time() { _term_attempts++; _start_term = os::elapsedTime(); } - void end_term_time() { _term_time += os::elapsedTime() - _start_term; } -protected: - G1CollectedHeap* _g1h; - G1ParScanThreadState* _par_scan_state; - RefToScanQueueSet* _queues; - ParallelTaskTerminator* _terminator; - - G1ParScanThreadState* par_scan_state() { return _par_scan_state; } - RefToScanQueueSet* queues() { return _queues; } - ParallelTaskTerminator* terminator() { return _terminator; } - -public: - G1ParEvacuateFollowersClosure(G1CollectedHeap* g1h, - G1ParScanThreadState* par_scan_state, - RefToScanQueueSet* queues, - ParallelTaskTerminator* terminator) - : _g1h(g1h), _par_scan_state(par_scan_state), - _queues(queues), _terminator(terminator), - _start_term(0.0), _term_time(0.0), _term_attempts(0) {} - - void do_void(); - - double term_time() const { return _term_time; } - size_t term_attempts() const { return _term_attempts; } - -private: - inline bool offer_termination(); -}; - bool G1ParEvacuateFollowersClosure::offer_termination() { G1ParScanThreadState* const pss = par_scan_state(); start_term_time(); diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index 8acf26779e7..4715632031a 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -1518,4 +1518,40 @@ protected: size_t _max_heap_capacity; }; +class G1ParEvacuateFollowersClosure : public VoidClosure { +private: + double _start_term; + double _term_time; + size_t _term_attempts; + + void start_term_time() { _term_attempts++; _start_term = os::elapsedTime(); } + void end_term_time() { _term_time += os::elapsedTime() - _start_term; } +protected: + G1CollectedHeap* _g1h; + G1ParScanThreadState* _par_scan_state; + RefToScanQueueSet* _queues; + ParallelTaskTerminator* _terminator; + + G1ParScanThreadState* par_scan_state() { return _par_scan_state; } + RefToScanQueueSet* queues() { return _queues; } + ParallelTaskTerminator* terminator() { return _terminator; } + +public: + G1ParEvacuateFollowersClosure(G1CollectedHeap* g1h, + G1ParScanThreadState* par_scan_state, + RefToScanQueueSet* queues, + ParallelTaskTerminator* terminator) + : _g1h(g1h), _par_scan_state(par_scan_state), + _queues(queues), _terminator(terminator), + _start_term(0.0), _term_time(0.0), _term_attempts(0) {} + + void do_void(); + + double term_time() const { return _term_time; } + size_t term_attempts() const { return _term_attempts; } + +private: + inline bool offer_termination(); +}; + #endif // SHARE_VM_GC_G1_G1COLLECTEDHEAP_HPP From d2e0eb79a8e496b5128657aac8c8a4f4a4a67632 Mon Sep 17 00:00:00 2001 From: Rachel Protacio Date: Tue, 24 Nov 2015 11:40:18 -0500 Subject: [PATCH 074/260] 8143155: Remove TraceRuntimeCalls, TraceJNICalls, and TraceJVMCalls rather than convert to UL Removed TraceRuntimeCalls, TraceJNICalls, and TraceJVMCalls options because their output is excessive, not useful, and covered in a more useful way by other options. Reviewed-by: coleenp, dholmes, ddmitriev --- hotspot/src/share/vm/prims/jni.cpp | 17 +------- hotspot/src/share/vm/prims/jvm.cpp | 41 +++++-------------- hotspot/src/share/vm/runtime/globals.hpp | 9 ---- .../src/share/vm/runtime/interfaceSupport.cpp | 4 -- .../src/share/vm/runtime/interfaceSupport.hpp | 5 --- hotspot/src/share/vm/runtime/thread.cpp | 7 ---- .../runtime/CommandLine/VMOptionWarning.java | 8 ++-- 7 files changed, 17 insertions(+), 74 deletions(-) diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 996180e4713..508cdd55af5 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -261,19 +261,6 @@ void jfieldIDWorkaround::verify_instance_jfieldID(Klass* k, jfieldID id) { Histogram* JNIHistogram; static volatile jint JNIHistogram_lock = 0; - class JNITraceWrapper : public StackObj { - public: - JNITraceWrapper(const char* format, ...) ATTRIBUTE_PRINTF(2, 3) { - if (TraceJNICalls) { - va_list ap; - va_start(ap, format); - tty->print("JNI "); - tty->vprint_cr(format, ap); - va_end(ap); - } - } - }; - class JNIHistogramElement : public HistogramElement { public: JNIHistogramElement(const char* name); @@ -305,7 +292,7 @@ void jfieldIDWorkaround::verify_instance_jfieldID(Klass* k, jfieldID id) { static JNIHistogramElement* e = new JNIHistogramElement(arg); \ /* There is a MT-race condition in VC++. So we need to make sure that that e has been initialized */ \ if (e != NULL) e->increment_count() - #define JNIWrapper(arg) JNICountWrapper(arg); JNITraceWrapper(arg) + #define JNIWrapper(arg) JNICountWrapper(arg); #else #define JNIWrapper(arg) #endif @@ -3759,7 +3746,7 @@ void copy_jni_function_table(const struct JNINativeInterface_ *new_jni_NativeInt void quicken_jni_functions() { // Replace GetField with fast versions if (UseFastJNIAccessors && !JvmtiExport::can_post_field_access() - && !VerifyJNIFields && !TraceJNICalls && !CountJNICalls && !CheckJNICalls + && !VerifyJNIFields && !CountJNICalls && !CheckJNICalls #if defined(_WINDOWS) && defined(IA32) && defined(COMPILER2) // windows x86 currently needs SEH wrapper and the gain of the fast // versions currently isn't certain for server vm on uniprocessor. diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 45db3542ec2..3b7f01df2a8 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -223,19 +223,6 @@ void trace_class_resolution(Klass* to_class) { // Wrapper to trace JVM functions #ifdef ASSERT - class JVMTraceWrapper : public StackObj { - public: - JVMTraceWrapper(const char* format, ...) ATTRIBUTE_PRINTF(2, 3) { - if (TraceJVMCalls) { - va_list ap; - va_start(ap, format); - tty->print("JVM "); - tty->vprint_cr(format, ap); - va_end(ap); - } - } - }; - Histogram* JVMHistogram; volatile jint JVMHistogram_lock = 0; @@ -269,15 +256,9 @@ void trace_class_resolution(Klass* to_class) { static JVMHistogramElement* e = new JVMHistogramElement(arg); \ if (e != NULL) e->increment_count(); // Due to bug in VC++, we need a NULL check here eventhough it should never happen! - #define JVMWrapper(arg1) JVMCountWrapper(arg1); JVMTraceWrapper(arg1) - #define JVMWrapper2(arg1, arg2) JVMCountWrapper(arg1); JVMTraceWrapper(arg1, arg2) - #define JVMWrapper3(arg1, arg2, arg3) JVMCountWrapper(arg1); JVMTraceWrapper(arg1, arg2, arg3) - #define JVMWrapper4(arg1, arg2, arg3, arg4) JVMCountWrapper(arg1); JVMTraceWrapper(arg1, arg2, arg3, arg4) + #define JVMWrapper(arg) JVMCountWrapper(arg); #else - #define JVMWrapper(arg1) - #define JVMWrapper2(arg1, arg2) - #define JVMWrapper3(arg1, arg2, arg3) - #define JVMWrapper4(arg1, arg2, arg3, arg4) + #define JVMWrapper(arg) #endif @@ -672,7 +653,7 @@ JVM_END // java.io.File /////////////////////////////////////////////////////////////// JVM_LEAF(char*, JVM_NativePath(char* path)) - JVMWrapper2("JVM_NativePath (%s)", path); + JVMWrapper("JVM_NativePath"); return os::native_path(path); JVM_END @@ -749,7 +730,7 @@ JVM_END // FindClassFromBootLoader is exported to the launcher for windows. JVM_ENTRY(jclass, JVM_FindClassFromBootLoader(JNIEnv* env, const char* name)) - JVMWrapper2("JVM_FindClassFromBootLoader %s", name); + JVMWrapper("JVM_FindClassFromBootLoader"); // Java libraries should ensure that name is never null... if (name == NULL || (int)strlen(name) > Symbol::max_length()) { @@ -774,7 +755,7 @@ JVM_END JVM_ENTRY(jclass, JVM_FindClassFromCaller(JNIEnv* env, const char* name, jboolean init, jobject loader, jclass caller)) - JVMWrapper2("JVM_FindClassFromCaller %s throws ClassNotFoundException", name); + JVMWrapper("JVM_FindClassFromCaller throws ClassNotFoundException"); // Java libraries should ensure that name is never null... if (name == NULL || (int)strlen(name) > Symbol::max_length()) { // It's impossible to create this class; the name cannot fit @@ -809,7 +790,7 @@ JVM_END JVM_ENTRY(jclass, JVM_FindClassFromClass(JNIEnv *env, const char *name, jboolean init, jclass from)) - JVMWrapper2("JVM_FindClassFromClass %s", name); + JVMWrapper("JVM_FindClassFromClass"); if (name == NULL || (int)strlen(name) > Symbol::max_length()) { // It's impossible to create this class; the name cannot fit // into the constant pool. @@ -916,14 +897,14 @@ static jclass jvm_define_class_common(JNIEnv *env, const char *name, JVM_ENTRY(jclass, JVM_DefineClass(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd)) - JVMWrapper2("JVM_DefineClass %s", name); + JVMWrapper("JVM_DefineClass"); return jvm_define_class_common(env, name, loader, buf, len, pd, NULL, THREAD); JVM_END JVM_ENTRY(jclass, JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source)) - JVMWrapper2("JVM_DefineClassWithSource %s", name); + JVMWrapper("JVM_DefineClassWithSource"); return jvm_define_class_common(env, name, loader, buf, len, pd, source, THREAD); JVM_END @@ -3350,7 +3331,7 @@ JVM_END JVM_ENTRY_NO_ENV(void*, JVM_LoadLibrary(const char* name)) //%note jvm_ct - JVMWrapper2("JVM_LoadLibrary (%s)", name); + JVMWrapper("JVM_LoadLibrary"); char ebuf[1024]; void *load_result; { @@ -3382,7 +3363,7 @@ JVM_END JVM_LEAF(void*, JVM_FindLibraryEntry(void* handle, const char* name)) - JVMWrapper2("JVM_FindLibraryEntry (%s)", name); + JVMWrapper("JVM_FindLibraryEntry"); return os::dll_lookup(handle, name); JVM_END @@ -3390,7 +3371,7 @@ JVM_END // JNI version /////////////////////////////////////////////////////////////////////////////// JVM_LEAF(jboolean, JVM_IsSupportedJNIVersion(jint version)) - JVMWrapper2("JVM_IsSupportedJNIVersion (%d)", version); + JVMWrapper("JVM_IsSupportedJNIVersion"); return Threads::is_supported_jni_version_including_1_1(version); JVM_END diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index cf6637e396a..7459a7aaebc 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1426,18 +1426,9 @@ public: \ /* tracing */ \ \ - notproduct(bool, TraceRuntimeCalls, false, \ - "Trace run-time calls") \ - \ - develop(bool, TraceJNICalls, false, \ - "Trace JNI calls") \ - \ develop(bool, StressRewriter, false, \ "Stress linktime bytecode rewriting") \ \ - notproduct(bool, TraceJVMCalls, false, \ - "Trace JVM calls") \ - \ product(ccstr, TraceJVMTI, NULL, \ "Trace flags for JVMTI functions and events") \ \ diff --git a/hotspot/src/share/vm/runtime/interfaceSupport.cpp b/hotspot/src/share/vm/runtime/interfaceSupport.cpp index 9f19a5f18ca..a65fca64e40 100644 --- a/hotspot/src/share/vm/runtime/interfaceSupport.cpp +++ b/hotspot/src/share/vm/runtime/interfaceSupport.cpp @@ -70,10 +70,6 @@ RuntimeHistogramElement::RuntimeHistogramElement(const char* elementName) { Atomic::dec(&RuntimeHistogram_lock); } -void InterfaceSupport::trace(const char* result_type, const char* header) { - tty->print_cr("%6ld %s", _number_of_calls, header); -} - void InterfaceSupport::gc_alot() { Thread *thread = Thread::current(); if (!thread->is_Java_thread()) return; // Avoid concurrent calls diff --git a/hotspot/src/share/vm/runtime/interfaceSupport.hpp b/hotspot/src/share/vm/runtime/interfaceSupport.hpp index 206d101e945..fc5374df4fc 100644 --- a/hotspot/src/share/vm/runtime/interfaceSupport.hpp +++ b/hotspot/src/share/vm/runtime/interfaceSupport.hpp @@ -74,9 +74,6 @@ class InterfaceSupport: AllStatic { static long _number_of_calls; static long _fullgc_alot_invocation; - // tracing - static void trace(const char* result_type, const char* header); - // Helper methods used to implement +ScavengeALot and +FullGCALot static void check_gc_alot() { if (ScavengeALot || FullGCALot) gc_alot(); } static void gc_alot(); @@ -402,8 +399,6 @@ class RuntimeHistogramElement : public HistogramElement { #define TRACE_CALL(result_type, header) \ InterfaceSupport::_number_of_calls++; \ - if (TraceRuntimeCalls) \ - InterfaceSupport::trace(#result_type, #header); \ if (CountRuntimeCalls) { \ static RuntimeHistogramElement* e = new RuntimeHistogramElement(#header); \ if (e != NULL) e->increment_count(); \ diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 5291b8025fa..db0f5d9812c 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -4022,13 +4022,6 @@ bool Threads::destroy_vm() { // will be stopped at native=>Java/VM barriers. Note that we can't // simply kill or suspend them, as it is inherently deadlock-prone. -#ifndef PRODUCT - // disable function tracing at JNI/JVM barriers - TraceJNICalls = false; - TraceJVMCalls = false; - TraceRuntimeCalls = false; -#endif - VM_Exit::set_vm_exited(); notify_vm_shutdown(); diff --git a/hotspot/test/runtime/CommandLine/VMOptionWarning.java b/hotspot/test/runtime/CommandLine/VMOptionWarning.java index 894b2c5297e..1d81ff18060 100644 --- a/hotspot/test/runtime/CommandLine/VMOptionWarning.java +++ b/hotspot/test/runtime/CommandLine/VMOptionWarning.java @@ -47,12 +47,12 @@ public class VMOptionWarning { output = new OutputAnalyzer(pb.start()); output.shouldContain("Error: VM option 'PrintInlining' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions."); - pb = ProcessTools.createJavaProcessBuilder("-XX:+TraceJNICalls", "-version"); + pb = ProcessTools.createJavaProcessBuilder("-XX:+VerifyStack", "-version"); output = new OutputAnalyzer(pb.start()); - output.shouldContain("Error: VM option 'TraceJNICalls' is develop and is available only in debug version of VM."); + output.shouldContain("Error: VM option 'VerifyStack' is develop and is available only in debug version of VM."); - pb = ProcessTools.createJavaProcessBuilder("-XX:+TraceJVMCalls", "-version"); + pb = ProcessTools.createJavaProcessBuilder("-XX:+ExecuteInternalVMTests", "-version"); output = new OutputAnalyzer(pb.start()); - output.shouldContain("Error: VM option 'TraceJVMCalls' is notproduct and is available only in debug version of VM."); + output.shouldContain("Error: VM option 'ExecuteInternalVMTests' is notproduct and is available only in debug version of VM."); } } From 130ba226a15941bcfd0d883f9576ca21d2545c4c Mon Sep 17 00:00:00 2001 From: Christian Tornqvist Date: Tue, 24 Nov 2015 10:12:11 -0800 Subject: [PATCH 075/260] 8143931: Back out JDK-8140450 Reviewed-by: coleenp --- hotspot/make/share/makefiles/mapfile-vers | 4 - .../src/share/vm/classfile/javaClasses.cpp | 224 ++------- .../src/share/vm/classfile/javaClasses.hpp | 83 +--- .../share/vm/classfile/javaClasses.inline.hpp | 63 --- .../share/vm/classfile/systemDictionary.hpp | 8 +- hotspot/src/share/vm/classfile/vmSymbols.hpp | 29 -- hotspot/src/share/vm/memory/universe.cpp | 14 - hotspot/src/share/vm/memory/universe.hpp | 3 - hotspot/src/share/vm/prims/jvm.cpp | 89 ---- hotspot/src/share/vm/prims/jvm.h | 31 -- hotspot/src/share/vm/prims/stackwalk.cpp | 470 ------------------ hotspot/src/share/vm/prims/stackwalk.hpp | 102 ---- hotspot/src/share/vm/runtime/globals.hpp | 6 - hotspot/src/share/vm/runtime/vframe.hpp | 12 +- 14 files changed, 58 insertions(+), 1080 deletions(-) delete mode 100644 hotspot/src/share/vm/prims/stackwalk.cpp delete mode 100644 hotspot/src/share/vm/prims/stackwalk.hpp diff --git a/hotspot/make/share/makefiles/mapfile-vers b/hotspot/make/share/makefiles/mapfile-vers index 9672bfe3fc9..7021e53d444 100644 --- a/hotspot/make/share/makefiles/mapfile-vers +++ b/hotspot/make/share/makefiles/mapfile-vers @@ -7,7 +7,6 @@ JVM_ActiveProcessorCount; JVM_ArrayCopy; JVM_AssertionStatusDirectives; - JVM_CallStackWalk; JVM_ClassDepth; JVM_ClassLoaderDepth; JVM_Clone; @@ -37,7 +36,6 @@ JVM_DumpAllStacks; JVM_DumpThreads; JVM_FillInStackTrace; - JVM_FillStackFrames; JVM_FindClassFromCaller; JVM_FindClassFromClass; JVM_FindClassFromBootLoader; @@ -135,7 +133,6 @@ JVM_MonitorNotify; JVM_MonitorNotifyAll; JVM_MonitorWait; - JVM_MoreStackWalk; JVM_NanoTime; JVM_NativePath; JVM_NewArray; @@ -153,7 +150,6 @@ JVM_SetClassSigners; JVM_SetNativeThreadName; JVM_SetPrimitiveArrayElement; - JVM_SetMethodInfo; JVM_SetThreadPriority; JVM_Sleep; JVM_StartThread; diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index 242bafdfc53..a9f7c4616c6 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -1518,11 +1518,43 @@ void java_lang_Throwable::print(Handle throwable, outputStream* st) { // After this many redefines, the stack trace is unreliable. const int MAX_VERSION = USHRT_MAX; +// Helper backtrace functions to store bci|version together. +static inline int merge_bci_and_version(int bci, int version) { + // only store u2 for version, checking for overflow. + if (version > USHRT_MAX || version < 0) version = MAX_VERSION; + assert((jushort)bci == bci, "bci should be short"); + return build_int_from_shorts(version, bci); +} + +static inline int bci_at(unsigned int merged) { + return extract_high_short_from_int(merged); +} +static inline int version_at(unsigned int merged) { + return extract_low_short_from_int(merged); +} + static inline bool version_matches(Method* method, int version) { assert(version < MAX_VERSION, "version is too big"); return method != NULL && (method->constants()->version() == version); } +static inline int get_line_number(Method* method, int bci) { + int line_number = 0; + if (method->is_native()) { + // Negative value different from -1 below, enabling Java code in + // class java.lang.StackTraceElement to distinguish "native" from + // "no LineNumberTable". JDK tests for -2. + line_number = -2; + } else { + // Returns -1 if no LineNumberTable, and otherwise actual line number + line_number = method->line_number_from_bci(bci); + if (line_number == -1 && ShowHiddenFrames) { + line_number = bci + 1000000; + } + } + return line_number; +} + // This class provides a simple wrapper over the internal structure of // exception backtrace to insulate users of the backtrace from needing // to know what it looks like. @@ -1644,7 +1676,7 @@ class BacktraceBuilder: public StackObj { } _methods->short_at_put(_index, method->orig_method_idnum()); - _bcis->int_at_put(_index, Backtrace::merge_bci_and_version(bci, method->constants()->version())); + _bcis->int_at_put(_index, merge_bci_and_version(bci, method->constants()->version())); _cprefs->short_at_put(_index, method->name_index()); // We need to save the mirrors in the backtrace to keep the class @@ -1656,6 +1688,19 @@ class BacktraceBuilder: public StackObj { }; +Symbol* get_source_file_name(InstanceKlass* holder, int version) { + // Find the specific ik version that contains this source_file_name_index + // via the previous versions list, but use the current version's + // constant pool to look it up. The previous version's index has been + // merged for the current constant pool. + InstanceKlass* ik = holder->get_klass_version(version); + // This version has been cleaned up. + if (ik == NULL) return NULL; + int source_file_name_index = ik->source_file_name_index(); + return (source_file_name_index == 0) ? + (Symbol*)NULL : holder->constants()->symbol_at(source_file_name_index); +} + // Print stack trace element to resource allocated buffer char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, int method_id, int version, int bci, int cpref) { @@ -1673,7 +1718,7 @@ char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, buf_len += (int)strlen(method_name); char* source_file_name = NULL; - Symbol* source = Backtrace::get_source_file_name(holder, version); + Symbol* source = get_source_file_name(holder, version); if (source != NULL) { source_file_name = source->as_C_string(); buf_len += (int)strlen(source_file_name); @@ -1688,7 +1733,7 @@ char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, if (!version_matches(method, version)) { strcat(buf, "(Redefined)"); } else { - int line_number = Backtrace::get_line_number(method, bci); + int line_number = get_line_number(method, bci); if (line_number == -2) { strcat(buf, "(Native Method)"); } else { @@ -1757,8 +1802,8 @@ void java_lang_Throwable::print_stack_trace(oop throwable, outputStream* st) { // NULL mirror means end of stack trace if (mirror.is_null()) goto handle_cause; int method = methods->short_at(index); - int version = Backtrace::version_at(bcis->int_at(index)); - int bci = Backtrace::bci_at(bcis->int_at(index)); + int version = version_at(bcis->int_at(index)); + int bci = bci_at(bcis->int_at(index)); int cpref = cprefs->short_at(index); print_stack_element(st, mirror, method, version, bci, cpref); } @@ -2045,8 +2090,8 @@ oop java_lang_Throwable::get_stack_trace_element(oop throwable, int index, TRAPS assert(methods != NULL && bcis != NULL && mirrors != NULL, "sanity check"); int method = methods->short_at(chunk_index); - int version = Backtrace::version_at(bcis->int_at(chunk_index)); - int bci = Backtrace::bci_at(bcis->int_at(chunk_index)); + int version = version_at(bcis->int_at(chunk_index)); + int bci = bci_at(bcis->int_at(chunk_index)); int cpref = cprefs->short_at(chunk_index); Handle mirror(THREAD, mirrors->obj_at(chunk_index)); @@ -2069,7 +2114,6 @@ oop java_lang_StackTraceElement::create(Handle mirror, int method_id, } Handle element = ik->allocate_instance_handle(CHECK_0); - // Fill in class name ResourceMark rm(THREAD); InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); @@ -2092,13 +2136,13 @@ oop java_lang_StackTraceElement::create(Handle mirror, int method_id, java_lang_StackTraceElement::set_lineNumber(element(), -1); } else { // Fill in source file name and line number. - Symbol* source = Backtrace::get_source_file_name(holder, version); + Symbol* source = get_source_file_name(holder, version); if (ShowHiddenFrames && source == NULL) source = vmSymbols::unknown_class_name(); oop filename = StringTable::intern(source, CHECK_0); java_lang_StackTraceElement::set_fileName(element(), filename); - int line_number = Backtrace::get_line_number(method, bci); + int line_number = get_line_number(method, bci); java_lang_StackTraceElement::set_lineNumber(element(), line_number); } return element(); @@ -2111,108 +2155,6 @@ oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, TRA return create(mirror, method_id, method->constants()->version(), bci, cpref, THREAD); } -Method* java_lang_StackFrameInfo::get_method(Handle stackFrame, InstanceKlass* holder, TRAPS) { - if (MemberNameInStackFrame) { - Handle mname(THREAD, stackFrame->obj_field(_memberName_offset)); - Method* method = (Method*)java_lang_invoke_MemberName::vmtarget(mname()); - // we should expand MemberName::name when Throwable uses StackTrace - // MethodHandles::expand_MemberName(mname, MethodHandles::_suppress_defc|MethodHandles::_suppress_type, CHECK_NULL); - return method; - } else { - short mid = stackFrame->short_field(_mid_offset); - short version = stackFrame->short_field(_version_offset); - return holder->method_with_orig_idnum(mid, version); - } -} - -Symbol* java_lang_StackFrameInfo::get_file_name(Handle stackFrame, InstanceKlass* holder) { - if (MemberNameInStackFrame) { - return holder->source_file_name(); - } else { - short version = stackFrame->short_field(_version_offset); - return Backtrace::get_source_file_name(holder, version); - } -} - -void java_lang_StackFrameInfo::set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci) { - // set Method* or mid/cpref - if (MemberNameInStackFrame) { - oop mname = stackFrame->obj_field(_memberName_offset); - InstanceKlass* ik = method->method_holder(); - CallInfo info(method(), ik); - MethodHandles::init_method_MemberName(mname, info); - } else { - int mid = method->orig_method_idnum(); - int cpref = method->name_index(); - assert((jushort)mid == mid, "mid should be short"); - assert((jushort)cpref == cpref, "cpref should be short"); - java_lang_StackFrameInfo::set_mid(stackFrame(), (short)mid); - java_lang_StackFrameInfo::set_cpref(stackFrame(), (short)cpref); - } - // set bci - java_lang_StackFrameInfo::set_bci(stackFrame(), bci); - // method may be redefined; store the version - int version = method->constants()->version(); - assert((jushort)version == version, "version should be short"); - java_lang_StackFrameInfo::set_version(stackFrame(), (short)version); -} - -void java_lang_StackFrameInfo::fill_methodInfo(Handle stackFrame, TRAPS) { - ResourceMark rm(THREAD); - oop k = stackFrame->obj_field(_declaringClass_offset); - InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(k)); - Method* method = java_lang_StackFrameInfo::get_method(stackFrame, holder, CHECK); - int bci = stackFrame->int_field(_bci_offset); - - // The method can be NULL if the requested class version is gone - Symbol* sym = (method != NULL) ? method->name() : NULL; - if (MemberNameInStackFrame) { - assert(sym != NULL, "MemberName must have method name"); - } else { - // The method can be NULL if the requested class version is gone - if (sym == NULL) { - short cpref = stackFrame->short_field(_cpref_offset); - sym = holder->constants()->symbol_at(cpref); - } - } - - // set method name - oop methodname = StringTable::intern(sym, CHECK); - java_lang_StackFrameInfo::set_methodName(stackFrame(), methodname); - - // set file name and line number - Symbol* source = get_file_name(stackFrame, holder); - if (source != NULL) { - oop filename = StringTable::intern(source, CHECK); - java_lang_StackFrameInfo::set_fileName(stackFrame(), filename); - } - - // if the method has been redefined, the bci is no longer applicable - short version = stackFrame->short_field(_version_offset); - if (version_matches(method, version)) { - int line_number = Backtrace::get_line_number(method, bci); - java_lang_StackFrameInfo::set_lineNumber(stackFrame(), line_number); - } -} - -void java_lang_StackFrameInfo::compute_offsets() { - Klass* k = SystemDictionary::StackFrameInfo_klass(); - compute_offset(_declaringClass_offset, k, vmSymbols::declaringClass_name(), vmSymbols::class_signature()); - compute_offset(_memberName_offset, k, vmSymbols::memberName_name(), vmSymbols::object_signature()); - compute_offset(_bci_offset, k, vmSymbols::bci_name(), vmSymbols::int_signature()); - compute_offset(_methodName_offset, k, vmSymbols::methodName_name(), vmSymbols::string_signature()); - compute_offset(_fileName_offset, k, vmSymbols::fileName_name(), vmSymbols::string_signature()); - compute_offset(_lineNumber_offset, k, vmSymbols::lineNumber_name(), vmSymbols::int_signature()); - STACKFRAMEINFO_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); -} - -void java_lang_LiveStackFrameInfo::compute_offsets() { - Klass* k = SystemDictionary::LiveStackFrameInfo_klass(); - compute_offset(_monitors_offset, k, vmSymbols::monitors_name(), vmSymbols::object_array_signature()); - compute_offset(_locals_offset, k, vmSymbols::locals_name(), vmSymbols::object_array_signature()); - compute_offset(_operands_offset, k, vmSymbols::operands_name(), vmSymbols::object_array_signature()); -} - void java_lang_reflect_AccessibleObject::compute_offsets() { Klass* k = SystemDictionary::reflect_AccessibleObject_klass(); compute_offset(override_offset, k, vmSymbols::override_name(), vmSymbols::bool_signature()); @@ -3529,18 +3471,6 @@ int java_lang_StackTraceElement::declaringClass_offset; int java_lang_StackTraceElement::methodName_offset; int java_lang_StackTraceElement::fileName_offset; int java_lang_StackTraceElement::lineNumber_offset; -int java_lang_StackFrameInfo::_declaringClass_offset; -int java_lang_StackFrameInfo::_memberName_offset; -int java_lang_StackFrameInfo::_bci_offset; -int java_lang_StackFrameInfo::_methodName_offset; -int java_lang_StackFrameInfo::_fileName_offset; -int java_lang_StackFrameInfo::_lineNumber_offset; -int java_lang_StackFrameInfo::_mid_offset; -int java_lang_StackFrameInfo::_version_offset; -int java_lang_StackFrameInfo::_cpref_offset; -int java_lang_LiveStackFrameInfo::_monitors_offset; -int java_lang_LiveStackFrameInfo::_locals_offset; -int java_lang_LiveStackFrameInfo::_operands_offset; int java_lang_AssertionStatusDirectives::classes_offset; int java_lang_AssertionStatusDirectives::classEnabled_offset; int java_lang_AssertionStatusDirectives::packages_offset; @@ -3570,50 +3500,6 @@ void java_lang_StackTraceElement::set_lineNumber(oop element, int value) { element->int_field_put(lineNumber_offset, value); } -// Support for java_lang_StackFrameInfo -void java_lang_StackFrameInfo::set_declaringClass(oop element, oop value) { - element->obj_field_put(_declaringClass_offset, value); -} - -void java_lang_StackFrameInfo::set_mid(oop element, short value) { - element->short_field_put(_mid_offset, value); -} - -void java_lang_StackFrameInfo::set_version(oop element, short value) { - element->short_field_put(_version_offset, value); -} - -void java_lang_StackFrameInfo::set_cpref(oop element, short value) { - element->short_field_put(_cpref_offset, value); -} - -void java_lang_StackFrameInfo::set_bci(oop element, int value) { - element->int_field_put(_bci_offset, value); -} - -void java_lang_StackFrameInfo::set_fileName(oop element, oop value) { - element->obj_field_put(_fileName_offset, value); -} - -void java_lang_StackFrameInfo::set_methodName(oop element, oop value) { - element->obj_field_put(_methodName_offset, value); -} - -void java_lang_StackFrameInfo::set_lineNumber(oop element, int value) { - element->int_field_put(_lineNumber_offset, value); -} - -void java_lang_LiveStackFrameInfo::set_monitors(oop element, oop value) { - element->obj_field_put(_monitors_offset, value); -} - -void java_lang_LiveStackFrameInfo::set_locals(oop element, oop value) { - element->obj_field_put(_locals_offset, value); -} - -void java_lang_LiveStackFrameInfo::set_operands(oop element, oop value) { - element->obj_field_put(_operands_offset, value); -} // Support for java Assertions - java_lang_AssertionStatusDirectives. @@ -3747,8 +3633,6 @@ void JavaClasses::compute_offsets() { sun_reflect_ConstantPool::compute_offsets(); sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets(); java_lang_reflect_Parameter::compute_offsets(); - java_lang_StackFrameInfo::compute_offsets(); - java_lang_LiveStackFrameInfo::compute_offsets(); // generated interpreter code wants to know about the offsets we just computed: AbstractAssembler::update_delayed_values(); diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 8e66cccf695..403e33e9ee3 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -1359,85 +1359,6 @@ class java_lang_StackTraceElement: AllStatic { }; -class Backtrace: AllStatic { - public: - // Helper backtrace functions to store bci|version together. - static int merge_bci_and_version(int bci, int version); - static int merge_mid_and_cpref(int mid, int cpref); - static int bci_at(unsigned int merged); - static int version_at(unsigned int merged); - static int mid_at(unsigned int merged); - static int cpref_at(unsigned int merged); - static int get_line_number(const methodHandle& method, int bci); - static Symbol* get_source_file_name(InstanceKlass* holder, int version); - - // Debugging - friend class JavaClasses; -}; - -// Interface to java.lang.StackFrameInfo objects - -#define STACKFRAMEINFO_INJECTED_FIELDS(macro) \ - macro(java_lang_StackFrameInfo, mid, short_signature, false) \ - macro(java_lang_StackFrameInfo, version, short_signature, false) \ - macro(java_lang_StackFrameInfo, cpref, short_signature, false) - -class java_lang_StackFrameInfo: AllStatic { -private: - static int _declaringClass_offset; - static int _memberName_offset; - static int _bci_offset; - static int _methodName_offset; - static int _fileName_offset; - static int _lineNumber_offset; - - static int _mid_offset; - static int _version_offset; - static int _cpref_offset; - - static Method* get_method(Handle stackFrame, InstanceKlass* holder, TRAPS); - static Symbol* get_file_name(Handle stackFrame, InstanceKlass* holder); - -public: - // Setters - static void set_declaringClass(oop info, oop value); - static void set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci); - static void set_bci(oop info, int value); - - // set method info in an instance of StackFrameInfo - static void fill_methodInfo(Handle info, TRAPS); - static void set_methodName(oop info, oop value); - static void set_fileName(oop info, oop value); - static void set_lineNumber(oop info, int value); - - // these injected fields are only used if -XX:-MemberNameInStackFrame set - static void set_mid(oop info, short value); - static void set_version(oop info, short value); - static void set_cpref(oop info, short value); - - static void compute_offsets(); - - // Debugging - friend class JavaClasses; -}; - -class java_lang_LiveStackFrameInfo: AllStatic { - private: - static int _monitors_offset; - static int _locals_offset; - static int _operands_offset; - - public: - static void set_monitors(oop info, oop value); - static void set_locals(oop info, oop value); - static void set_operands(oop info, oop value); - - static void compute_offsets(); - - // Debugging - friend class JavaClasses; -}; - // Interface to java.lang.AssertionStatusDirectives objects class java_lang_AssertionStatusDirectives: AllStatic { @@ -1521,9 +1442,7 @@ class InjectedField { CLASS_INJECTED_FIELDS(macro) \ CLASSLOADER_INJECTED_FIELDS(macro) \ MEMBERNAME_INJECTED_FIELDS(macro) \ - CALLSITECONTEXT_INJECTED_FIELDS(macro) \ - STACKFRAMEINFO_INJECTED_FIELDS(macro) - + CALLSITECONTEXT_INJECTED_FIELDS(macro) // Interface to hard-coded offset checking diff --git a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp index ac35ccb8439..723c2e86757 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp @@ -73,67 +73,4 @@ inline bool java_lang_invoke_DirectMethodHandle::is_instance(oop obj) { return obj != NULL && is_subclass(obj->klass()); } -inline int Backtrace::merge_bci_and_version(int bci, int version) { - // only store u2 for version, checking for overflow. - if (version > USHRT_MAX || version < 0) version = USHRT_MAX; - assert((jushort)bci == bci, "bci should be short"); - return build_int_from_shorts(version, bci); -} - -inline int Backtrace::merge_mid_and_cpref(int mid, int cpref) { - // only store u2 for mid and cpref, checking for overflow. - assert((jushort)mid == mid, "mid should be short"); - assert((jushort)cpref == cpref, "cpref should be short"); - return build_int_from_shorts(cpref, mid); -} - -inline int Backtrace::bci_at(unsigned int merged) { - return extract_high_short_from_int(merged); -} - -inline int Backtrace::version_at(unsigned int merged) { - return extract_low_short_from_int(merged); -} - -inline int Backtrace::mid_at(unsigned int merged) { - return extract_high_short_from_int(merged); -} - -inline int Backtrace::cpref_at(unsigned int merged) { - return extract_low_short_from_int(merged); -} - -inline int Backtrace::get_line_number(const methodHandle& method, int bci) { - int line_number = 0; - if (method->is_native()) { - // Negative value different from -1 below, enabling Java code in - // class java.lang.StackTraceElement to distinguish "native" from - // "no LineNumberTable". JDK tests for -2. - line_number = -2; - } else { - // Returns -1 if no LineNumberTable, and otherwise actual line number - line_number = method->line_number_from_bci(bci); - if (line_number == -1 && ShowHiddenFrames) { - line_number = bci + 1000000; - } - } - return line_number; -} - -/* - * Returns the source file name of a given InstanceKlass and version - */ -inline Symbol* Backtrace::get_source_file_name(InstanceKlass* holder, int version) { - // Find the specific ik version that contains this source_file_name_index - // via the previous versions list, but use the current version's - // constant pool to look it up. The previous version's index has been - // merged for the current constant pool. - InstanceKlass* ik = holder->get_klass_version(version); - // This version has been cleaned up. - if (ik == NULL) return NULL; - int source_file_name_index = ik->source_file_name_index(); - return (source_file_name_index == 0) ? - (Symbol*)NULL : holder->constants()->symbol_at(source_file_name_index); -} - #endif // SHARE_VM_CLASSFILE_JAVACLASSES_INLINE_HPP diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index 41811e343cd..e735f095dbe 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -180,17 +180,11 @@ class Ticks; do_klass(sun_misc_Launcher_klass, sun_misc_Launcher, Pre ) \ do_klass(CodeSource_klass, java_security_CodeSource, Pre ) \ \ + /* It's NULL in non-1.4 JDKs. */ \ do_klass(StackTraceElement_klass, java_lang_StackTraceElement, Opt ) \ - \ /* It's okay if this turns out to be NULL in non-1.4 JDKs. */ \ do_klass(nio_Buffer_klass, java_nio_Buffer, Opt ) \ \ - /* Stack Walking */ \ - do_klass(StackWalker_klass, java_lang_StackWalker, Opt ) \ - do_klass(AbstractStackWalker_klass, java_lang_StackStreamFactory_AbstractStackWalker, Opt ) \ - do_klass(StackFrameInfo_klass, java_lang_StackFrameInfo, Opt ) \ - do_klass(LiveStackFrameInfo_klass, java_lang_LiveStackFrameInfo, Opt ) \ - \ /* Preload boxing klasses */ \ do_klass(Boolean_klass, java_lang_Boolean, Pre ) \ do_klass(Character_klass, java_lang_Character, Pre ) \ diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 9b4470f82d8..91ceb9b4925 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -311,22 +311,6 @@ /* Support for JVMCI */ \ JVMCI_VM_SYMBOLS_DO(template, do_alias) \ \ - template(java_lang_StackWalker, "java/lang/StackWalker") \ - template(java_lang_StackFrameInfo, "java/lang/StackFrameInfo") \ - template(java_lang_LiveStackFrameInfo, "java/lang/LiveStackFrameInfo") \ - template(java_lang_StackStreamFactory_AbstractStackWalker, "java/lang/StackStreamFactory$AbstractStackWalker") \ - template(doStackWalk_name, "doStackWalk") \ - template(doStackWalk_signature, "(JIIII)Ljava/lang/Object;") \ - template(asPrimitive_name, "asPrimitive") \ - template(asPrimitive_int_signature, "(I)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ - template(asPrimitive_long_signature, "(J)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ - template(asPrimitive_short_signature, "(S)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ - template(asPrimitive_byte_signature, "(B)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ - template(asPrimitive_char_signature, "(C)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ - template(asPrimitive_float_signature, "(F)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ - template(asPrimitive_double_signature, "(D)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ - template(asPrimitive_boolean_signature, "(Z)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ - \ /* common method and field names */ \ template(object_initializer_name, "") \ template(class_initializer_name, "") \ @@ -427,18 +411,6 @@ template(append_name, "append") \ template(klass_name, "klass") \ template(array_klass_name, "array_klass") \ - template(declaringClass_name, "declaringClass") \ - template(memberName_name, "memberName") \ - template(mid_name, "mid") \ - template(cpref_name, "cpref") \ - template(version_name, "version") \ - template(bci_name, "bci") \ - template(methodName_name, "methodName") \ - template(fileName_name, "fileName") \ - template(lineNumber_name, "lineNumber") \ - template(monitors_name, "monitors") \ - template(locals_name, "locals") \ - template(operands_name, "operands") \ template(oop_size_name, "oop_size") \ template(static_oop_field_count_name, "static_oop_field_count") \ template(protection_domain_name, "protection_domain") \ @@ -543,7 +515,6 @@ template(class_array_signature, "[Ljava/lang/Class;") \ template(classloader_signature, "Ljava/lang/ClassLoader;") \ template(object_signature, "Ljava/lang/Object;") \ - template(object_array_signature, "[Ljava/lang/Object;") \ template(class_signature, "Ljava/lang/Class;") \ template(string_signature, "Ljava/lang/String;") \ template(reference_signature, "Ljava/lang/ref/Reference;") \ diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index d06a7fbddc3..7ec9cfa3a99 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -115,7 +115,6 @@ LatestMethodCache* Universe::_finalizer_register_cache = NULL; LatestMethodCache* Universe::_loader_addClass_cache = NULL; LatestMethodCache* Universe::_pd_implies_cache = NULL; LatestMethodCache* Universe::_throw_illegal_access_error_cache = NULL; -LatestMethodCache* Universe::_do_stack_walk_cache = NULL; oop Universe::_out_of_memory_error_java_heap = NULL; oop Universe::_out_of_memory_error_metaspace = NULL; oop Universe::_out_of_memory_error_class_metaspace = NULL; @@ -241,7 +240,6 @@ void Universe::serialize(SerializeClosure* f, bool do_all) { _loader_addClass_cache->serialize(f); _pd_implies_cache->serialize(f); _throw_illegal_access_error_cache->serialize(f); - _do_stack_walk_cache->serialize(f); } void Universe::check_alignment(uintx size, uintx alignment, const char* name) { @@ -676,7 +674,6 @@ jint universe_init() { Universe::_loader_addClass_cache = new LatestMethodCache(); Universe::_pd_implies_cache = new LatestMethodCache(); Universe::_throw_illegal_access_error_cache = new LatestMethodCache(); - Universe::_do_stack_walk_cache = new LatestMethodCache(); if (UseSharedSpaces) { // Read the data structures supporting the shared spaces (shared @@ -1051,17 +1048,6 @@ bool universe_post_init() { SystemDictionary::ProtectionDomain_klass(), m); } - // Setup method for stack walking - InstanceKlass::cast(SystemDictionary::AbstractStackWalker_klass())->link_class(CHECK_false); - m = InstanceKlass::cast(SystemDictionary::AbstractStackWalker_klass())-> - find_method(vmSymbols::doStackWalk_name(), - vmSymbols::doStackWalk_signature()); - // Allow NULL which should only happen with bootstrapping. - if (m != NULL) { - Universe::_do_stack_walk_cache->init( - SystemDictionary::AbstractStackWalker_klass(), m); - } - // This needs to be done before the first scavenge/gc, since // it's an input to soft ref clearing policy. { diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index f2dc42e6cfe..854a818883c 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -149,7 +149,6 @@ class Universe: AllStatic { static LatestMethodCache* _loader_addClass_cache; // method for registering loaded classes in class loader vector static LatestMethodCache* _pd_implies_cache; // method for checking protection domain attributes static LatestMethodCache* _throw_illegal_access_error_cache; // Unsafe.throwIllegalAccessError() method - static LatestMethodCache* _do_stack_walk_cache; // method for stack walker callback // preallocated error objects (no backtrace) static oop _out_of_memory_error_java_heap; @@ -315,8 +314,6 @@ class Universe: AllStatic { static Method* protection_domain_implies_method() { return _pd_implies_cache->get_method(); } static Method* throw_illegal_access_error() { return _throw_illegal_access_error_cache->get_method(); } - static Method* do_stack_walk_method() { return _do_stack_walk_cache->get_method(); } - static oop null_ptr_exception_instance() { return _null_ptr_exception_instance; } static oop arithmetic_exception_instance() { return _arithmetic_exception_instance; } static oop virtual_machine_error_instance() { return _virtual_machine_error_instance; } diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index f6442b98574..45db3542ec2 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -46,7 +46,6 @@ #include "prims/jvmtiThreadState.hpp" #include "prims/nativeLookup.hpp" #include "prims/privilegedStack.hpp" -#include "prims/stackwalk.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/handles.inline.hpp" @@ -548,94 +547,6 @@ JVM_ENTRY(jobject, JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint JVM_END -// java.lang.StackWalker ////////////////////////////////////////////////////// - - -JVM_ENTRY(jobject, JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode, - jint skip_frames, jint frame_count, jint start_index, - jobjectArray classes, - jobjectArray frames)) - JVMWrapper("JVM_CallStackWalk"); - JavaThread* jt = (JavaThread*) THREAD; - if (!jt->is_Java_thread() || !jt->has_last_Java_frame()) { - THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: no stack trace", NULL); - } - - Handle stackStream_h(THREAD, JNIHandles::resolve_non_null(stackStream)); - objArrayOop ca = objArrayOop(JNIHandles::resolve_non_null(classes)); - objArrayHandle classes_array_h(THREAD, ca); - - // frames array is null when only getting caller reference - objArrayOop fa = objArrayOop(JNIHandles::resolve(frames)); - objArrayHandle frames_array_h(THREAD, fa); - - int limit = start_index + frame_count; - if (classes_array_h->length() < limit) { - THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers", NULL); - } - - Handle result = StackWalk::walk(stackStream_h, mode, skip_frames, frame_count, - start_index, classes_array_h, - frames_array_h, CHECK_NULL); - return JNIHandles::make_local(env, result()); -JVM_END - - -JVM_ENTRY(jint, JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor, - jint frame_count, jint start_index, - jobjectArray classes, - jobjectArray frames)) - JVMWrapper("JVM_MoreStackWalk"); - JavaThread* jt = (JavaThread*) THREAD; - objArrayOop ca = objArrayOop(JNIHandles::resolve_non_null(classes)); - objArrayHandle classes_array_h(THREAD, ca); - - // frames array is null when only getting caller reference - objArrayOop fa = objArrayOop(JNIHandles::resolve(frames)); - objArrayHandle frames_array_h(THREAD, fa); - - int limit = start_index+frame_count; - if (classes_array_h->length() < limit) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers"); - } - - Handle stackStream_h(THREAD, JNIHandles::resolve_non_null(stackStream)); - return StackWalk::moreFrames(stackStream_h, mode, anchor, frame_count, - start_index, classes_array_h, - frames_array_h, THREAD); -JVM_END - -JVM_ENTRY(void, JVM_FillStackFrames(JNIEnv *env, jclass stackStream, - jint start_index, - jobjectArray frames, - jint from_index, jint to_index)) - JVMWrapper("JVM_FillStackFrames"); - if (TraceStackWalk) { - tty->print("JVM_FillStackFrames() start_index=%d from_index=%d to_index=%d\n", - start_index, from_index, to_index); - } - - JavaThread* jt = (JavaThread*) THREAD; - - objArrayOop fa = objArrayOop(JNIHandles::resolve_non_null(frames)); - objArrayHandle frames_array_h(THREAD, fa); - - if (frames_array_h->length() < to_index) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "array length not matched"); - } - - for (int i = from_index; i < to_index; i++) { - Handle stackFrame(THREAD, frames_array_h->obj_at(i)); - java_lang_StackFrameInfo::fill_methodInfo(stackFrame, CHECK); - } -JVM_END - -JVM_ENTRY(void, JVM_SetMethodInfo(JNIEnv *env, jobject frame)) - JVMWrapper("JVM_SetMethodInfo"); - Handle stackFrame(THREAD, JNIHandles::resolve(frame)); - java_lang_StackFrameInfo::fill_methodInfo(stackFrame, THREAD); -JVM_END - // java.lang.Object /////////////////////////////////////////////// diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index 021f55dccb3..bc42dbf3edb 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -200,37 +200,6 @@ JVM_GetStackTraceDepth(JNIEnv *env, jobject throwable); JNIEXPORT jobject JNICALL JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint index); -/* - * java.lang.StackWalker - */ -enum { - JVM_STACKWALK_FILL_CLASS_REFS_ONLY = 0x2, - JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE = 0x10, - JVM_STACKWALK_SHOW_HIDDEN_FRAMES = 0x20, - JVM_STACKWALK_FILL_LIVE_STACK_FRAMES = 0x100 -}; - -JNIEXPORT jobject JNICALL -JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode, - jint skip_frames, jint frame_count, jint start_index, - jobjectArray classes, - jobjectArray frames); - -JNIEXPORT jint JNICALL -JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor, - jint frame_count, jint start_index, - jobjectArray classes, - jobjectArray frames); - -JNIEXPORT void JNICALL -JVM_FillStackFrames(JNIEnv* env, jclass cls, - jint start_index, - jobjectArray frames, - jint from_index, jint toIndex); - -JNIEXPORT void JNICALL -JVM_SetMethodInfo(JNIEnv* env, jobject frame); - /* * java.lang.Thread */ diff --git a/hotspot/src/share/vm/prims/stackwalk.cpp b/hotspot/src/share/vm/prims/stackwalk.cpp deleted file mode 100644 index 3e292641a79..00000000000 --- a/hotspot/src/share/vm/prims/stackwalk.cpp +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "classfile/javaClasses.hpp" -#include "classfile/javaClasses.inline.hpp" -#include "classfile/vmSymbols.hpp" -#include "memory/oopFactory.hpp" -#include "oops/oop.inline.hpp" -#include "oops/objArrayOop.inline.hpp" -#include "prims/stackwalk.hpp" -#include "runtime/globals.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/javaCalls.hpp" -#include "runtime/vframe.hpp" -#include "utilities/globalDefinitions.hpp" - -// setup and cleanup actions -void StackWalkAnchor::setup_magic_on_entry(objArrayHandle classes_array) { - classes_array->obj_at_put(magic_pos, _thread->threadObj()); - _anchor = address_value(); - assert(check_magic(classes_array), "invalid magic"); -} - -bool StackWalkAnchor::check_magic(objArrayHandle classes_array) { - oop m1 = classes_array->obj_at(magic_pos); - jlong m2 = _anchor; - if (m1 == _thread->threadObj() && m2 == address_value()) return true; - return false; -} - -bool StackWalkAnchor::cleanup_magic_on_exit(objArrayHandle classes_array) { - bool ok = check_magic(classes_array); - classes_array->obj_at_put(magic_pos, NULL); - _anchor = 0L; - return ok; -} - -// Returns StackWalkAnchor for the current stack being traversed. -// -// Parameters: -// thread Current Java thread. -// magic Magic value used for each stack walking -// classes_array User-supplied buffers. The 0th element is reserved -// to this StackWalkAnchor to use -// -StackWalkAnchor* StackWalkAnchor::from_current(JavaThread* thread, jlong magic, - objArrayHandle classes_array) -{ - assert(thread != NULL && thread->is_Java_thread(), ""); - oop m1 = classes_array->obj_at(magic_pos); - if (m1 != thread->threadObj()) return NULL; - if (magic == 0L) return NULL; - StackWalkAnchor* anchor = (StackWalkAnchor*) (intptr_t) magic; - if (!anchor->is_valid_in(thread, classes_array)) return NULL; - return anchor; -} - -// Unpacks one or more frames into user-supplied buffers. -// Updates the end index, and returns the number of unpacked frames. -// Always start with the existing vfst.method and bci. -// Do not call vfst.next to advance over the last returned value. -// In other words, do not leave any stale data in the vfst. -// -// Parameters: -// mode Restrict which frames to be decoded. -// vfst vFrameStream. -// max_nframes Maximum number of frames to be filled. -// start_index Start index to the user-supplied buffers. -// classes_array Buffer to store classes in, starting at start_index. -// frames_array Buffer to store StackFrame in, starting at start_index. -// NULL if not used. -// end_index End index to the user-supplied buffers with unpacked frames. -// -// Returns the number of frames whose information was transferred into the buffers. -// -int StackWalk::fill_in_frames(jlong mode, vframeStream& vfst, - int max_nframes, int start_index, - objArrayHandle classes_array, - objArrayHandle frames_array, - int& end_index, TRAPS) { - if (TraceStackWalk) { - tty->print_cr("fill_in_frames limit=%d start=%d frames length=%d", - max_nframes, start_index, classes_array->length()); - } - assert(max_nframes > 0, "invalid max_nframes"); - assert(start_index + max_nframes <= classes_array->length(), "oob"); - - int frames_decoded = 0; - for (; !vfst.at_end(); vfst.next()) { - Method* method = vfst.method(); - int bci = vfst.bci(); - - if (method == NULL) continue; - if (!ShowHiddenFrames && StackWalk::skip_hidden_frames(mode)) { - if (method->is_hidden()) { - if (TraceStackWalk) { - tty->print(" hidden method: "); method->print_short_name(); - tty->print("\n"); - } - continue; - } - } - - int index = end_index++; - if (TraceStackWalk) { - tty->print(" %d: frame method: ", index); method->print_short_name(); - tty->print_cr(" bci=%d", bci); - } - - classes_array->obj_at_put(index, method->method_holder()->java_mirror()); - // fill in StackFrameInfo and initialize MemberName - if (live_frame_info(mode)) { - Handle stackFrame(frames_array->obj_at(index)); - fill_live_stackframe(stackFrame, method, bci, vfst.java_frame(), CHECK_0); - } else if (need_method_info(mode)) { - Handle stackFrame(frames_array->obj_at(index)); - fill_stackframe(stackFrame, method, bci); - } - if (++frames_decoded >= max_nframes) break; - } - return frames_decoded; -} - -static oop create_primitive_value_instance(StackValueCollection* values, int i, TRAPS) { - Klass* k = SystemDictionary::resolve_or_null(vmSymbols::java_lang_LiveStackFrameInfo(), CHECK_NULL); - instanceKlassHandle ik (THREAD, k); - - JavaValue result(T_OBJECT); - JavaCallArguments args; - Symbol* signature = NULL; - - // ## TODO: type is only available in LocalVariable table, if present. - // ## StackValue type is T_INT or T_OBJECT. - switch (values->at(i)->type()) { - case T_INT: - args.push_int(values->int_at(i)); - signature = vmSymbols::asPrimitive_int_signature(); - break; - - case T_LONG: - args.push_long(values->long_at(i)); - signature = vmSymbols::asPrimitive_long_signature(); - break; - - case T_FLOAT: - args.push_float(values->float_at(i)); - signature = vmSymbols::asPrimitive_float_signature(); - break; - - case T_DOUBLE: - args.push_double(values->double_at(i)); - signature = vmSymbols::asPrimitive_double_signature(); - break; - - case T_BYTE: - args.push_int(values->int_at(i)); - signature = vmSymbols::asPrimitive_byte_signature(); - break; - - case T_SHORT: - args.push_int(values->int_at(i)); - signature = vmSymbols::asPrimitive_short_signature(); - break; - - case T_CHAR: - args.push_int(values->int_at(i)); - signature = vmSymbols::asPrimitive_char_signature(); - break; - - case T_BOOLEAN: - args.push_int(values->int_at(i)); - signature = vmSymbols::asPrimitive_boolean_signature(); - break; - - case T_OBJECT: - return values->obj_at(i)(); - - case T_CONFLICT: - // put a non-null slot - args.push_int(0); - signature = vmSymbols::asPrimitive_int_signature(); - break; - - default: ShouldNotReachHere(); - } - JavaCalls::call_static(&result, - ik, - vmSymbols::asPrimitive_name(), - signature, - &args, - CHECK_NULL); - return (instanceOop) result.get_jobject(); -} - -static objArrayHandle values_to_object_array(StackValueCollection* values, TRAPS) { - objArrayHandle empty; - int length = values->size(); - objArrayOop array_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), - length, CHECK_(empty)); - objArrayHandle array_h(THREAD, array_oop); - for (int i = 0; i < values->size(); i++) { - StackValue* st = values->at(i); - oop obj = create_primitive_value_instance(values, i, CHECK_(empty)); - if (obj != NULL) - array_h->obj_at_put(i, obj); - } - return array_h; -} - -static objArrayHandle monitors_to_object_array(GrowableArray* monitors, TRAPS) { - int length = monitors->length(); - objArrayOop array_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), - length, CHECK_(objArrayHandle())); - objArrayHandle array_h(THREAD, array_oop); - for (int i = 0; i < length; i++) { - MonitorInfo* monitor = monitors->at(i); - array_h->obj_at_put(i, monitor->owner()); - } - return array_h; -} - -// Fill StackFrameInfo with declaringClass and bci and initialize memberName -void StackWalk::fill_stackframe(Handle stackFrame, const methodHandle& method, int bci) { - java_lang_StackFrameInfo::set_declaringClass(stackFrame(), method->method_holder()->java_mirror()); - java_lang_StackFrameInfo::set_method_and_bci(stackFrame(), method, bci); -} - -// Fill LiveStackFrameInfo with locals, monitors, and expressions -void StackWalk::fill_live_stackframe(Handle stackFrame, const methodHandle& method, - int bci, javaVFrame* jvf, TRAPS) { - fill_stackframe(stackFrame, method, bci); - if (jvf != NULL) { - StackValueCollection* locals = jvf->locals(); - StackValueCollection* expressions = jvf->expressions(); - GrowableArray* monitors = jvf->monitors(); - - if (!locals->is_empty()) { - objArrayHandle locals_h = values_to_object_array(locals, CHECK); - java_lang_LiveStackFrameInfo::set_locals(stackFrame(), locals_h()); - } - if (!expressions->is_empty()) { - objArrayHandle expressions_h = values_to_object_array(expressions, CHECK); - java_lang_LiveStackFrameInfo::set_operands(stackFrame(), expressions_h()); - } - if (monitors->length() > 0) { - objArrayHandle monitors_h = monitors_to_object_array(monitors, CHECK); - java_lang_LiveStackFrameInfo::set_monitors(stackFrame(), monitors_h()); - } - } -} - -// Begins stack walking. -// -// Parameters: -// stackStream StackStream object -// mode Stack walking mode. -// skip_frames Number of frames to be skipped. -// frame_count Number of frames to be traversed. -// start_index Start index to the user-supplied buffers. -// classes_array Buffer to store classes in, starting at start_index. -// frames_array Buffer to store StackFrame in, starting at start_index. -// NULL if not used. -// -// Returns Object returned from AbstractStackWalker::doStackWalk call. -// -oop StackWalk::walk(Handle stackStream, jlong mode, - int skip_frames, int frame_count, int start_index, - objArrayHandle classes_array, - objArrayHandle frames_array, - TRAPS) { - JavaThread* jt = (JavaThread*)THREAD; - if (TraceStackWalk) { - tty->print_cr("Start walking: mode " JLONG_FORMAT " skip %d frames batch size %d", - mode, skip_frames, frame_count); - } - - if (need_method_info(mode)) { - if (frames_array.is_null()) { - THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", NULL); - } - } - - Klass* stackWalker_klass = SystemDictionary::StackWalker_klass(); - Klass* abstractStackWalker_klass = SystemDictionary::AbstractStackWalker_klass(); - - methodHandle m_doStackWalk(THREAD, Universe::do_stack_walk_method()); - - // Open up a traversable stream onto my stack. - // This stream will be made available by *reference* to the inner Java call. - StackWalkAnchor anchor(jt); - vframeStream& vfst = anchor.vframe_stream(); - - { - // Skip all methods from AbstractStackWalker and StackWalk (enclosing method) - if (!fill_in_stacktrace(mode)) { - while (!vfst.at_end()) { - InstanceKlass* ik = vfst.method()->method_holder(); - if (ik != stackWalker_klass && - ik != abstractStackWalker_klass && ik->super() != abstractStackWalker_klass) { - break; - } - - if (TraceStackWalk) { - tty->print(" skip "); vfst.method()->print_short_name(); tty->print("\n"); - } - vfst.next(); - } - } - - // For exceptions, skip Throwable::fillInStackTrace and methods - // of the exception class and superclasses - if (fill_in_stacktrace(mode)) { - bool skip_to_fillInStackTrace = false; - bool skip_throwableInit_check = false; - while (!vfst.at_end() && !skip_throwableInit_check) { - InstanceKlass* ik = vfst.method()->method_holder(); - Method* method = vfst.method(); - if (!skip_to_fillInStackTrace) { - if (ik == SystemDictionary::Throwable_klass() && - method->name() == vmSymbols::fillInStackTrace_name()) { - // this frame will be skipped - skip_to_fillInStackTrace = true; - } - } else if (!(ik->is_subclass_of(SystemDictionary::Throwable_klass()) && - method->name() == vmSymbols::object_initializer_name())) { - // there are none or we've seen them all - either way stop checking - skip_throwableInit_check = true; - break; - } - - if (TraceStackWalk) { - tty->print("stack walk: skip "); vfst.method()->print_short_name(); tty->print("\n"); - } - vfst.next(); - } - } - - // stack frame has been traversed individually and resume stack walk - // from the stack frame at depth == skip_frames. - for (int n=0; n < skip_frames && !vfst.at_end(); vfst.next(), n++) { - if (TraceStackWalk) { - tty->print(" skip "); vfst.method()->print_short_name(); - tty->print_cr(" frame id: " PTR_FORMAT " pc: " PTR_FORMAT, - p2i(vfst.frame_id()), p2i(vfst.frame_pc())); - } - } - } - - // The Method* pointer in the vfst has a very short shelf life. Grab it now. - int end_index = start_index; - int numFrames = 0; - if (!vfst.at_end()) { - numFrames = fill_in_frames(mode, vfst, frame_count, start_index, classes_array, - frames_array, end_index, CHECK_NULL); - if (numFrames < 1) { - THROW_MSG_(vmSymbols::java_lang_InternalError(), "stack walk: decode failed", NULL); - } - } - - // JVM_CallStackWalk walks the stack and fills in stack frames, then calls to - // Java method java.lang.StackStreamFactory.AbstractStackWalker::doStackWalk - // which calls the implementation to consume the stack frames. - // When JVM_CallStackWalk returns, it invalidates the stack stream. - JavaValue result(T_OBJECT); - JavaCallArguments args(stackStream); - args.push_long(anchor.address_value()); - args.push_int(skip_frames); - args.push_int(frame_count); - args.push_int(start_index); - args.push_int(end_index); - - // Link the thread and vframe stream into the callee-visible object - anchor.setup_magic_on_entry(classes_array); - - JavaCalls::call(&result, m_doStackWalk, &args, THREAD); - - // Do this before anything else happens, to disable any lingering stream objects - bool ok = anchor.cleanup_magic_on_exit(classes_array); - - // Throw pending exception if we must - (void) (CHECK_NULL); - - if (!ok) { - THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers on exit", NULL); - } - - // Return normally - return (oop)result.get_jobject(); - -} - -// Walk the next batch of stack frames -// -// Parameters: -// stackStream StackStream object -// mode Stack walking mode. -// magic Must be valid value to continue the stack walk -// frame_count Number of frames to be decoded. -// start_index Start index to the user-supplied buffers. -// classes_array Buffer to store classes in, starting at start_index. -// frames_array Buffer to store StackFrame in, starting at start_index. -// NULL if not used. -// -// Returns the end index of frame filled in the buffer. -// -jint StackWalk::moreFrames(Handle stackStream, jlong mode, jlong magic, - int frame_count, int start_index, - objArrayHandle classes_array, - objArrayHandle frames_array, - TRAPS) -{ - JavaThread* jt = (JavaThread*)THREAD; - StackWalkAnchor* existing_anchor = StackWalkAnchor::from_current(jt, magic, classes_array); - if (existing_anchor == NULL) { - THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers", 0L); - } - - if ((need_method_info(mode) || live_frame_info(mode)) && frames_array.is_null()) { - THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", 0L); - } - - if (TraceStackWalk) { - tty->print_cr("StackWalk::moreFrames frame_count %d existing_anchor " PTR_FORMAT " start %d frames %d", - frame_count, p2i(existing_anchor), start_index, classes_array->length()); - } - int end_index = start_index; - if (frame_count <= 0) { - return end_index; // No operation. - } - - int count = frame_count + start_index; - assert (classes_array->length() >= count, "not enough space in buffers"); - - StackWalkAnchor& anchor = (*existing_anchor); - vframeStream& vfst = anchor.vframe_stream(); - if (!vfst.at_end()) { - vfst.next(); // this was the last frame decoded in the previous batch - if (!vfst.at_end()) { - int n = fill_in_frames(mode, vfst, frame_count, start_index, classes_array, - frames_array, end_index, CHECK_0); - if (n < 1) { - THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: later decode failed", 0L); - } - return end_index; - } - } - return end_index; -} diff --git a/hotspot/src/share/vm/prims/stackwalk.hpp b/hotspot/src/share/vm/prims/stackwalk.hpp deleted file mode 100644 index 1fa906815be..00000000000 --- a/hotspot/src/share/vm/prims/stackwalk.hpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - - -#ifndef SHARE_VM_PRIMS_STACKWALK_HPP -#define SHARE_VM_PRIMS_STACKWALK_HPP - -#include "oops/oop.hpp" -#include "runtime/vframe.hpp" - -class StackWalkAnchor : public StackObj { -private: - enum { - magic_pos = 0 - }; - - JavaThread* _thread; - vframeStream _vfst; - jlong _anchor; -public: - StackWalkAnchor(JavaThread* thread) - : _thread(thread), _vfst(thread), _anchor(0L) {} - - vframeStream& vframe_stream() { return _vfst; } - JavaThread* thread() { return _thread; } - - void setup_magic_on_entry(objArrayHandle classes_array); - bool check_magic(objArrayHandle classes_array); - bool cleanup_magic_on_exit(objArrayHandle classes_array); - - bool is_valid_in(Thread* thread, objArrayHandle classes_array) { - return (_thread == thread && check_magic(classes_array)); - } - - jlong address_value() { - return (jlong) castable_address(this); - } - - static StackWalkAnchor* from_current(JavaThread* thread, jlong anchor, objArrayHandle frames_array); -}; - -class StackWalk : public AllStatic { -private: - static int fill_in_frames(jlong mode, vframeStream& vfst, - int max_nframes, int start_index, - objArrayHandle classes_array, - objArrayHandle frames_array, - int& end_index, TRAPS); - - static void fill_stackframe(Handle stackFrame, const methodHandle& method, int bci); - - static void fill_live_stackframe(Handle stackFrame, const methodHandle& method, int bci, - javaVFrame* jvf, TRAPS); - - static inline bool skip_hidden_frames(int mode) { - return (mode & JVM_STACKWALK_SHOW_HIDDEN_FRAMES) == 0; - } - static inline bool need_method_info(int mode) { - return (mode & JVM_STACKWALK_FILL_CLASS_REFS_ONLY) == 0; - } - static inline bool live_frame_info(int mode) { - return (mode & JVM_STACKWALK_FILL_LIVE_STACK_FRAMES) != 0; - } - static inline bool fill_in_stacktrace(int mode) { - return (mode & JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE) != 0; - } - -public: - static oop walk(Handle stackStream, jlong mode, - int skip_frames, int frame_count, int start_index, - objArrayHandle classes_array, - objArrayHandle frames_array, - TRAPS); - - static jint moreFrames(Handle stackStream, jlong mode, jlong magic, - int frame_count, int start_index, - objArrayHandle classes_array, - objArrayHandle frames_array, - TRAPS); -}; -#endif // SHARE_VM_PRIMS_STACKWALK_HPP diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index d9f06a92e0f..cf6637e396a 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3115,12 +3115,6 @@ public: "exceptions (0 means all)") \ range(0, max_jint/2) \ \ - develop(bool, TraceStackWalk, false, \ - "Trace stack walking") \ - \ - product(bool, MemberNameInStackFrame, true, \ - "Use MemberName in StackFrame") \ - \ /* notice: the max range value here is max_jint, not max_intx */ \ /* because of overflow issue */ \ NOT_EMBEDDED(diagnostic(intx, GuaranteedSafepointInterval, 1000, \ diff --git a/hotspot/src/share/vm/runtime/vframe.hpp b/hotspot/src/share/vm/runtime/vframe.hpp index 654d6b823b1..74c9b725811 100644 --- a/hotspot/src/share/vm/runtime/vframe.hpp +++ b/hotspot/src/share/vm/runtime/vframe.hpp @@ -317,18 +317,10 @@ class vframeStreamCommon : StackObj { intptr_t* frame_id() const { return _frame.id(); } address frame_pc() const { return _frame.pc(); } - javaVFrame* java_frame() { - vframe* vf = vframe::new_vframe(&_frame, &_reg_map, _thread); - if (vf->is_java_frame()) { - return (javaVFrame*)vf; - } - return NULL; - } - CodeBlob* cb() const { return _frame.cb(); } nmethod* nm() const { - assert( cb() != NULL && cb()->is_nmethod(), "usage"); - return (nmethod*) cb(); + assert( cb() != NULL && cb()->is_nmethod(), "usage"); + return (nmethod*) cb(); } // Frame type From f85cf9d7becb49730c3b499e3a4789e18470d1c5 Mon Sep 17 00:00:00 2001 From: Joseph Provino Date: Tue, 24 Nov 2015 15:13:02 -0500 Subject: [PATCH 076/260] 8139922: Get rid of dead code in ConcurrentMark ConcurrentMark contains lots of unused code which has been removed. Reviewed-by: jmasa, tschatzl --- hotspot/src/share/vm/gc/g1/concurrentMark.cpp | 116 +----------------- hotspot/src/share/vm/gc/g1/concurrentMark.hpp | 82 ------------- .../share/vm/gc/g1/concurrentMark.inline.hpp | 10 -- 3 files changed, 1 insertion(+), 207 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp index 4fed0ca353d..5ad17675ed3 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp @@ -74,9 +74,7 @@ HeapWord* CMBitMapRO::getNextMarkedWordAddress(const HeapWord* addr, addr = (HeapWord*)align_size_up((intptr_t)addr, HeapWordSize << _shifter); size_t addrOffset = heapWordToOffset(addr); - if (limit == NULL) { - limit = _bmStartWord + _bmWordSize; - } + assert(limit != NULL, "limit must not be NULL"); size_t limitOffset = heapWordToOffset(limit); size_t nextOffset = _bm.get_next_one_offset(addrOffset, limitOffset); HeapWord* nextAddr = offsetToHeapWord(nextOffset); @@ -86,26 +84,6 @@ HeapWord* CMBitMapRO::getNextMarkedWordAddress(const HeapWord* addr, return nextAddr; } -HeapWord* CMBitMapRO::getNextUnmarkedWordAddress(const HeapWord* addr, - const HeapWord* limit) const { - size_t addrOffset = heapWordToOffset(addr); - if (limit == NULL) { - limit = _bmStartWord + _bmWordSize; - } - size_t limitOffset = heapWordToOffset(limit); - size_t nextOffset = _bm.get_next_zero_offset(addrOffset, limitOffset); - HeapWord* nextAddr = offsetToHeapWord(nextOffset); - assert(nextAddr >= addr, "get_next_one postcondition"); - assert(nextAddr == limit || !isMarked(nextAddr), - "get_next_one postcondition"); - return nextAddr; -} - -int CMBitMapRO::heapWordDiffToOffsetDiff(size_t diff) const { - assert((diff & ((1 << _shifter) - 1)) == 0, "argument check"); - return (int) (diff >> _shifter); -} - #ifndef PRODUCT bool CMBitMapRO::covers(MemRegion heap_rs) const { // assert(_bm.map() == _virtual_space.low(), "map inconsistency"); @@ -211,17 +189,6 @@ void CMBitMap::clearAll() { return; } -void CMBitMap::markRange(MemRegion mr) { - mr.intersection(MemRegion(_bmStartWord, _bmWordSize)); - assert(!mr.is_empty(), "unexpected empty region"); - assert((offsetToHeapWord(heapWordToOffset(mr.end())) == - ((HeapWord *) mr.end())), - "markRange memory region end is not card aligned"); - // convert address range into offset range - _bm.at_put_range(heapWordToOffset(mr.start()), - heapWordToOffset(mr.end()), true); -} - void CMBitMap::clearRange(MemRegion mr) { mr.intersection(MemRegion(_bmStartWord, _bmWordSize)); assert(!mr.is_empty(), "unexpected empty region"); @@ -230,20 +197,6 @@ void CMBitMap::clearRange(MemRegion mr) { heapWordToOffset(mr.end()), false); } -MemRegion CMBitMap::getAndClearMarkedRegion(HeapWord* addr, - HeapWord* end_addr) { - HeapWord* start = getNextMarkedWordAddress(addr); - start = MIN2(start, end_addr); - HeapWord* end = getNextUnmarkedWordAddress(start); - end = MIN2(end, end_addr); - assert(start <= end, "Consistency check"); - MemRegion mr(start, end); - if (!mr.is_empty()) { - clearRange(mr); - } - return mr; -} - CMMarkStack::CMMarkStack(ConcurrentMark* cm) : _base(NULL), _cm(cm) {} @@ -466,8 +419,6 @@ ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev _max_parallel_marking_threads(0), _sleep_factor(0.0), _marking_task_overhead(1.0), - _cleanup_sleep_factor(0.0), - _cleanup_task_overhead(1.0), _cleanup_list("Cleanup List"), _region_bm((BitMap::idx_t)(g1h->max_regions()), false /* in_resource_area*/), _card_bm((g1h->reserved_region().byte_size() + CardTableModRefBS::card_size - 1) >> @@ -568,22 +519,6 @@ ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev _parallel_marking_threads = ConcGCThreads; _max_parallel_marking_threads = _parallel_marking_threads; - if (parallel_marking_threads() > 1) { - _cleanup_task_overhead = 1.0; - } else { - _cleanup_task_overhead = marking_task_overhead(); - } - _cleanup_sleep_factor = - (1.0 - cleanup_task_overhead()) / cleanup_task_overhead(); - -#if 0 - gclog_or_tty->print_cr("Marking Threads %d", parallel_marking_threads()); - gclog_or_tty->print_cr("CM Marking Task Overhead %1.4lf", marking_task_overhead()); - gclog_or_tty->print_cr("CM Sleep Factor %1.4lf", sleep_factor()); - gclog_or_tty->print_cr("CL Marking Task Overhead %1.4lf", cleanup_task_overhead()); - gclog_or_tty->print_cr("CL Sleep Factor %1.4lf", cleanup_sleep_factor()); -#endif - _parallel_workers = new WorkGang("G1 Marker", _max_parallel_marking_threads, false, true); if (_parallel_workers == NULL) { @@ -840,14 +775,6 @@ void ConcurrentMark::checkpointRootsInitialPre() { void ConcurrentMark::checkpointRootsInitialPost() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - // If we force an overflow during remark, the remark operation will - // actually abort and we'll restart concurrent marking. If we always - // force an overflow during remark we'll never actually complete the - // marking phase. So, we initialize this here, at the start of the - // cycle, so that at the remaining overflow number will decrease at - // every remark and we'll eventually not need to cause one. - force_overflow_stw()->init(); - // Start Concurrent Marking weak-reference discovery. ReferenceProcessor* rp = g1h->ref_processor_cm(); // enable ("weak") refs discovery @@ -920,7 +847,6 @@ void ConcurrentMark::enter_first_sync_barrier(uint worker_id) { // we exit this method to abort the pause and restart concurrent // marking. reset_marking_state(true /* clear_overflow */); - force_overflow()->update(); if (G1Log::fine()) { gclog_or_tty->gclog_stamp(); @@ -940,32 +866,6 @@ void ConcurrentMark::enter_second_sync_barrier(uint worker_id) { // at this point everything should be re-initialized and ready to go } -#ifndef PRODUCT -void ForceOverflowSettings::init() { - _num_remaining = G1ConcMarkForceOverflow; - _force = false; - update(); -} - -void ForceOverflowSettings::update() { - if (_num_remaining > 0) { - _num_remaining -= 1; - _force = true; - } else { - _force = false; - } -} - -bool ForceOverflowSettings::should_force() { - if (_force) { - _force = false; - return true; - } else { - return false; - } -} -#endif // !PRODUCT - class CMConcurrentMarkingTask: public AbstractGangTask { private: ConcurrentMark* _cm; @@ -1131,7 +1031,6 @@ void ConcurrentMark::markFromRoots() { // stop-the-world GC happens even as we mark in this generation. _restart_for_overflow = false; - force_overflow_conc()->init(); // _g1h has _n_par_threads _parallel_marking_threads = calc_parallel_marking_threads(); @@ -2440,10 +2339,6 @@ void ConcurrentMark::clearRangePrevBitmap(MemRegion mr) { ((CMBitMap*)_prevMarkBitMap)->clearRange(mr); } -void ConcurrentMark::clearRangeNextBitmap(MemRegion mr) { - _nextMarkBitMap->clearRange(mr); -} - HeapRegion* ConcurrentMark::claim_region(uint worker_id) { // "checkpoint" the finger @@ -3535,15 +3430,6 @@ void CMTask::do_marking_step(double time_target_ms, } } - // If we are about to wrap up and go into termination, check if we - // should raise the overflow flag. - if (do_termination && !has_aborted()) { - if (_cm->force_overflow()->should_force()) { - _cm->set_has_overflown(); - regular_clock_call(); - } - } - // We still haven't aborted. Now, let's try to get into the // termination protocol. if (do_termination && !has_aborted()) { diff --git a/hotspot/src/share/vm/gc/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc/g1/concurrentMark.hpp index d5f4fd71fe4..6a4260ed323 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMark.hpp @@ -65,11 +65,8 @@ class CMBitMapRO VALUE_OBJ_CLASS_SPEC { // constructor CMBitMapRO(int shifter); - enum { do_yield = true }; - // inquiries HeapWord* startWord() const { return _bmStartWord; } - size_t sizeInWords() const { return _bmWordSize; } // the following is one past the last word in space HeapWord* endWord() const { return _bmStartWord + _bmWordSize; } @@ -83,18 +80,12 @@ class CMBitMapRO VALUE_OBJ_CLASS_SPEC { // iteration inline bool iterate(BitMapClosure* cl, MemRegion mr); - inline bool iterate(BitMapClosure* cl); // Return the address corresponding to the next marked bit at or after // "addr", and before "limit", if "limit" is non-NULL. If there is no // such bit, returns "limit" if that is non-NULL, or else "endWord()". HeapWord* getNextMarkedWordAddress(const HeapWord* addr, const HeapWord* limit = NULL) const; - // Return the address corresponding to the next unmarked bit at or after - // "addr", and before "limit", if "limit" is non-NULL. If there is no - // such bit, returns "limit" if that is non-NULL, or else "endWord()". - HeapWord* getNextUnmarkedWordAddress(const HeapWord* addr, - const HeapWord* limit = NULL) const; // conversion utilities HeapWord* offsetToHeapWord(size_t offset) const { @@ -103,7 +94,6 @@ class CMBitMapRO VALUE_OBJ_CLASS_SPEC { size_t heapWordToOffset(const HeapWord* addr) const { return pointer_delta(addr, _bmStartWord) >> _shifter; } - int heapWordDiffToOffsetDiff(size_t diff) const; // The argument addr should be the start address of a valid object HeapWord* nextObject(HeapWord* addr) { @@ -153,20 +143,9 @@ class CMBitMap : public CMBitMapRO { inline void mark(HeapWord* addr); inline void clear(HeapWord* addr); inline bool parMark(HeapWord* addr); - inline bool parClear(HeapWord* addr); - void markRange(MemRegion mr); void clearRange(MemRegion mr); - // Starting at the bit corresponding to "addr" (inclusive), find the next - // "1" bit, if any. This bit starts some run of consecutive "1"'s; find - // the end of this run (stopping at "end_addr"). Return the MemRegion - // covering from the start of the region corresponding to the first bit - // of the run to the end of the region corresponding to the last bit of - // the run. If there is no "1" bit at or after "addr", return an empty - // MemRegion. - MemRegion getAndClearMarkedRegion(HeapWord* addr, HeapWord* end_addr); - // Clear the whole mark bitmap. void clearAll(); }; @@ -231,19 +210,6 @@ class CMMarkStack VALUE_OBJ_CLASS_SPEC { template void iterate(Fn fn); }; -class ForceOverflowSettings VALUE_OBJ_CLASS_SPEC { -private: -#ifndef PRODUCT - uintx _num_remaining; - bool _force; -#endif // !defined(PRODUCT) - -public: - void init() PRODUCT_RETURN; - void update() PRODUCT_RETURN; - bool should_force() PRODUCT_RETURN_( return false; ); -}; - class YoungList; // Root Regions are regions that are not empty at the beginning of a @@ -326,10 +292,6 @@ protected: double _marking_task_overhead; // Marking target overhead for // a single task - // Same as the two above, but for the cleanup task - double _cleanup_sleep_factor; - double _cleanup_task_overhead; - FreeRegionList _cleanup_list; // Concurrent marking support structures @@ -404,9 +366,6 @@ protected: WorkGang* _parallel_workers; - ForceOverflowSettings _force_overflow_conc; - ForceOverflowSettings _force_overflow_stw; - void weakRefsWorkParallelPart(BoolObjectClosure* is_alive, bool purged_classes); void weakRefsWork(bool clear_all_soft_refs); @@ -443,8 +402,6 @@ protected: uint max_parallel_marking_threads() const { return _max_parallel_marking_threads;} double sleep_factor() { return _sleep_factor; } double marking_task_overhead() { return _marking_task_overhead;} - double cleanup_sleep_factor() { return _cleanup_sleep_factor; } - double cleanup_task_overhead() { return _cleanup_task_overhead;} HeapWord* finger() { return _finger; } bool concurrent() { return _concurrent; } @@ -502,22 +459,6 @@ protected: void enter_first_sync_barrier(uint worker_id); void enter_second_sync_barrier(uint worker_id); - ForceOverflowSettings* force_overflow_conc() { - return &_force_overflow_conc; - } - - ForceOverflowSettings* force_overflow_stw() { - return &_force_overflow_stw; - } - - ForceOverflowSettings* force_overflow() { - if (concurrent()) { - return force_overflow_conc(); - } else { - return force_overflow_stw(); - } - } - // Live Data Counting data structures... // These data structures are initialized at the start of // marking. They are written to while marking is active. @@ -625,28 +566,6 @@ public: uint worker_id, HeapRegion* hr = NULL); - // It iterates over the heap and for each object it comes across it - // will dump the contents of its reference fields, as well as - // liveness information for the object and its referents. The dump - // will be written to a file with the following name: - // G1PrintReachableBaseFile + "." + str. - // vo decides whether the prev (vo == UsePrevMarking), the next - // (vo == UseNextMarking) marking information, or the mark word - // (vo == UseMarkWord) will be used to determine the liveness of - // each object / referent. - // If all is true, all objects in the heap will be dumped, otherwise - // only the live ones. In the dump the following symbols / breviations - // are used: - // M : an explicitly live object (its bitmap bit is set) - // > : an implicitly live object (over tams) - // O : an object outside the G1 heap (typically: in the perm gen) - // NOT : a reference field whose referent is not live - // AND MARKED : indicates that an object is both explicitly and - // implicitly live (it should be one or the other, not both) - void print_reachable(const char* str, - VerifyOption vo, - bool all) PRODUCT_RETURN; - // Clear the next marking bitmap (will be called concurrently). void clearNextBitmap(); @@ -686,7 +605,6 @@ public: // next bitmaps. NB: the previous bitmap is usually // read-only, so use this carefully! void clearRangePrevBitmap(MemRegion mr); - void clearRangeNextBitmap(MemRegion mr); // Notify data structures that a GC has started. void note_start_of_gc() { diff --git a/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp b/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp index c75f6898713..fe26975cc20 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp @@ -185,11 +185,6 @@ inline bool CMBitMapRO::iterate(BitMapClosure* cl, MemRegion mr) { return true; } -inline bool CMBitMapRO::iterate(BitMapClosure* cl) { - MemRegion mr(startWord(), sizeInWords()); - return iterate(cl, mr); -} - #define check_mark(addr) \ assert(_bmStartWord <= (addr) && (addr) < (_bmStartWord + _bmWordSize), \ "outside underlying space?"); \ @@ -213,11 +208,6 @@ inline bool CMBitMap::parMark(HeapWord* addr) { return _bm.par_set_bit(heapWordToOffset(addr)); } -inline bool CMBitMap::parClear(HeapWord* addr) { - check_mark(addr); - return _bm.par_clear_bit(heapWordToOffset(addr)); -} - #undef check_mark template From dea766f3326316b01841cec5ac0a451112a6344a Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Tue, 24 Nov 2015 15:58:26 -0500 Subject: [PATCH 077/260] 8143233: [windows] Fixes to os::check_heap() Reviewed-by: dholmes, ctornqvi --- hotspot/src/os/windows/vm/os_windows.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 45a9bb11d0b..2969e74d052 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -5254,7 +5254,13 @@ bool os::check_heap(bool force) { // Note: HeapValidate executes two hardware breakpoints when it finds something // wrong; at these points, eax contains the address of the offending block (I think). // To get to the exlicit error message(s) below, just continue twice. - HANDLE heap = GetProcessHeap(); + // + // Note: we want to check the CRT heap, which is not necessarily located in the + // process default heap. + HANDLE heap = (HANDLE) _get_heap_handle(); + if (!heap) { + return true; + } // If we fail to lock the heap, then gflags.exe has been used // or some other special heap flag has been set that prevents @@ -5267,11 +5273,13 @@ bool os::check_heap(bool force) { !HeapValidate(heap, 0, phe.lpData)) { tty->print_cr("C heap has been corrupted (time: %d allocations)", mallocDebugCounter); tty->print_cr("corrupted block near address %#x, length %d", phe.lpData, phe.cbData); + HeapUnlock(heap); fatal("corrupted C heap"); } } DWORD err = GetLastError(); if (err != ERROR_NO_MORE_ITEMS && err != ERROR_CALL_NOT_IMPLEMENTED) { + HeapUnlock(heap); fatal("heap walk aborted with error %d", err); } HeapUnlock(heap); From 2b732b223e7ef41a7cbe2cdc99f588cb3252b3b6 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Tue, 24 Nov 2015 14:59:17 -0800 Subject: [PATCH 078/260] 8143911: Reintegrate JEP 259: Stack-Walking API Co-authored-by: Brent Christian Co-authored-by: Daniel Fuchs Co-authored-by: Hamlin Li Reviewed-by: coleenp, dfuchs, bchristi, psandoz, sspitsyn --- hotspot/make/share/makefiles/mapfile-vers | 4 + .../src/share/vm/classfile/javaClasses.cpp | 224 +++++++-- .../src/share/vm/classfile/javaClasses.hpp | 83 +++- .../share/vm/classfile/javaClasses.inline.hpp | 63 +++ .../share/vm/classfile/systemDictionary.hpp | 8 +- hotspot/src/share/vm/classfile/vmSymbols.hpp | 29 ++ hotspot/src/share/vm/memory/universe.cpp | 14 + hotspot/src/share/vm/memory/universe.hpp | 3 + hotspot/src/share/vm/prims/jvm.cpp | 89 ++++ hotspot/src/share/vm/prims/jvm.h | 31 ++ hotspot/src/share/vm/prims/stackwalk.cpp | 470 ++++++++++++++++++ hotspot/src/share/vm/prims/stackwalk.hpp | 102 ++++ hotspot/src/share/vm/runtime/globals.hpp | 6 + hotspot/src/share/vm/runtime/vframe.hpp | 12 +- 14 files changed, 1080 insertions(+), 58 deletions(-) create mode 100644 hotspot/src/share/vm/prims/stackwalk.cpp create mode 100644 hotspot/src/share/vm/prims/stackwalk.hpp diff --git a/hotspot/make/share/makefiles/mapfile-vers b/hotspot/make/share/makefiles/mapfile-vers index 7021e53d444..9672bfe3fc9 100644 --- a/hotspot/make/share/makefiles/mapfile-vers +++ b/hotspot/make/share/makefiles/mapfile-vers @@ -7,6 +7,7 @@ JVM_ActiveProcessorCount; JVM_ArrayCopy; JVM_AssertionStatusDirectives; + JVM_CallStackWalk; JVM_ClassDepth; JVM_ClassLoaderDepth; JVM_Clone; @@ -36,6 +37,7 @@ JVM_DumpAllStacks; JVM_DumpThreads; JVM_FillInStackTrace; + JVM_FillStackFrames; JVM_FindClassFromCaller; JVM_FindClassFromClass; JVM_FindClassFromBootLoader; @@ -133,6 +135,7 @@ JVM_MonitorNotify; JVM_MonitorNotifyAll; JVM_MonitorWait; + JVM_MoreStackWalk; JVM_NanoTime; JVM_NativePath; JVM_NewArray; @@ -150,6 +153,7 @@ JVM_SetClassSigners; JVM_SetNativeThreadName; JVM_SetPrimitiveArrayElement; + JVM_SetMethodInfo; JVM_SetThreadPriority; JVM_Sleep; JVM_StartThread; diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index a9f7c4616c6..242bafdfc53 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -1518,43 +1518,11 @@ void java_lang_Throwable::print(Handle throwable, outputStream* st) { // After this many redefines, the stack trace is unreliable. const int MAX_VERSION = USHRT_MAX; -// Helper backtrace functions to store bci|version together. -static inline int merge_bci_and_version(int bci, int version) { - // only store u2 for version, checking for overflow. - if (version > USHRT_MAX || version < 0) version = MAX_VERSION; - assert((jushort)bci == bci, "bci should be short"); - return build_int_from_shorts(version, bci); -} - -static inline int bci_at(unsigned int merged) { - return extract_high_short_from_int(merged); -} -static inline int version_at(unsigned int merged) { - return extract_low_short_from_int(merged); -} - static inline bool version_matches(Method* method, int version) { assert(version < MAX_VERSION, "version is too big"); return method != NULL && (method->constants()->version() == version); } -static inline int get_line_number(Method* method, int bci) { - int line_number = 0; - if (method->is_native()) { - // Negative value different from -1 below, enabling Java code in - // class java.lang.StackTraceElement to distinguish "native" from - // "no LineNumberTable". JDK tests for -2. - line_number = -2; - } else { - // Returns -1 if no LineNumberTable, and otherwise actual line number - line_number = method->line_number_from_bci(bci); - if (line_number == -1 && ShowHiddenFrames) { - line_number = bci + 1000000; - } - } - return line_number; -} - // This class provides a simple wrapper over the internal structure of // exception backtrace to insulate users of the backtrace from needing // to know what it looks like. @@ -1676,7 +1644,7 @@ class BacktraceBuilder: public StackObj { } _methods->short_at_put(_index, method->orig_method_idnum()); - _bcis->int_at_put(_index, merge_bci_and_version(bci, method->constants()->version())); + _bcis->int_at_put(_index, Backtrace::merge_bci_and_version(bci, method->constants()->version())); _cprefs->short_at_put(_index, method->name_index()); // We need to save the mirrors in the backtrace to keep the class @@ -1688,19 +1656,6 @@ class BacktraceBuilder: public StackObj { }; -Symbol* get_source_file_name(InstanceKlass* holder, int version) { - // Find the specific ik version that contains this source_file_name_index - // via the previous versions list, but use the current version's - // constant pool to look it up. The previous version's index has been - // merged for the current constant pool. - InstanceKlass* ik = holder->get_klass_version(version); - // This version has been cleaned up. - if (ik == NULL) return NULL; - int source_file_name_index = ik->source_file_name_index(); - return (source_file_name_index == 0) ? - (Symbol*)NULL : holder->constants()->symbol_at(source_file_name_index); -} - // Print stack trace element to resource allocated buffer char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, int method_id, int version, int bci, int cpref) { @@ -1718,7 +1673,7 @@ char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, buf_len += (int)strlen(method_name); char* source_file_name = NULL; - Symbol* source = get_source_file_name(holder, version); + Symbol* source = Backtrace::get_source_file_name(holder, version); if (source != NULL) { source_file_name = source->as_C_string(); buf_len += (int)strlen(source_file_name); @@ -1733,7 +1688,7 @@ char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, if (!version_matches(method, version)) { strcat(buf, "(Redefined)"); } else { - int line_number = get_line_number(method, bci); + int line_number = Backtrace::get_line_number(method, bci); if (line_number == -2) { strcat(buf, "(Native Method)"); } else { @@ -1802,8 +1757,8 @@ void java_lang_Throwable::print_stack_trace(oop throwable, outputStream* st) { // NULL mirror means end of stack trace if (mirror.is_null()) goto handle_cause; int method = methods->short_at(index); - int version = version_at(bcis->int_at(index)); - int bci = bci_at(bcis->int_at(index)); + int version = Backtrace::version_at(bcis->int_at(index)); + int bci = Backtrace::bci_at(bcis->int_at(index)); int cpref = cprefs->short_at(index); print_stack_element(st, mirror, method, version, bci, cpref); } @@ -2090,8 +2045,8 @@ oop java_lang_Throwable::get_stack_trace_element(oop throwable, int index, TRAPS assert(methods != NULL && bcis != NULL && mirrors != NULL, "sanity check"); int method = methods->short_at(chunk_index); - int version = version_at(bcis->int_at(chunk_index)); - int bci = bci_at(bcis->int_at(chunk_index)); + int version = Backtrace::version_at(bcis->int_at(chunk_index)); + int bci = Backtrace::bci_at(bcis->int_at(chunk_index)); int cpref = cprefs->short_at(chunk_index); Handle mirror(THREAD, mirrors->obj_at(chunk_index)); @@ -2114,6 +2069,7 @@ oop java_lang_StackTraceElement::create(Handle mirror, int method_id, } Handle element = ik->allocate_instance_handle(CHECK_0); + // Fill in class name ResourceMark rm(THREAD); InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); @@ -2136,13 +2092,13 @@ oop java_lang_StackTraceElement::create(Handle mirror, int method_id, java_lang_StackTraceElement::set_lineNumber(element(), -1); } else { // Fill in source file name and line number. - Symbol* source = get_source_file_name(holder, version); + Symbol* source = Backtrace::get_source_file_name(holder, version); if (ShowHiddenFrames && source == NULL) source = vmSymbols::unknown_class_name(); oop filename = StringTable::intern(source, CHECK_0); java_lang_StackTraceElement::set_fileName(element(), filename); - int line_number = get_line_number(method, bci); + int line_number = Backtrace::get_line_number(method, bci); java_lang_StackTraceElement::set_lineNumber(element(), line_number); } return element(); @@ -2155,6 +2111,108 @@ oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, TRA return create(mirror, method_id, method->constants()->version(), bci, cpref, THREAD); } +Method* java_lang_StackFrameInfo::get_method(Handle stackFrame, InstanceKlass* holder, TRAPS) { + if (MemberNameInStackFrame) { + Handle mname(THREAD, stackFrame->obj_field(_memberName_offset)); + Method* method = (Method*)java_lang_invoke_MemberName::vmtarget(mname()); + // we should expand MemberName::name when Throwable uses StackTrace + // MethodHandles::expand_MemberName(mname, MethodHandles::_suppress_defc|MethodHandles::_suppress_type, CHECK_NULL); + return method; + } else { + short mid = stackFrame->short_field(_mid_offset); + short version = stackFrame->short_field(_version_offset); + return holder->method_with_orig_idnum(mid, version); + } +} + +Symbol* java_lang_StackFrameInfo::get_file_name(Handle stackFrame, InstanceKlass* holder) { + if (MemberNameInStackFrame) { + return holder->source_file_name(); + } else { + short version = stackFrame->short_field(_version_offset); + return Backtrace::get_source_file_name(holder, version); + } +} + +void java_lang_StackFrameInfo::set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci) { + // set Method* or mid/cpref + if (MemberNameInStackFrame) { + oop mname = stackFrame->obj_field(_memberName_offset); + InstanceKlass* ik = method->method_holder(); + CallInfo info(method(), ik); + MethodHandles::init_method_MemberName(mname, info); + } else { + int mid = method->orig_method_idnum(); + int cpref = method->name_index(); + assert((jushort)mid == mid, "mid should be short"); + assert((jushort)cpref == cpref, "cpref should be short"); + java_lang_StackFrameInfo::set_mid(stackFrame(), (short)mid); + java_lang_StackFrameInfo::set_cpref(stackFrame(), (short)cpref); + } + // set bci + java_lang_StackFrameInfo::set_bci(stackFrame(), bci); + // method may be redefined; store the version + int version = method->constants()->version(); + assert((jushort)version == version, "version should be short"); + java_lang_StackFrameInfo::set_version(stackFrame(), (short)version); +} + +void java_lang_StackFrameInfo::fill_methodInfo(Handle stackFrame, TRAPS) { + ResourceMark rm(THREAD); + oop k = stackFrame->obj_field(_declaringClass_offset); + InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(k)); + Method* method = java_lang_StackFrameInfo::get_method(stackFrame, holder, CHECK); + int bci = stackFrame->int_field(_bci_offset); + + // The method can be NULL if the requested class version is gone + Symbol* sym = (method != NULL) ? method->name() : NULL; + if (MemberNameInStackFrame) { + assert(sym != NULL, "MemberName must have method name"); + } else { + // The method can be NULL if the requested class version is gone + if (sym == NULL) { + short cpref = stackFrame->short_field(_cpref_offset); + sym = holder->constants()->symbol_at(cpref); + } + } + + // set method name + oop methodname = StringTable::intern(sym, CHECK); + java_lang_StackFrameInfo::set_methodName(stackFrame(), methodname); + + // set file name and line number + Symbol* source = get_file_name(stackFrame, holder); + if (source != NULL) { + oop filename = StringTable::intern(source, CHECK); + java_lang_StackFrameInfo::set_fileName(stackFrame(), filename); + } + + // if the method has been redefined, the bci is no longer applicable + short version = stackFrame->short_field(_version_offset); + if (version_matches(method, version)) { + int line_number = Backtrace::get_line_number(method, bci); + java_lang_StackFrameInfo::set_lineNumber(stackFrame(), line_number); + } +} + +void java_lang_StackFrameInfo::compute_offsets() { + Klass* k = SystemDictionary::StackFrameInfo_klass(); + compute_offset(_declaringClass_offset, k, vmSymbols::declaringClass_name(), vmSymbols::class_signature()); + compute_offset(_memberName_offset, k, vmSymbols::memberName_name(), vmSymbols::object_signature()); + compute_offset(_bci_offset, k, vmSymbols::bci_name(), vmSymbols::int_signature()); + compute_offset(_methodName_offset, k, vmSymbols::methodName_name(), vmSymbols::string_signature()); + compute_offset(_fileName_offset, k, vmSymbols::fileName_name(), vmSymbols::string_signature()); + compute_offset(_lineNumber_offset, k, vmSymbols::lineNumber_name(), vmSymbols::int_signature()); + STACKFRAMEINFO_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); +} + +void java_lang_LiveStackFrameInfo::compute_offsets() { + Klass* k = SystemDictionary::LiveStackFrameInfo_klass(); + compute_offset(_monitors_offset, k, vmSymbols::monitors_name(), vmSymbols::object_array_signature()); + compute_offset(_locals_offset, k, vmSymbols::locals_name(), vmSymbols::object_array_signature()); + compute_offset(_operands_offset, k, vmSymbols::operands_name(), vmSymbols::object_array_signature()); +} + void java_lang_reflect_AccessibleObject::compute_offsets() { Klass* k = SystemDictionary::reflect_AccessibleObject_klass(); compute_offset(override_offset, k, vmSymbols::override_name(), vmSymbols::bool_signature()); @@ -3471,6 +3529,18 @@ int java_lang_StackTraceElement::declaringClass_offset; int java_lang_StackTraceElement::methodName_offset; int java_lang_StackTraceElement::fileName_offset; int java_lang_StackTraceElement::lineNumber_offset; +int java_lang_StackFrameInfo::_declaringClass_offset; +int java_lang_StackFrameInfo::_memberName_offset; +int java_lang_StackFrameInfo::_bci_offset; +int java_lang_StackFrameInfo::_methodName_offset; +int java_lang_StackFrameInfo::_fileName_offset; +int java_lang_StackFrameInfo::_lineNumber_offset; +int java_lang_StackFrameInfo::_mid_offset; +int java_lang_StackFrameInfo::_version_offset; +int java_lang_StackFrameInfo::_cpref_offset; +int java_lang_LiveStackFrameInfo::_monitors_offset; +int java_lang_LiveStackFrameInfo::_locals_offset; +int java_lang_LiveStackFrameInfo::_operands_offset; int java_lang_AssertionStatusDirectives::classes_offset; int java_lang_AssertionStatusDirectives::classEnabled_offset; int java_lang_AssertionStatusDirectives::packages_offset; @@ -3500,6 +3570,50 @@ void java_lang_StackTraceElement::set_lineNumber(oop element, int value) { element->int_field_put(lineNumber_offset, value); } +// Support for java_lang_StackFrameInfo +void java_lang_StackFrameInfo::set_declaringClass(oop element, oop value) { + element->obj_field_put(_declaringClass_offset, value); +} + +void java_lang_StackFrameInfo::set_mid(oop element, short value) { + element->short_field_put(_mid_offset, value); +} + +void java_lang_StackFrameInfo::set_version(oop element, short value) { + element->short_field_put(_version_offset, value); +} + +void java_lang_StackFrameInfo::set_cpref(oop element, short value) { + element->short_field_put(_cpref_offset, value); +} + +void java_lang_StackFrameInfo::set_bci(oop element, int value) { + element->int_field_put(_bci_offset, value); +} + +void java_lang_StackFrameInfo::set_fileName(oop element, oop value) { + element->obj_field_put(_fileName_offset, value); +} + +void java_lang_StackFrameInfo::set_methodName(oop element, oop value) { + element->obj_field_put(_methodName_offset, value); +} + +void java_lang_StackFrameInfo::set_lineNumber(oop element, int value) { + element->int_field_put(_lineNumber_offset, value); +} + +void java_lang_LiveStackFrameInfo::set_monitors(oop element, oop value) { + element->obj_field_put(_monitors_offset, value); +} + +void java_lang_LiveStackFrameInfo::set_locals(oop element, oop value) { + element->obj_field_put(_locals_offset, value); +} + +void java_lang_LiveStackFrameInfo::set_operands(oop element, oop value) { + element->obj_field_put(_operands_offset, value); +} // Support for java Assertions - java_lang_AssertionStatusDirectives. @@ -3633,6 +3747,8 @@ void JavaClasses::compute_offsets() { sun_reflect_ConstantPool::compute_offsets(); sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets(); java_lang_reflect_Parameter::compute_offsets(); + java_lang_StackFrameInfo::compute_offsets(); + java_lang_LiveStackFrameInfo::compute_offsets(); // generated interpreter code wants to know about the offsets we just computed: AbstractAssembler::update_delayed_values(); diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 403e33e9ee3..8e66cccf695 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -1359,6 +1359,85 @@ class java_lang_StackTraceElement: AllStatic { }; +class Backtrace: AllStatic { + public: + // Helper backtrace functions to store bci|version together. + static int merge_bci_and_version(int bci, int version); + static int merge_mid_and_cpref(int mid, int cpref); + static int bci_at(unsigned int merged); + static int version_at(unsigned int merged); + static int mid_at(unsigned int merged); + static int cpref_at(unsigned int merged); + static int get_line_number(const methodHandle& method, int bci); + static Symbol* get_source_file_name(InstanceKlass* holder, int version); + + // Debugging + friend class JavaClasses; +}; + +// Interface to java.lang.StackFrameInfo objects + +#define STACKFRAMEINFO_INJECTED_FIELDS(macro) \ + macro(java_lang_StackFrameInfo, mid, short_signature, false) \ + macro(java_lang_StackFrameInfo, version, short_signature, false) \ + macro(java_lang_StackFrameInfo, cpref, short_signature, false) + +class java_lang_StackFrameInfo: AllStatic { +private: + static int _declaringClass_offset; + static int _memberName_offset; + static int _bci_offset; + static int _methodName_offset; + static int _fileName_offset; + static int _lineNumber_offset; + + static int _mid_offset; + static int _version_offset; + static int _cpref_offset; + + static Method* get_method(Handle stackFrame, InstanceKlass* holder, TRAPS); + static Symbol* get_file_name(Handle stackFrame, InstanceKlass* holder); + +public: + // Setters + static void set_declaringClass(oop info, oop value); + static void set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci); + static void set_bci(oop info, int value); + + // set method info in an instance of StackFrameInfo + static void fill_methodInfo(Handle info, TRAPS); + static void set_methodName(oop info, oop value); + static void set_fileName(oop info, oop value); + static void set_lineNumber(oop info, int value); + + // these injected fields are only used if -XX:-MemberNameInStackFrame set + static void set_mid(oop info, short value); + static void set_version(oop info, short value); + static void set_cpref(oop info, short value); + + static void compute_offsets(); + + // Debugging + friend class JavaClasses; +}; + +class java_lang_LiveStackFrameInfo: AllStatic { + private: + static int _monitors_offset; + static int _locals_offset; + static int _operands_offset; + + public: + static void set_monitors(oop info, oop value); + static void set_locals(oop info, oop value); + static void set_operands(oop info, oop value); + + static void compute_offsets(); + + // Debugging + friend class JavaClasses; +}; + // Interface to java.lang.AssertionStatusDirectives objects class java_lang_AssertionStatusDirectives: AllStatic { @@ -1442,7 +1521,9 @@ class InjectedField { CLASS_INJECTED_FIELDS(macro) \ CLASSLOADER_INJECTED_FIELDS(macro) \ MEMBERNAME_INJECTED_FIELDS(macro) \ - CALLSITECONTEXT_INJECTED_FIELDS(macro) + CALLSITECONTEXT_INJECTED_FIELDS(macro) \ + STACKFRAMEINFO_INJECTED_FIELDS(macro) + // Interface to hard-coded offset checking diff --git a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp index 723c2e86757..ac35ccb8439 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp @@ -73,4 +73,67 @@ inline bool java_lang_invoke_DirectMethodHandle::is_instance(oop obj) { return obj != NULL && is_subclass(obj->klass()); } +inline int Backtrace::merge_bci_and_version(int bci, int version) { + // only store u2 for version, checking for overflow. + if (version > USHRT_MAX || version < 0) version = USHRT_MAX; + assert((jushort)bci == bci, "bci should be short"); + return build_int_from_shorts(version, bci); +} + +inline int Backtrace::merge_mid_and_cpref(int mid, int cpref) { + // only store u2 for mid and cpref, checking for overflow. + assert((jushort)mid == mid, "mid should be short"); + assert((jushort)cpref == cpref, "cpref should be short"); + return build_int_from_shorts(cpref, mid); +} + +inline int Backtrace::bci_at(unsigned int merged) { + return extract_high_short_from_int(merged); +} + +inline int Backtrace::version_at(unsigned int merged) { + return extract_low_short_from_int(merged); +} + +inline int Backtrace::mid_at(unsigned int merged) { + return extract_high_short_from_int(merged); +} + +inline int Backtrace::cpref_at(unsigned int merged) { + return extract_low_short_from_int(merged); +} + +inline int Backtrace::get_line_number(const methodHandle& method, int bci) { + int line_number = 0; + if (method->is_native()) { + // Negative value different from -1 below, enabling Java code in + // class java.lang.StackTraceElement to distinguish "native" from + // "no LineNumberTable". JDK tests for -2. + line_number = -2; + } else { + // Returns -1 if no LineNumberTable, and otherwise actual line number + line_number = method->line_number_from_bci(bci); + if (line_number == -1 && ShowHiddenFrames) { + line_number = bci + 1000000; + } + } + return line_number; +} + +/* + * Returns the source file name of a given InstanceKlass and version + */ +inline Symbol* Backtrace::get_source_file_name(InstanceKlass* holder, int version) { + // Find the specific ik version that contains this source_file_name_index + // via the previous versions list, but use the current version's + // constant pool to look it up. The previous version's index has been + // merged for the current constant pool. + InstanceKlass* ik = holder->get_klass_version(version); + // This version has been cleaned up. + if (ik == NULL) return NULL; + int source_file_name_index = ik->source_file_name_index(); + return (source_file_name_index == 0) ? + (Symbol*)NULL : holder->constants()->symbol_at(source_file_name_index); +} + #endif // SHARE_VM_CLASSFILE_JAVACLASSES_INLINE_HPP diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index e735f095dbe..41811e343cd 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -180,11 +180,17 @@ class Ticks; do_klass(sun_misc_Launcher_klass, sun_misc_Launcher, Pre ) \ do_klass(CodeSource_klass, java_security_CodeSource, Pre ) \ \ - /* It's NULL in non-1.4 JDKs. */ \ do_klass(StackTraceElement_klass, java_lang_StackTraceElement, Opt ) \ + \ /* It's okay if this turns out to be NULL in non-1.4 JDKs. */ \ do_klass(nio_Buffer_klass, java_nio_Buffer, Opt ) \ \ + /* Stack Walking */ \ + do_klass(StackWalker_klass, java_lang_StackWalker, Opt ) \ + do_klass(AbstractStackWalker_klass, java_lang_StackStreamFactory_AbstractStackWalker, Opt ) \ + do_klass(StackFrameInfo_klass, java_lang_StackFrameInfo, Opt ) \ + do_klass(LiveStackFrameInfo_klass, java_lang_LiveStackFrameInfo, Opt ) \ + \ /* Preload boxing klasses */ \ do_klass(Boolean_klass, java_lang_Boolean, Pre ) \ do_klass(Character_klass, java_lang_Character, Pre ) \ diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index ee081869579..dc31c3b3527 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -311,6 +311,22 @@ /* Support for JVMCI */ \ JVMCI_VM_SYMBOLS_DO(template, do_alias) \ \ + template(java_lang_StackWalker, "java/lang/StackWalker") \ + template(java_lang_StackFrameInfo, "java/lang/StackFrameInfo") \ + template(java_lang_LiveStackFrameInfo, "java/lang/LiveStackFrameInfo") \ + template(java_lang_StackStreamFactory_AbstractStackWalker, "java/lang/StackStreamFactory$AbstractStackWalker") \ + template(doStackWalk_name, "doStackWalk") \ + template(doStackWalk_signature, "(JIIII)Ljava/lang/Object;") \ + template(asPrimitive_name, "asPrimitive") \ + template(asPrimitive_int_signature, "(I)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + template(asPrimitive_long_signature, "(J)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + template(asPrimitive_short_signature, "(S)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + template(asPrimitive_byte_signature, "(B)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + template(asPrimitive_char_signature, "(C)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + template(asPrimitive_float_signature, "(F)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + template(asPrimitive_double_signature, "(D)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + template(asPrimitive_boolean_signature, "(Z)Ljava/lang/LiveStackFrame$PrimitiveValue;") \ + \ /* common method and field names */ \ template(object_initializer_name, "") \ template(class_initializer_name, "") \ @@ -411,6 +427,18 @@ template(append_name, "append") \ template(klass_name, "klass") \ template(array_klass_name, "array_klass") \ + template(declaringClass_name, "declaringClass") \ + template(memberName_name, "memberName") \ + template(mid_name, "mid") \ + template(cpref_name, "cpref") \ + template(version_name, "version") \ + template(bci_name, "bci") \ + template(methodName_name, "methodName") \ + template(fileName_name, "fileName") \ + template(lineNumber_name, "lineNumber") \ + template(monitors_name, "monitors") \ + template(locals_name, "locals") \ + template(operands_name, "operands") \ template(oop_size_name, "oop_size") \ template(static_oop_field_count_name, "static_oop_field_count") \ template(protection_domain_name, "protection_domain") \ @@ -515,6 +543,7 @@ template(class_array_signature, "[Ljava/lang/Class;") \ template(classloader_signature, "Ljava/lang/ClassLoader;") \ template(object_signature, "Ljava/lang/Object;") \ + template(object_array_signature, "[Ljava/lang/Object;") \ template(class_signature, "Ljava/lang/Class;") \ template(string_signature, "Ljava/lang/String;") \ template(reference_signature, "Ljava/lang/ref/Reference;") \ diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index 7ec9cfa3a99..d06a7fbddc3 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -115,6 +115,7 @@ LatestMethodCache* Universe::_finalizer_register_cache = NULL; LatestMethodCache* Universe::_loader_addClass_cache = NULL; LatestMethodCache* Universe::_pd_implies_cache = NULL; LatestMethodCache* Universe::_throw_illegal_access_error_cache = NULL; +LatestMethodCache* Universe::_do_stack_walk_cache = NULL; oop Universe::_out_of_memory_error_java_heap = NULL; oop Universe::_out_of_memory_error_metaspace = NULL; oop Universe::_out_of_memory_error_class_metaspace = NULL; @@ -240,6 +241,7 @@ void Universe::serialize(SerializeClosure* f, bool do_all) { _loader_addClass_cache->serialize(f); _pd_implies_cache->serialize(f); _throw_illegal_access_error_cache->serialize(f); + _do_stack_walk_cache->serialize(f); } void Universe::check_alignment(uintx size, uintx alignment, const char* name) { @@ -674,6 +676,7 @@ jint universe_init() { Universe::_loader_addClass_cache = new LatestMethodCache(); Universe::_pd_implies_cache = new LatestMethodCache(); Universe::_throw_illegal_access_error_cache = new LatestMethodCache(); + Universe::_do_stack_walk_cache = new LatestMethodCache(); if (UseSharedSpaces) { // Read the data structures supporting the shared spaces (shared @@ -1048,6 +1051,17 @@ bool universe_post_init() { SystemDictionary::ProtectionDomain_klass(), m); } + // Setup method for stack walking + InstanceKlass::cast(SystemDictionary::AbstractStackWalker_klass())->link_class(CHECK_false); + m = InstanceKlass::cast(SystemDictionary::AbstractStackWalker_klass())-> + find_method(vmSymbols::doStackWalk_name(), + vmSymbols::doStackWalk_signature()); + // Allow NULL which should only happen with bootstrapping. + if (m != NULL) { + Universe::_do_stack_walk_cache->init( + SystemDictionary::AbstractStackWalker_klass(), m); + } + // This needs to be done before the first scavenge/gc, since // it's an input to soft ref clearing policy. { diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index 854a818883c..f2dc42e6cfe 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -149,6 +149,7 @@ class Universe: AllStatic { static LatestMethodCache* _loader_addClass_cache; // method for registering loaded classes in class loader vector static LatestMethodCache* _pd_implies_cache; // method for checking protection domain attributes static LatestMethodCache* _throw_illegal_access_error_cache; // Unsafe.throwIllegalAccessError() method + static LatestMethodCache* _do_stack_walk_cache; // method for stack walker callback // preallocated error objects (no backtrace) static oop _out_of_memory_error_java_heap; @@ -314,6 +315,8 @@ class Universe: AllStatic { static Method* protection_domain_implies_method() { return _pd_implies_cache->get_method(); } static Method* throw_illegal_access_error() { return _throw_illegal_access_error_cache->get_method(); } + static Method* do_stack_walk_method() { return _do_stack_walk_cache->get_method(); } + static oop null_ptr_exception_instance() { return _null_ptr_exception_instance; } static oop arithmetic_exception_instance() { return _arithmetic_exception_instance; } static oop virtual_machine_error_instance() { return _virtual_machine_error_instance; } diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 45db3542ec2..f6442b98574 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -46,6 +46,7 @@ #include "prims/jvmtiThreadState.hpp" #include "prims/nativeLookup.hpp" #include "prims/privilegedStack.hpp" +#include "prims/stackwalk.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/handles.inline.hpp" @@ -547,6 +548,94 @@ JVM_ENTRY(jobject, JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint JVM_END +// java.lang.StackWalker ////////////////////////////////////////////////////// + + +JVM_ENTRY(jobject, JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode, + jint skip_frames, jint frame_count, jint start_index, + jobjectArray classes, + jobjectArray frames)) + JVMWrapper("JVM_CallStackWalk"); + JavaThread* jt = (JavaThread*) THREAD; + if (!jt->is_Java_thread() || !jt->has_last_Java_frame()) { + THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: no stack trace", NULL); + } + + Handle stackStream_h(THREAD, JNIHandles::resolve_non_null(stackStream)); + objArrayOop ca = objArrayOop(JNIHandles::resolve_non_null(classes)); + objArrayHandle classes_array_h(THREAD, ca); + + // frames array is null when only getting caller reference + objArrayOop fa = objArrayOop(JNIHandles::resolve(frames)); + objArrayHandle frames_array_h(THREAD, fa); + + int limit = start_index + frame_count; + if (classes_array_h->length() < limit) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers", NULL); + } + + Handle result = StackWalk::walk(stackStream_h, mode, skip_frames, frame_count, + start_index, classes_array_h, + frames_array_h, CHECK_NULL); + return JNIHandles::make_local(env, result()); +JVM_END + + +JVM_ENTRY(jint, JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor, + jint frame_count, jint start_index, + jobjectArray classes, + jobjectArray frames)) + JVMWrapper("JVM_MoreStackWalk"); + JavaThread* jt = (JavaThread*) THREAD; + objArrayOop ca = objArrayOop(JNIHandles::resolve_non_null(classes)); + objArrayHandle classes_array_h(THREAD, ca); + + // frames array is null when only getting caller reference + objArrayOop fa = objArrayOop(JNIHandles::resolve(frames)); + objArrayHandle frames_array_h(THREAD, fa); + + int limit = start_index+frame_count; + if (classes_array_h->length() < limit) { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "not enough space in buffers"); + } + + Handle stackStream_h(THREAD, JNIHandles::resolve_non_null(stackStream)); + return StackWalk::moreFrames(stackStream_h, mode, anchor, frame_count, + start_index, classes_array_h, + frames_array_h, THREAD); +JVM_END + +JVM_ENTRY(void, JVM_FillStackFrames(JNIEnv *env, jclass stackStream, + jint start_index, + jobjectArray frames, + jint from_index, jint to_index)) + JVMWrapper("JVM_FillStackFrames"); + if (TraceStackWalk) { + tty->print("JVM_FillStackFrames() start_index=%d from_index=%d to_index=%d\n", + start_index, from_index, to_index); + } + + JavaThread* jt = (JavaThread*) THREAD; + + objArrayOop fa = objArrayOop(JNIHandles::resolve_non_null(frames)); + objArrayHandle frames_array_h(THREAD, fa); + + if (frames_array_h->length() < to_index) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "array length not matched"); + } + + for (int i = from_index; i < to_index; i++) { + Handle stackFrame(THREAD, frames_array_h->obj_at(i)); + java_lang_StackFrameInfo::fill_methodInfo(stackFrame, CHECK); + } +JVM_END + +JVM_ENTRY(void, JVM_SetMethodInfo(JNIEnv *env, jobject frame)) + JVMWrapper("JVM_SetMethodInfo"); + Handle stackFrame(THREAD, JNIHandles::resolve(frame)); + java_lang_StackFrameInfo::fill_methodInfo(stackFrame, THREAD); +JVM_END + // java.lang.Object /////////////////////////////////////////////// diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index bc42dbf3edb..021f55dccb3 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -200,6 +200,37 @@ JVM_GetStackTraceDepth(JNIEnv *env, jobject throwable); JNIEXPORT jobject JNICALL JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint index); +/* + * java.lang.StackWalker + */ +enum { + JVM_STACKWALK_FILL_CLASS_REFS_ONLY = 0x2, + JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE = 0x10, + JVM_STACKWALK_SHOW_HIDDEN_FRAMES = 0x20, + JVM_STACKWALK_FILL_LIVE_STACK_FRAMES = 0x100 +}; + +JNIEXPORT jobject JNICALL +JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode, + jint skip_frames, jint frame_count, jint start_index, + jobjectArray classes, + jobjectArray frames); + +JNIEXPORT jint JNICALL +JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor, + jint frame_count, jint start_index, + jobjectArray classes, + jobjectArray frames); + +JNIEXPORT void JNICALL +JVM_FillStackFrames(JNIEnv* env, jclass cls, + jint start_index, + jobjectArray frames, + jint from_index, jint toIndex); + +JNIEXPORT void JNICALL +JVM_SetMethodInfo(JNIEnv* env, jobject frame); + /* * java.lang.Thread */ diff --git a/hotspot/src/share/vm/prims/stackwalk.cpp b/hotspot/src/share/vm/prims/stackwalk.cpp new file mode 100644 index 00000000000..3e292641a79 --- /dev/null +++ b/hotspot/src/share/vm/prims/stackwalk.cpp @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/javaClasses.hpp" +#include "classfile/javaClasses.inline.hpp" +#include "classfile/vmSymbols.hpp" +#include "memory/oopFactory.hpp" +#include "oops/oop.inline.hpp" +#include "oops/objArrayOop.inline.hpp" +#include "prims/stackwalk.hpp" +#include "runtime/globals.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/vframe.hpp" +#include "utilities/globalDefinitions.hpp" + +// setup and cleanup actions +void StackWalkAnchor::setup_magic_on_entry(objArrayHandle classes_array) { + classes_array->obj_at_put(magic_pos, _thread->threadObj()); + _anchor = address_value(); + assert(check_magic(classes_array), "invalid magic"); +} + +bool StackWalkAnchor::check_magic(objArrayHandle classes_array) { + oop m1 = classes_array->obj_at(magic_pos); + jlong m2 = _anchor; + if (m1 == _thread->threadObj() && m2 == address_value()) return true; + return false; +} + +bool StackWalkAnchor::cleanup_magic_on_exit(objArrayHandle classes_array) { + bool ok = check_magic(classes_array); + classes_array->obj_at_put(magic_pos, NULL); + _anchor = 0L; + return ok; +} + +// Returns StackWalkAnchor for the current stack being traversed. +// +// Parameters: +// thread Current Java thread. +// magic Magic value used for each stack walking +// classes_array User-supplied buffers. The 0th element is reserved +// to this StackWalkAnchor to use +// +StackWalkAnchor* StackWalkAnchor::from_current(JavaThread* thread, jlong magic, + objArrayHandle classes_array) +{ + assert(thread != NULL && thread->is_Java_thread(), ""); + oop m1 = classes_array->obj_at(magic_pos); + if (m1 != thread->threadObj()) return NULL; + if (magic == 0L) return NULL; + StackWalkAnchor* anchor = (StackWalkAnchor*) (intptr_t) magic; + if (!anchor->is_valid_in(thread, classes_array)) return NULL; + return anchor; +} + +// Unpacks one or more frames into user-supplied buffers. +// Updates the end index, and returns the number of unpacked frames. +// Always start with the existing vfst.method and bci. +// Do not call vfst.next to advance over the last returned value. +// In other words, do not leave any stale data in the vfst. +// +// Parameters: +// mode Restrict which frames to be decoded. +// vfst vFrameStream. +// max_nframes Maximum number of frames to be filled. +// start_index Start index to the user-supplied buffers. +// classes_array Buffer to store classes in, starting at start_index. +// frames_array Buffer to store StackFrame in, starting at start_index. +// NULL if not used. +// end_index End index to the user-supplied buffers with unpacked frames. +// +// Returns the number of frames whose information was transferred into the buffers. +// +int StackWalk::fill_in_frames(jlong mode, vframeStream& vfst, + int max_nframes, int start_index, + objArrayHandle classes_array, + objArrayHandle frames_array, + int& end_index, TRAPS) { + if (TraceStackWalk) { + tty->print_cr("fill_in_frames limit=%d start=%d frames length=%d", + max_nframes, start_index, classes_array->length()); + } + assert(max_nframes > 0, "invalid max_nframes"); + assert(start_index + max_nframes <= classes_array->length(), "oob"); + + int frames_decoded = 0; + for (; !vfst.at_end(); vfst.next()) { + Method* method = vfst.method(); + int bci = vfst.bci(); + + if (method == NULL) continue; + if (!ShowHiddenFrames && StackWalk::skip_hidden_frames(mode)) { + if (method->is_hidden()) { + if (TraceStackWalk) { + tty->print(" hidden method: "); method->print_short_name(); + tty->print("\n"); + } + continue; + } + } + + int index = end_index++; + if (TraceStackWalk) { + tty->print(" %d: frame method: ", index); method->print_short_name(); + tty->print_cr(" bci=%d", bci); + } + + classes_array->obj_at_put(index, method->method_holder()->java_mirror()); + // fill in StackFrameInfo and initialize MemberName + if (live_frame_info(mode)) { + Handle stackFrame(frames_array->obj_at(index)); + fill_live_stackframe(stackFrame, method, bci, vfst.java_frame(), CHECK_0); + } else if (need_method_info(mode)) { + Handle stackFrame(frames_array->obj_at(index)); + fill_stackframe(stackFrame, method, bci); + } + if (++frames_decoded >= max_nframes) break; + } + return frames_decoded; +} + +static oop create_primitive_value_instance(StackValueCollection* values, int i, TRAPS) { + Klass* k = SystemDictionary::resolve_or_null(vmSymbols::java_lang_LiveStackFrameInfo(), CHECK_NULL); + instanceKlassHandle ik (THREAD, k); + + JavaValue result(T_OBJECT); + JavaCallArguments args; + Symbol* signature = NULL; + + // ## TODO: type is only available in LocalVariable table, if present. + // ## StackValue type is T_INT or T_OBJECT. + switch (values->at(i)->type()) { + case T_INT: + args.push_int(values->int_at(i)); + signature = vmSymbols::asPrimitive_int_signature(); + break; + + case T_LONG: + args.push_long(values->long_at(i)); + signature = vmSymbols::asPrimitive_long_signature(); + break; + + case T_FLOAT: + args.push_float(values->float_at(i)); + signature = vmSymbols::asPrimitive_float_signature(); + break; + + case T_DOUBLE: + args.push_double(values->double_at(i)); + signature = vmSymbols::asPrimitive_double_signature(); + break; + + case T_BYTE: + args.push_int(values->int_at(i)); + signature = vmSymbols::asPrimitive_byte_signature(); + break; + + case T_SHORT: + args.push_int(values->int_at(i)); + signature = vmSymbols::asPrimitive_short_signature(); + break; + + case T_CHAR: + args.push_int(values->int_at(i)); + signature = vmSymbols::asPrimitive_char_signature(); + break; + + case T_BOOLEAN: + args.push_int(values->int_at(i)); + signature = vmSymbols::asPrimitive_boolean_signature(); + break; + + case T_OBJECT: + return values->obj_at(i)(); + + case T_CONFLICT: + // put a non-null slot + args.push_int(0); + signature = vmSymbols::asPrimitive_int_signature(); + break; + + default: ShouldNotReachHere(); + } + JavaCalls::call_static(&result, + ik, + vmSymbols::asPrimitive_name(), + signature, + &args, + CHECK_NULL); + return (instanceOop) result.get_jobject(); +} + +static objArrayHandle values_to_object_array(StackValueCollection* values, TRAPS) { + objArrayHandle empty; + int length = values->size(); + objArrayOop array_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), + length, CHECK_(empty)); + objArrayHandle array_h(THREAD, array_oop); + for (int i = 0; i < values->size(); i++) { + StackValue* st = values->at(i); + oop obj = create_primitive_value_instance(values, i, CHECK_(empty)); + if (obj != NULL) + array_h->obj_at_put(i, obj); + } + return array_h; +} + +static objArrayHandle monitors_to_object_array(GrowableArray* monitors, TRAPS) { + int length = monitors->length(); + objArrayOop array_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), + length, CHECK_(objArrayHandle())); + objArrayHandle array_h(THREAD, array_oop); + for (int i = 0; i < length; i++) { + MonitorInfo* monitor = monitors->at(i); + array_h->obj_at_put(i, monitor->owner()); + } + return array_h; +} + +// Fill StackFrameInfo with declaringClass and bci and initialize memberName +void StackWalk::fill_stackframe(Handle stackFrame, const methodHandle& method, int bci) { + java_lang_StackFrameInfo::set_declaringClass(stackFrame(), method->method_holder()->java_mirror()); + java_lang_StackFrameInfo::set_method_and_bci(stackFrame(), method, bci); +} + +// Fill LiveStackFrameInfo with locals, monitors, and expressions +void StackWalk::fill_live_stackframe(Handle stackFrame, const methodHandle& method, + int bci, javaVFrame* jvf, TRAPS) { + fill_stackframe(stackFrame, method, bci); + if (jvf != NULL) { + StackValueCollection* locals = jvf->locals(); + StackValueCollection* expressions = jvf->expressions(); + GrowableArray* monitors = jvf->monitors(); + + if (!locals->is_empty()) { + objArrayHandle locals_h = values_to_object_array(locals, CHECK); + java_lang_LiveStackFrameInfo::set_locals(stackFrame(), locals_h()); + } + if (!expressions->is_empty()) { + objArrayHandle expressions_h = values_to_object_array(expressions, CHECK); + java_lang_LiveStackFrameInfo::set_operands(stackFrame(), expressions_h()); + } + if (monitors->length() > 0) { + objArrayHandle monitors_h = monitors_to_object_array(monitors, CHECK); + java_lang_LiveStackFrameInfo::set_monitors(stackFrame(), monitors_h()); + } + } +} + +// Begins stack walking. +// +// Parameters: +// stackStream StackStream object +// mode Stack walking mode. +// skip_frames Number of frames to be skipped. +// frame_count Number of frames to be traversed. +// start_index Start index to the user-supplied buffers. +// classes_array Buffer to store classes in, starting at start_index. +// frames_array Buffer to store StackFrame in, starting at start_index. +// NULL if not used. +// +// Returns Object returned from AbstractStackWalker::doStackWalk call. +// +oop StackWalk::walk(Handle stackStream, jlong mode, + int skip_frames, int frame_count, int start_index, + objArrayHandle classes_array, + objArrayHandle frames_array, + TRAPS) { + JavaThread* jt = (JavaThread*)THREAD; + if (TraceStackWalk) { + tty->print_cr("Start walking: mode " JLONG_FORMAT " skip %d frames batch size %d", + mode, skip_frames, frame_count); + } + + if (need_method_info(mode)) { + if (frames_array.is_null()) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", NULL); + } + } + + Klass* stackWalker_klass = SystemDictionary::StackWalker_klass(); + Klass* abstractStackWalker_klass = SystemDictionary::AbstractStackWalker_klass(); + + methodHandle m_doStackWalk(THREAD, Universe::do_stack_walk_method()); + + // Open up a traversable stream onto my stack. + // This stream will be made available by *reference* to the inner Java call. + StackWalkAnchor anchor(jt); + vframeStream& vfst = anchor.vframe_stream(); + + { + // Skip all methods from AbstractStackWalker and StackWalk (enclosing method) + if (!fill_in_stacktrace(mode)) { + while (!vfst.at_end()) { + InstanceKlass* ik = vfst.method()->method_holder(); + if (ik != stackWalker_klass && + ik != abstractStackWalker_klass && ik->super() != abstractStackWalker_klass) { + break; + } + + if (TraceStackWalk) { + tty->print(" skip "); vfst.method()->print_short_name(); tty->print("\n"); + } + vfst.next(); + } + } + + // For exceptions, skip Throwable::fillInStackTrace and methods + // of the exception class and superclasses + if (fill_in_stacktrace(mode)) { + bool skip_to_fillInStackTrace = false; + bool skip_throwableInit_check = false; + while (!vfst.at_end() && !skip_throwableInit_check) { + InstanceKlass* ik = vfst.method()->method_holder(); + Method* method = vfst.method(); + if (!skip_to_fillInStackTrace) { + if (ik == SystemDictionary::Throwable_klass() && + method->name() == vmSymbols::fillInStackTrace_name()) { + // this frame will be skipped + skip_to_fillInStackTrace = true; + } + } else if (!(ik->is_subclass_of(SystemDictionary::Throwable_klass()) && + method->name() == vmSymbols::object_initializer_name())) { + // there are none or we've seen them all - either way stop checking + skip_throwableInit_check = true; + break; + } + + if (TraceStackWalk) { + tty->print("stack walk: skip "); vfst.method()->print_short_name(); tty->print("\n"); + } + vfst.next(); + } + } + + // stack frame has been traversed individually and resume stack walk + // from the stack frame at depth == skip_frames. + for (int n=0; n < skip_frames && !vfst.at_end(); vfst.next(), n++) { + if (TraceStackWalk) { + tty->print(" skip "); vfst.method()->print_short_name(); + tty->print_cr(" frame id: " PTR_FORMAT " pc: " PTR_FORMAT, + p2i(vfst.frame_id()), p2i(vfst.frame_pc())); + } + } + } + + // The Method* pointer in the vfst has a very short shelf life. Grab it now. + int end_index = start_index; + int numFrames = 0; + if (!vfst.at_end()) { + numFrames = fill_in_frames(mode, vfst, frame_count, start_index, classes_array, + frames_array, end_index, CHECK_NULL); + if (numFrames < 1) { + THROW_MSG_(vmSymbols::java_lang_InternalError(), "stack walk: decode failed", NULL); + } + } + + // JVM_CallStackWalk walks the stack and fills in stack frames, then calls to + // Java method java.lang.StackStreamFactory.AbstractStackWalker::doStackWalk + // which calls the implementation to consume the stack frames. + // When JVM_CallStackWalk returns, it invalidates the stack stream. + JavaValue result(T_OBJECT); + JavaCallArguments args(stackStream); + args.push_long(anchor.address_value()); + args.push_int(skip_frames); + args.push_int(frame_count); + args.push_int(start_index); + args.push_int(end_index); + + // Link the thread and vframe stream into the callee-visible object + anchor.setup_magic_on_entry(classes_array); + + JavaCalls::call(&result, m_doStackWalk, &args, THREAD); + + // Do this before anything else happens, to disable any lingering stream objects + bool ok = anchor.cleanup_magic_on_exit(classes_array); + + // Throw pending exception if we must + (void) (CHECK_NULL); + + if (!ok) { + THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers on exit", NULL); + } + + // Return normally + return (oop)result.get_jobject(); + +} + +// Walk the next batch of stack frames +// +// Parameters: +// stackStream StackStream object +// mode Stack walking mode. +// magic Must be valid value to continue the stack walk +// frame_count Number of frames to be decoded. +// start_index Start index to the user-supplied buffers. +// classes_array Buffer to store classes in, starting at start_index. +// frames_array Buffer to store StackFrame in, starting at start_index. +// NULL if not used. +// +// Returns the end index of frame filled in the buffer. +// +jint StackWalk::moreFrames(Handle stackStream, jlong mode, jlong magic, + int frame_count, int start_index, + objArrayHandle classes_array, + objArrayHandle frames_array, + TRAPS) +{ + JavaThread* jt = (JavaThread*)THREAD; + StackWalkAnchor* existing_anchor = StackWalkAnchor::from_current(jt, magic, classes_array); + if (existing_anchor == NULL) { + THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: corrupted buffers", 0L); + } + + if ((need_method_info(mode) || live_frame_info(mode)) && frames_array.is_null()) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "frames_array is NULL", 0L); + } + + if (TraceStackWalk) { + tty->print_cr("StackWalk::moreFrames frame_count %d existing_anchor " PTR_FORMAT " start %d frames %d", + frame_count, p2i(existing_anchor), start_index, classes_array->length()); + } + int end_index = start_index; + if (frame_count <= 0) { + return end_index; // No operation. + } + + int count = frame_count + start_index; + assert (classes_array->length() >= count, "not enough space in buffers"); + + StackWalkAnchor& anchor = (*existing_anchor); + vframeStream& vfst = anchor.vframe_stream(); + if (!vfst.at_end()) { + vfst.next(); // this was the last frame decoded in the previous batch + if (!vfst.at_end()) { + int n = fill_in_frames(mode, vfst, frame_count, start_index, classes_array, + frames_array, end_index, CHECK_0); + if (n < 1) { + THROW_MSG_(vmSymbols::java_lang_InternalError(), "doStackWalk: later decode failed", 0L); + } + return end_index; + } + } + return end_index; +} diff --git a/hotspot/src/share/vm/prims/stackwalk.hpp b/hotspot/src/share/vm/prims/stackwalk.hpp new file mode 100644 index 00000000000..1fa906815be --- /dev/null +++ b/hotspot/src/share/vm/prims/stackwalk.hpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + + +#ifndef SHARE_VM_PRIMS_STACKWALK_HPP +#define SHARE_VM_PRIMS_STACKWALK_HPP + +#include "oops/oop.hpp" +#include "runtime/vframe.hpp" + +class StackWalkAnchor : public StackObj { +private: + enum { + magic_pos = 0 + }; + + JavaThread* _thread; + vframeStream _vfst; + jlong _anchor; +public: + StackWalkAnchor(JavaThread* thread) + : _thread(thread), _vfst(thread), _anchor(0L) {} + + vframeStream& vframe_stream() { return _vfst; } + JavaThread* thread() { return _thread; } + + void setup_magic_on_entry(objArrayHandle classes_array); + bool check_magic(objArrayHandle classes_array); + bool cleanup_magic_on_exit(objArrayHandle classes_array); + + bool is_valid_in(Thread* thread, objArrayHandle classes_array) { + return (_thread == thread && check_magic(classes_array)); + } + + jlong address_value() { + return (jlong) castable_address(this); + } + + static StackWalkAnchor* from_current(JavaThread* thread, jlong anchor, objArrayHandle frames_array); +}; + +class StackWalk : public AllStatic { +private: + static int fill_in_frames(jlong mode, vframeStream& vfst, + int max_nframes, int start_index, + objArrayHandle classes_array, + objArrayHandle frames_array, + int& end_index, TRAPS); + + static void fill_stackframe(Handle stackFrame, const methodHandle& method, int bci); + + static void fill_live_stackframe(Handle stackFrame, const methodHandle& method, int bci, + javaVFrame* jvf, TRAPS); + + static inline bool skip_hidden_frames(int mode) { + return (mode & JVM_STACKWALK_SHOW_HIDDEN_FRAMES) == 0; + } + static inline bool need_method_info(int mode) { + return (mode & JVM_STACKWALK_FILL_CLASS_REFS_ONLY) == 0; + } + static inline bool live_frame_info(int mode) { + return (mode & JVM_STACKWALK_FILL_LIVE_STACK_FRAMES) != 0; + } + static inline bool fill_in_stacktrace(int mode) { + return (mode & JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE) != 0; + } + +public: + static oop walk(Handle stackStream, jlong mode, + int skip_frames, int frame_count, int start_index, + objArrayHandle classes_array, + objArrayHandle frames_array, + TRAPS); + + static jint moreFrames(Handle stackStream, jlong mode, jlong magic, + int frame_count, int start_index, + objArrayHandle classes_array, + objArrayHandle frames_array, + TRAPS); +}; +#endif // SHARE_VM_PRIMS_STACKWALK_HPP diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index cf6637e396a..d9f06a92e0f 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3115,6 +3115,12 @@ public: "exceptions (0 means all)") \ range(0, max_jint/2) \ \ + develop(bool, TraceStackWalk, false, \ + "Trace stack walking") \ + \ + product(bool, MemberNameInStackFrame, true, \ + "Use MemberName in StackFrame") \ + \ /* notice: the max range value here is max_jint, not max_intx */ \ /* because of overflow issue */ \ NOT_EMBEDDED(diagnostic(intx, GuaranteedSafepointInterval, 1000, \ diff --git a/hotspot/src/share/vm/runtime/vframe.hpp b/hotspot/src/share/vm/runtime/vframe.hpp index 74c9b725811..654d6b823b1 100644 --- a/hotspot/src/share/vm/runtime/vframe.hpp +++ b/hotspot/src/share/vm/runtime/vframe.hpp @@ -317,10 +317,18 @@ class vframeStreamCommon : StackObj { intptr_t* frame_id() const { return _frame.id(); } address frame_pc() const { return _frame.pc(); } + javaVFrame* java_frame() { + vframe* vf = vframe::new_vframe(&_frame, &_reg_map, _thread); + if (vf->is_java_frame()) { + return (javaVFrame*)vf; + } + return NULL; + } + CodeBlob* cb() const { return _frame.cb(); } nmethod* nm() const { - assert( cb() != NULL && cb()->is_nmethod(), "usage"); - return (nmethod*) cb(); + assert( cb() != NULL && cb()->is_nmethod(), "usage"); + return (nmethod*) cb(); } // Frame type From 6887844c720002521ef11bc9e4a9e231ebef678c Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Tue, 24 Nov 2015 16:58:45 -0800 Subject: [PATCH 079/260] 8143963: improve ClassLoader::trace_class_path to accept an additional outputStream* arg For fixing a truncation problem on the output from -XX:+TraceClassPaths Reviewed-by: coleenp, jiangli, cjplummer, minqi --- hotspot/src/share/vm/classfile/classLoader.cpp | 14 +++++++------- hotspot/src/share/vm/classfile/classLoader.hpp | 2 +- .../src/share/vm/classfile/sharedPathsMiscInfo.cpp | 4 ++-- .../src/share/vm/classfile/sharedPathsMiscInfo.hpp | 2 +- hotspot/src/share/vm/runtime/arguments.cpp | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index 21140f33c6e..a89d50db966 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -414,30 +414,30 @@ void ClassLoader::exit_with_path_failure(const char* error, const char* message) } #endif -void ClassLoader::trace_class_path(const char* msg, const char* name) { +void ClassLoader::trace_class_path(outputStream* out, const char* msg, const char* name) { if (!TraceClassPaths) { return; } if (msg) { - tty->print("%s", msg); + out->print("%s", msg); } if (name) { if (strlen(name) < 256) { - tty->print("%s", name); + out->print("%s", name); } else { // For very long paths, we need to print each character separately, // as print_cr() has a length limit while (name[0] != '\0') { - tty->print("%c", name[0]); + out->print("%c", name[0]); name++; } } } if (msg && msg[0] == '[') { - tty->print_cr("]"); + out->print_cr("]"); } else { - tty->cr(); + out->cr(); } } @@ -466,7 +466,7 @@ void ClassLoader::setup_bootstrap_search_path() { // Don't print sys_class_path - this is the bootcp of this current VM process, not necessarily // the same as the bootcp of the shared archive. } else { - trace_class_path("[Bootstrap loader class path=", sys_class_path); + trace_class_path(tty, "[Bootstrap loader class path=", sys_class_path); } #if INCLUDE_CDS if (DumpSharedSpaces) { diff --git a/hotspot/src/share/vm/classfile/classLoader.hpp b/hotspot/src/share/vm/classfile/classLoader.hpp index 4971c7c3b9a..63034372251 100644 --- a/hotspot/src/share/vm/classfile/classLoader.hpp +++ b/hotspot/src/share/vm/classfile/classLoader.hpp @@ -328,7 +328,7 @@ class ClassLoader: AllStatic { static void exit_with_path_failure(const char* error, const char* message); #endif - static void trace_class_path(const char* msg, const char* name = NULL); + static void trace_class_path(outputStream* out, const char* msg, const char* name = NULL); // VM monitoring and management support static jlong classloader_time_ms(); diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp index 9bb82f7fd19..9233e3243ad 100644 --- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -67,7 +67,7 @@ bool SharedPathsMiscInfo::read(void* ptr, size_t size) { } bool SharedPathsMiscInfo::fail(const char* msg, const char* name) { - ClassLoader::trace_class_path(msg, name); + ClassLoader::trace_class_path(tty, msg, name); MetaspaceShared::set_archive_loading_failed(); return false; } diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp index fb3d143d217..652d20c883a 100644 --- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp @@ -65,7 +65,7 @@ protected: bool read(void* ptr, size_t size); static void trace_class_path(const char* msg, const char* name = NULL) { - ClassLoader::trace_class_path(msg, name); + ClassLoader::trace_class_path(tty, msg, name); } protected: static bool fail(const char* msg, const char* name = NULL); diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index ca98eb8e7f0..e3bcfbbb241 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -3425,7 +3425,7 @@ void Arguments::fix_appclasspath() { } if (!PrintSharedArchiveAndExit) { - ClassLoader::trace_class_path("[classpath: ", _java_class_path->value()); + ClassLoader::trace_class_path(tty, "[classpath: ", _java_class_path->value()); } } From 0091d09fd22065a2e4ff2e002a330f8c33419ccb Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Wed, 25 Nov 2015 08:52:55 +0100 Subject: [PATCH 080/260] 8143544: Make CMSCollector::is_cms_reachable() non-product Reviewed-by: ysr, tschatzl --- .../share/vm/gc/cms/concurrentMarkSweepGeneration.cpp | 11 +++++------ .../share/vm/gc/cms/concurrentMarkSweepGeneration.hpp | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp index 8771eec8de9..45439181aa5 100644 --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp @@ -2240,7 +2240,6 @@ bool CMSCollector::have_cms_token() { } return false; } -#endif // Check reachability of the given heap address in CMS generation, // treating all other generations as roots. @@ -2260,21 +2259,21 @@ bool CMSCollector::is_cms_reachable(HeapWord* addr) { // Clear the marking bit map array before starting, but, just // for kicks, first report if the given address is already marked - gclog_or_tty->print_cr("Start: Address " PTR_FORMAT " is%s marked", p2i(addr), + tty->print_cr("Start: Address " PTR_FORMAT " is%s marked", p2i(addr), _markBitMap.isMarked(addr) ? "" : " not"); if (verify_after_remark()) { MutexLockerEx x(verification_mark_bm()->lock(), Mutex::_no_safepoint_check_flag); bool result = verification_mark_bm()->isMarked(addr); - gclog_or_tty->print_cr("TransitiveMark: Address " PTR_FORMAT " %s marked", p2i(addr), - result ? "IS" : "is NOT"); + tty->print_cr("TransitiveMark: Address " PTR_FORMAT " %s marked", p2i(addr), + result ? "IS" : "is NOT"); return result; } else { - gclog_or_tty->print_cr("Could not compute result"); + tty->print_cr("Could not compute result"); return false; } } - +#endif void CMSCollector::print_on_error(outputStream* st) { diff --git a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp index 1f0be952fc5..10eb76fb35b 100644 --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp @@ -926,7 +926,7 @@ class CMSCollector: public CHeapObj { // one (foreground collector or background collector). static void check_correct_thread_executing() PRODUCT_RETURN; - bool is_cms_reachable(HeapWord* addr); + NOT_PRODUCT(bool is_cms_reachable(HeapWord* addr);) // Performance Counter Support CollectorCounters* counters() { return _gc_counters; } From 352c2060f2552bdd1c2d703e5acc3f4af416ff09 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 25 Nov 2015 14:43:29 +0100 Subject: [PATCH 081/260] 8136679: JFR event for adaptive IHOP Reviewed-by: tbenson, mgerdin, sangheki, ehelin --- .../src/share/vm/gc/g1/g1CollectorPolicy.cpp | 2 + hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp | 41 ++++++++++------- hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp | 4 +- hotspot/src/share/vm/gc/shared/gcTrace.cpp | 30 +++++++++++++ hotspot/src/share/vm/gc/shared/gcTrace.hpp | 28 ++++++++++++ .../src/share/vm/gc/shared/gcTraceSend.cpp | 45 +++++++++++++++++++ hotspot/src/share/vm/trace/trace.xml | 26 +++++++++++ 7 files changed, 158 insertions(+), 18 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index 2a69d6ae890..a7dba98c72c 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -1213,6 +1213,8 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t last_unrestrained_young_length * HeapRegion::GrainBytes); _bytes_allocated_in_old_since_last_gc = 0; + _ihop_control->send_trace_event(_g1->gc_tracer_stw()); + // Note that _mmu_tracker->max_gc_time() returns the time in seconds. double update_rs_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSetUpdatingPauseTimePercent / 100.0; diff --git a/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp b/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp index 29d48777101..077f7b7ecf5 100644 --- a/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp +++ b/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp @@ -27,6 +27,7 @@ #include "gc/g1/g1ErgoVerbose.hpp" #include "gc/g1/g1IHOPControl.hpp" #include "gc/g1/g1Predictions.hpp" +#include "gc/shared/gcTrace.hpp" G1IHOPControl::G1IHOPControl(double initial_ihop_percent, size_t target_occupancy) : _initial_ihop_percent(initial_ihop_percent), @@ -62,6 +63,15 @@ void G1IHOPControl::print() { last_marking_length_s()); } +void G1IHOPControl::send_trace_event(G1NewTracer* tracer) { + tracer->report_basic_ihop_statistics(get_conc_mark_start_threshold(), + _target_occupancy, + G1CollectedHeap::heap()->used(), + _last_allocated_bytes, + _last_allocation_time_s, + last_marking_length_s()); +} + G1StaticIHOPControl::G1StaticIHOPControl(double ihop_percent, size_t target_occupancy) : G1IHOPControl(ihop_percent, target_occupancy), _last_marking_length_s(0.0) { @@ -166,11 +176,11 @@ size_t G1AdaptiveIHOPControl::get_conc_mark_start_threshold() { } void G1AdaptiveIHOPControl::update_allocation_info(double allocation_time_s, size_t allocated_bytes, size_t additional_buffer_size) { - assert(allocation_time_s >= 0.0, "Allocation time must be positive but is %.3f", allocation_time_s); + G1IHOPControl::update_allocation_info(allocation_time_s, allocated_bytes, additional_buffer_size); + double allocation_rate = (double) allocated_bytes / allocation_time_s; _allocation_rate_s.add(allocation_rate); - _last_allocation_bytes = allocated_bytes; _last_unrestrained_young_size = additional_buffer_size; } @@ -180,21 +190,7 @@ void G1AdaptiveIHOPControl::update_marking_length(double marking_length_s) { } void G1AdaptiveIHOPControl::print() { - ergo_verbose6(ErgoIHOP, - "basic information", - ergo_format_reason("value update") - ergo_format_byte_perc("threshold") - ergo_format_byte("target occupancy") - ergo_format_byte("current occupancy") - ergo_format_double("recent old gen allocation rate") - ergo_format_double("recent marking phase length"), - get_conc_mark_start_threshold(), - percent_of(get_conc_mark_start_threshold(), _target_occupancy), - _target_occupancy, - G1CollectedHeap::heap()->used(), - _allocation_rate_s.last(), - _marking_times_s.last() - ); + G1IHOPControl::print(); size_t actual_target = actual_target_threshold(); ergo_verbose6(ErgoIHOP, "adaptive IHOP information", @@ -213,6 +209,17 @@ void G1AdaptiveIHOPControl::print() { ); } +void G1AdaptiveIHOPControl::send_trace_event(G1NewTracer* tracer) { + G1IHOPControl::send_trace_event(tracer); + tracer->report_adaptive_ihop_statistics(get_conc_mark_start_threshold(), + actual_target_threshold(), + G1CollectedHeap::heap()->used(), + _last_unrestrained_young_size, + _predictor->get_new_prediction(&_allocation_rate_s), + _predictor->get_new_prediction(&_marking_times_s), + have_enough_data_for_prediction()); +} + #ifndef PRODUCT void G1AdaptiveIHOPControl::test() { size_t const initial_threshold = 45; diff --git a/hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp b/hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp index ee9c27213ea..085b8798a0c 100644 --- a/hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp +++ b/hotspot/src/share/vm/gc/g1/g1IHOPControl.hpp @@ -29,6 +29,7 @@ #include "utilities/numberSeq.hpp" class G1Predictions; +class G1NewTracer; // Base class for algorithms that calculate the heap occupancy at which // concurrent marking should start. This heap usage threshold should be relative @@ -73,6 +74,7 @@ class G1IHOPControl : public CHeapObj { virtual void update_marking_length(double marking_length_s) = 0; virtual void print(); + virtual void send_trace_event(G1NewTracer* tracer); }; // The returned concurrent mark starting occupancy threshold is a fixed value @@ -111,7 +113,6 @@ class G1AdaptiveIHOPControl : public G1IHOPControl { TruncatedSeq _marking_times_s; TruncatedSeq _allocation_rate_s; - size_t _last_allocation_bytes; // Most recent mutator allocation since last GC. // The most recent unrestrained size of the young gen. This is used as an additional // factor in the calculation of the threshold, as the threshold is based on // non-young gen occupancy at the end of GC. For the IHOP threshold, we need to @@ -142,6 +143,7 @@ class G1AdaptiveIHOPControl : public G1IHOPControl { virtual void update_marking_length(double marking_length_s); virtual void print(); + virtual void send_trace_event(G1NewTracer* tracer); #ifndef PRODUCT static void test(); #endif diff --git a/hotspot/src/share/vm/gc/shared/gcTrace.cpp b/hotspot/src/share/vm/gc/shared/gcTrace.cpp index becf4b5b867..10da185584e 100644 --- a/hotspot/src/share/vm/gc/shared/gcTrace.cpp +++ b/hotspot/src/share/vm/gc/shared/gcTrace.cpp @@ -212,4 +212,34 @@ void G1NewTracer::report_evacuation_statistics(const G1EvacSummary& young_summar send_old_evacuation_statistics(old_summary); } +void G1NewTracer::report_basic_ihop_statistics(size_t threshold, + size_t target_ccupancy, + size_t current_occupancy, + size_t last_allocation_size, + double last_allocation_duration, + double last_marking_length) { + send_basic_ihop_statistics(threshold, + target_ccupancy, + current_occupancy, + last_allocation_size, + last_allocation_duration, + last_marking_length); +} + +void G1NewTracer::report_adaptive_ihop_statistics(size_t threshold, + size_t internal_target_occupancy, + size_t current_occupancy, + size_t additional_buffer_size, + double predicted_allocation_rate, + double predicted_marking_length, + bool prediction_active) { + send_adaptive_ihop_statistics(threshold, + internal_target_occupancy, + additional_buffer_size, + current_occupancy, + predicted_allocation_rate, + predicted_marking_length, + prediction_active); +} + #endif diff --git a/hotspot/src/share/vm/gc/shared/gcTrace.hpp b/hotspot/src/share/vm/gc/shared/gcTrace.hpp index e0db92dbe8f..bcacbb9b12b 100644 --- a/hotspot/src/share/vm/gc/shared/gcTrace.hpp +++ b/hotspot/src/share/vm/gc/shared/gcTrace.hpp @@ -253,6 +253,20 @@ class G1NewTracer : public YoungGCTracer { void report_evacuation_failed(EvacuationFailedInfo& ef_info); void report_evacuation_statistics(const G1EvacSummary& young_summary, const G1EvacSummary& old_summary) const; + + void report_basic_ihop_statistics(size_t threshold, + size_t target_occupancy, + size_t current_occupancy, + size_t last_allocation_size, + double last_allocation_duration, + double last_marking_length); + void report_adaptive_ihop_statistics(size_t threshold, + size_t internal_target_occupancy, + size_t current_occupancy, + size_t additional_buffer_size, + double predicted_allocation_rate, + double predicted_marking_length, + bool prediction_active); private: void send_g1_young_gc_event(); void send_evacuation_info_event(EvacuationInfo* info); @@ -260,6 +274,20 @@ class G1NewTracer : public YoungGCTracer { void send_young_evacuation_statistics(const G1EvacSummary& summary) const; void send_old_evacuation_statistics(const G1EvacSummary& summary) const; + + void send_basic_ihop_statistics(size_t threshold, + size_t target_occupancy, + size_t current_occupancy, + size_t last_allocation_size, + double last_allocation_duration, + double last_marking_length); + void send_adaptive_ihop_statistics(size_t threshold, + size_t internal_target_occupancy, + size_t current_occupancy, + size_t additional_buffer_size, + double predicted_allocation_rate, + double predicted_marking_length, + bool prediction_active); }; #endif diff --git a/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp b/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp index da72a232d78..5c6b5ad2284 100644 --- a/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp +++ b/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp @@ -35,6 +35,7 @@ #if INCLUDE_ALL_GCS #include "gc/g1/evacuationInfo.hpp" #include "gc/g1/g1YCTypes.hpp" +#include "tracefiles/traceEventClasses.hpp" #endif // All GC dependencies against the trace framework is contained within this file. @@ -265,6 +266,50 @@ void G1NewTracer::send_old_evacuation_statistics(const G1EvacSummary& summary) c old_evt.commit(); } } + +void G1NewTracer::send_basic_ihop_statistics(size_t threshold, + size_t target_occupancy, + size_t current_occupancy, + size_t last_allocation_size, + double last_allocation_duration, + double last_marking_length) { + EventGCG1BasicIHOP evt; + if (evt.should_commit()) { + evt.set_gcId(GCId::current()); + evt.set_threshold(threshold); + evt.set_targetOccupancy(target_occupancy); + evt.set_thresholdPercentage(target_occupancy > 0 ? threshold * 100.0 / target_occupancy : 0.0); + evt.set_currentOccupancy(current_occupancy); + evt.set_lastAllocationSize(last_allocation_size); + evt.set_lastAllocationDuration(last_allocation_duration); + evt.set_lastAllocationRate(last_allocation_duration != 0.0 ? last_allocation_size / last_allocation_duration : 0.0); + evt.set_lastMarkingLength(last_marking_length); + evt.commit(); + } +} + +void G1NewTracer::send_adaptive_ihop_statistics(size_t threshold, + size_t internal_target_occupancy, + size_t current_occupancy, + size_t additional_buffer_size, + double predicted_allocation_rate, + double predicted_marking_length, + bool prediction_active) { + EventGCG1AdaptiveIHOP evt; + if (evt.should_commit()) { + evt.set_gcId(GCId::current()); + evt.set_threshold(threshold); + evt.set_thresholdPercentage(internal_target_occupancy > 0 ? threshold * 100.0 / internal_target_occupancy : 0.0); + evt.set_internalTargetOccupancy(internal_target_occupancy); + evt.set_currentOccupancy(current_occupancy); + evt.set_additionalBufferSize(additional_buffer_size); + evt.set_predictedAllocationRate(predicted_allocation_rate); + evt.set_predictedMarkingLength(predicted_marking_length); + evt.set_predictionActive(prediction_active); + evt.commit(); + } +} + #endif static TraceStructVirtualSpace to_trace_struct(const VirtualSpaceSummary& summary) { diff --git a/hotspot/src/share/vm/trace/trace.xml b/hotspot/src/share/vm/trace/trace.xml index 0329d9b725a..c1f4dfb88de 100644 --- a/hotspot/src/share/vm/trace/trace.xml +++ b/hotspot/src/share/vm/trace/trace.xml @@ -369,6 +369,32 @@ Declares a structure type that can be used in other events. + + + + + + + + + + + + + + + + + + + + + + + + Date: Wed, 25 Nov 2015 09:08:51 -0500 Subject: [PATCH 082/260] 8098557: Only init superintf if subclass, not sub interface inits Must exclude jck lang exec05001m311_rt until fixed. Reviewed-by: lfoltan, hseigel, dholmes --- hotspot/src/share/vm/oops/instanceKlass.cpp | 5 ++- .../lambda-features/TestInterfaceInit.java | 35 ++++++++++++++----- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 03584ee0320..0b41d13c77a 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -815,10 +815,13 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_k, TRAPS) { } } + // If C is an interface that declares a non-abstract, non-static method, + // the initialization of a class (not an interface) that implements C directly or + // indirectly. // Recursively initialize any superinterfaces that declare default methods // Only need to recurse if has_default_methods which includes declaring and // inheriting default methods - if (this_k->has_default_methods()) { + if (!this_k->is_interface() && this_k->has_default_methods()) { this_k->initialize_super_interfaces(this_k, CHECK); } diff --git a/hotspot/test/runtime/lambda-features/TestInterfaceInit.java b/hotspot/test/runtime/lambda-features/TestInterfaceInit.java index 0493a60bb1e..f3d8e8aacd5 100644 --- a/hotspot/test/runtime/lambda-features/TestInterfaceInit.java +++ b/hotspot/test/runtime/lambda-features/TestInterfaceInit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,8 @@ /* * @test * @bug 8034275 - * @summary [JDK 8u40] Test interface initialization: only for interfaces declaring default methods + * @bug 8098557 + * @summary [JDK 8u40] Test interface init: only for interfaces declaring default methods, when subclass inits * @run main TestInterfaceInit */ import java.util.List; @@ -39,43 +40,59 @@ public class TestInterfaceInit { // Declares a default method and initializes interface I { boolean v = TestInterfaceInit.out(I.class); - default void x() {} + default void ix() {} } // Declares a default method and initializes interface J extends I { boolean v = TestInterfaceInit.out(J.class); - default void x() {} + default void jx() {} } - // No default method, does not initialize + // No default method, has an abstract method, does not initialize interface JN extends J { boolean v = TestInterfaceInit.out(JN.class); + public abstract void jnx(); } // Declares a default method and initializes interface K extends I { boolean v = TestInterfaceInit.out(K.class); - default void x() {} + default void kx() {} } - // No default method, does not initialize + // No default method, has a static method, does not initialize interface KN extends K { boolean v = TestInterfaceInit.out(KN.class); + static void knx() {} } interface L extends JN, KN { boolean v = TestInterfaceInit.out(L.class); - default void x() {} + default void lx() {} + } + + static class ChildClass implements JN, KN { + boolean v = TestInterfaceInit.out(ChildClass.class); + public void jnx() {} } public static void main(String[] args) { // Trigger initialization boolean v = L.v; - List> expectedCInitOrder = Arrays.asList(I.class,J.class,K.class,L.class); + List> expectedCInitOrder = Arrays.asList(L.class); if (!cInitOrder.equals(expectedCInitOrder)) { throw new RuntimeException(String.format("Class initialization array %s not equal to expected array %s", cInitOrder, expectedCInitOrder)); } + + ChildClass myC = new ChildClass(); + boolean w = myC.v; + + expectedCInitOrder = Arrays.asList(L.class,I.class,J.class,K.class,ChildClass.class); + if (!cInitOrder.equals(expectedCInitOrder)) { + throw new RuntimeException(String.format("Class initialization array %s not equal to expected array %s", cInitOrder, expectedCInitOrder)); + } + } static boolean out(Class c) { From 4699c70e25ae8dfbddfb9c073874f9d6141105d1 Mon Sep 17 00:00:00 2001 From: Sebastian Sickelmann Date: Wed, 25 Nov 2015 16:33:28 +0100 Subject: [PATCH 083/260] 8136978: Much nearly duplicated code for vmError support Moved all non os specific code in vmError_[os].cpp to vmError_posix.cpp, moved os specific code to os_[os].cpp and refactored all other references accordingly Reviewed-by: stuefe, coleenp, dholmes --- hotspot/src/os/aix/vm/os_aix.cpp | 27 +++- hotspot/src/os/aix/vm/vmError_aix.cpp | 134 ----------------- hotspot/src/os/bsd/vm/os_bsd.cpp | 28 +++- hotspot/src/os/bsd/vm/vmError_bsd.cpp | 138 ----------------- hotspot/src/os/linux/vm/os_linux.cpp | 30 +++- hotspot/src/os/linux/vm/vmError_linux.cpp | 139 ------------------ hotspot/src/os/posix/vm/os_posix.cpp | 33 +++++ hotspot/src/os/posix/vm/os_posix.hpp | 6 + .../vm/vmError_posix.cpp} | 52 +++---- hotspot/src/os/solaris/vm/os_solaris.cpp | 26 +++- hotspot/src/os/windows/vm/os_windows.cpp | 26 +++- hotspot/src/os/windows/vm/vmError_windows.cpp | 32 ---- hotspot/src/share/vm/runtime/os.hpp | 3 +- hotspot/src/share/vm/utilities/vmError.cpp | 8 + 14 files changed, 202 insertions(+), 480 deletions(-) delete mode 100644 hotspot/src/os/aix/vm/vmError_aix.cpp delete mode 100644 hotspot/src/os/bsd/vm/vmError_bsd.cpp delete mode 100644 hotspot/src/os/linux/vm/vmError_linux.cpp rename hotspot/src/os/{solaris/vm/vmError_solaris.cpp => posix/vm/vmError_posix.cpp} (74%) diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index b45a9d360aa..65f005e6977 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -3785,7 +3785,7 @@ os::os_exception_wrapper(java_call_t f, JavaValue* value, const methodHandle& me void os::print_statistics() { } -int os::message_box(const char* title, const char* message) { +bool os::message_box(const char* title, const char* message) { int i; fdStream err(defaultStream::error_fd()); for (i = 0; i < 78; i++) err.print_raw("="); @@ -4914,3 +4914,28 @@ void TestReserveMemorySpecial_test() { // No tests available for this platform } #endif + +bool os::start_debugging(char *buf, int buflen) { + int len = (int)strlen(buf); + char *p = &buf[len]; + + jio_snprintf(p, buflen -len, + "\n\n" + "Do you want to debug the problem?\n\n" + "To debug, run 'dbx -a %d'; then switch to thread tid " INTX_FORMAT ", k-tid " INTX_FORMAT "\n" + "Enter 'yes' to launch dbx automatically (PATH must include dbx)\n" + "Otherwise, press RETURN to abort...", + os::current_process_id(), + os::current_thread_id(), thread_self()); + + bool yes = os::message_box("Unexpected Error", buf); + + if (yes) { + // yes, user asked VM to launch debugger + jio_snprintf(buf, buflen, "dbx -a %d", os::current_process_id()); + + os::fork_and_exec(buf); + yes = false; + } + return yes; +} diff --git a/hotspot/src/os/aix/vm/vmError_aix.cpp b/hotspot/src/os/aix/vm/vmError_aix.cpp deleted file mode 100644 index cfa88dbe4f7..00000000000 --- a/hotspot/src/os/aix/vm/vmError_aix.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2003, 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. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 "runtime/arguments.hpp" -#include "runtime/os.hpp" -#include "runtime/thread.hpp" -#include "utilities/vmError.hpp" - -#include -#include -#include -#include - -void VMError::show_message_box(char *buf, int buflen) { - bool yes; - do { - error_string(buf, buflen); - int len = (int)strlen(buf); - char *p = &buf[len]; - - jio_snprintf(p, buflen - len, - "\n\n" - "Do you want to debug the problem?\n\n" - "To debug, run 'dbx -a %d'; then switch to thread tid " INTX_FORMAT ", k-tid " INTX_FORMAT "\n" - "Enter 'yes' to launch dbx automatically (PATH must include dbx)\n" - "Otherwise, press RETURN to abort...", - os::current_process_id(), - os::current_thread_id(), thread_self()); - - yes = os::message_box("Unexpected Error", buf); - - if (yes) { - // yes, user asked VM to launch debugger - jio_snprintf(buf, buflen, "dbx -a %d", os::current_process_id()); - - os::fork_and_exec(buf); - yes = false; - } - } while (yes); -} - -// Handle all synchronous signals which may happen during signal handling, -// not just SIGSEGV and SIGBUS. -static const int SIGNALS[] = { SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP }; // add more if needed -static const int NUM_SIGNALS = sizeof(SIGNALS) / sizeof(int); - -// Space for our "saved" signal flags and handlers -static int resettedSigflags[NUM_SIGNALS]; -static address resettedSighandler[NUM_SIGNALS]; - -static void save_signal(int idx, int sig) { - struct sigaction sa; - sigaction(sig, NULL, &sa); - resettedSigflags[idx] = sa.sa_flags; - resettedSighandler[idx] = (sa.sa_flags & SA_SIGINFO) - ? CAST_FROM_FN_PTR(address, sa.sa_sigaction) - : CAST_FROM_FN_PTR(address, sa.sa_handler); -} - -int VMError::get_resetted_sigflags(int sig) { - for (int i = 0; i < NUM_SIGNALS; i++) { - if (SIGNALS[i] == sig) { - return resettedSigflags[i]; - } - } - return -1; -} - -address VMError::get_resetted_sighandler(int sig) { - for (int i = 0; i < NUM_SIGNALS; i++) { - if (SIGNALS[i] == sig) { - return resettedSighandler[i]; - } - } - return NULL; -} - -static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { - - // Unmask current signal. - sigset_t newset; - sigemptyset(&newset); - sigaddset(&newset, sig); - // and all other synchronous signals too. - for (int i = 0; i < NUM_SIGNALS; i++) { - sigaddset(&newset, SIGNALS[i]); - } - sigthreadmask(SIG_UNBLOCK, &newset, NULL); - - // support safefetch faults in error handling - ucontext_t* const uc = (ucontext_t*) ucVoid; - address const pc = uc ? os::Aix::ucontext_get_pc(uc) : NULL; - if (uc && pc && StubRoutines::is_safefetch_fault(pc)) { - os::Aix::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); - return; - } - - VMError::report_and_die(NULL, sig, pc, info, ucVoid); -} - -void VMError::reset_signal_handlers() { - sigset_t newset; - sigemptyset(&newset); - - for (int i = 0; i < NUM_SIGNALS; i++) { - save_signal(i, SIGNALS[i]); - os::signal(SIGNALS[i], CAST_FROM_FN_PTR(void *, crash_handler)); - sigaddset(&newset, SIGNALS[i]); - } - - sigthreadmask(SIG_UNBLOCK, &newset, NULL); -} diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index a21d2c92a0b..f3227683c12 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -3768,7 +3768,7 @@ void os::os_exception_wrapper(java_call_t f, JavaValue* value, void os::print_statistics() { } -int os::message_box(const char* title, const char* message) { +bool os::message_box(const char* title, const char* message) { int i; fdStream err(defaultStream::error_fd()); for (i = 0; i < 78; i++) err.print_raw("="); @@ -4672,3 +4672,29 @@ void TestReserveMemorySpecial_test() { // No tests available for this platform } #endif + +bool os::start_debugging(char *buf, int buflen) { + int len = (int)strlen(buf); + char *p = &buf[len]; + + jio_snprintf(p, buflen-len, + "\n\n" + "Do you want to debug the problem?\n\n" + "To debug, run 'gdb /proc/%d/exe %d'; then switch to thread " INTX_FORMAT " (" INTPTR_FORMAT ")\n" + "Enter 'yes' to launch gdb automatically (PATH must include gdb)\n" + "Otherwise, press RETURN to abort...", + os::current_process_id(), os::current_process_id(), + os::current_thread_id(), os::current_thread_id()); + + bool yes = os::message_box("Unexpected Error", buf); + + if (yes) { + // yes, user asked VM to launch debugger + jio_snprintf(buf, sizeof(buf), "gdb /proc/%d/exe %d", + os::current_process_id(), os::current_process_id()); + + os::fork_and_exec(buf); + yes = false; + } + return yes; +} diff --git a/hotspot/src/os/bsd/vm/vmError_bsd.cpp b/hotspot/src/os/bsd/vm/vmError_bsd.cpp deleted file mode 100644 index 1b34a701276..00000000000 --- a/hotspot/src/os/bsd/vm/vmError_bsd.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 "runtime/arguments.hpp" -#include "runtime/os.hpp" -#include "runtime/thread.hpp" -#include "utilities/vmError.hpp" - -#include -#include -#include -#include -#include - -void VMError::show_message_box(char *buf, int buflen) { - bool yes; - do { - error_string(buf, buflen); - int len = (int)strlen(buf); - char *p = &buf[len]; - - jio_snprintf(p, buflen - len, - "\n\n" - "Do you want to debug the problem?\n\n" - "To debug, run 'gdb /proc/%d/exe %d'; then switch to thread " INTX_FORMAT " (" INTPTR_FORMAT ")\n" - "Enter 'yes' to launch gdb automatically (PATH must include gdb)\n" - "Otherwise, press RETURN to abort...", - os::current_process_id(), os::current_process_id(), - os::current_thread_id(), os::current_thread_id()); - - yes = os::message_box("Unexpected Error", buf); - - if (yes) { - // yes, user asked VM to launch debugger - jio_snprintf(buf, buflen, "gdb /proc/%d/exe %d", - os::current_process_id(), os::current_process_id()); - - os::fork_and_exec(buf); - yes = false; - } - } while (yes); -} - -// handle all synchronous program error signals which may happen during error -// reporting. They must be unblocked, caught, handled. - -static const int SIGNALS[] = { SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP }; // add more if needed -static const int NUM_SIGNALS = sizeof(SIGNALS) / sizeof(int); - -// Space for our "saved" signal flags and handlers -static int resettedSigflags[NUM_SIGNALS]; -static address resettedSighandler[NUM_SIGNALS]; - -static void save_signal(int idx, int sig) -{ - struct sigaction sa; - sigaction(sig, NULL, &sa); - resettedSigflags[idx] = sa.sa_flags; - resettedSighandler[idx] = (sa.sa_flags & SA_SIGINFO) - ? CAST_FROM_FN_PTR(address, sa.sa_sigaction) - : CAST_FROM_FN_PTR(address, sa.sa_handler); -} - -int VMError::get_resetted_sigflags(int sig) { - for (int i = 0; i < NUM_SIGNALS; i++) { - if (SIGNALS[i] == sig) { - return resettedSigflags[i]; - } - } - return -1; -} - -address VMError::get_resetted_sighandler(int sig) { - for (int i = 0; i < NUM_SIGNALS; i++) { - if (SIGNALS[i] == sig) { - return resettedSighandler[i]; - } - } - return NULL; -} - -static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { - // unmask current signal - sigset_t newset; - sigemptyset(&newset); - sigaddset(&newset, sig); - // also unmask other synchronous signals - for (int i = 0; i < NUM_SIGNALS; i++) { - sigaddset(&newset, SIGNALS[i]); - } - pthread_sigmask(SIG_UNBLOCK, &newset, NULL); - - // support safefetch faults in error handling - ucontext_t* const uc = (ucontext_t*) ucVoid; - address const pc = uc ? os::Bsd::ucontext_get_pc(uc) : NULL; - - if (uc && pc && StubRoutines::is_safefetch_fault(pc)) { - os::Bsd::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); - return; - } - - VMError::report_and_die(NULL, sig, pc, info, ucVoid); -} - -void VMError::reset_signal_handlers() { - // install signal handlers for all synchronous program error signals - sigset_t newset; - sigemptyset(&newset); - - for (int i = 0; i < NUM_SIGNALS; i++) { - save_signal(i, SIGNALS[i]); - os::signal(SIGNALS[i], CAST_FROM_FN_PTR(void *, crash_handler)); - sigaddset(&newset, SIGNALS[i]); - } - pthread_sigmask(SIG_UNBLOCK, &newset, NULL); -} diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index b81aa765dee..72449aff0bc 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -4970,7 +4970,7 @@ os::os_exception_wrapper(java_call_t f, JavaValue* value, const methodHandle& me void os::print_statistics() { } -int os::message_box(const char* title, const char* message) { +bool os::message_box(const char* title, const char* message) { int i; fdStream err(defaultStream::error_fd()); for (i = 0; i < 78; i++) err.print_raw("="); @@ -5995,6 +5995,34 @@ int os::get_core_path(char* buffer, size_t bufferSize) { return strlen(buffer); } +bool os::start_debugging(char *buf, int buflen) { + int len = (int)strlen(buf); + char *p = &buf[len]; + + jio_snprintf(p, buflen-len, + "\n\n" + "Do you want to debug the problem?\n\n" + "To debug, run 'gdb /proc/%d/exe %d'; then switch to thread " UINTX_FORMAT " (" INTPTR_FORMAT ")\n" + "Enter 'yes' to launch gdb automatically (PATH must include gdb)\n" + "Otherwise, press RETURN to abort...", + os::current_process_id(), os::current_process_id(), + os::current_thread_id(), os::current_thread_id()); + + bool yes = os::message_box("Unexpected Error", buf); + + if (yes) { + // yes, user asked VM to launch debugger + jio_snprintf(buf, sizeof(buf), "gdb /proc/%d/exe %d", + os::current_process_id(), os::current_process_id()); + + os::fork_and_exec(buf); + yes = false; + } + return yes; +} + + + /////////////// Unit tests /////////////// #ifndef PRODUCT diff --git a/hotspot/src/os/linux/vm/vmError_linux.cpp b/hotspot/src/os/linux/vm/vmError_linux.cpp deleted file mode 100644 index 4d684db2c8e..00000000000 --- a/hotspot/src/os/linux/vm/vmError_linux.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 "runtime/arguments.hpp" -#include "runtime/os.hpp" -#include "runtime/thread.hpp" -#include "utilities/vmError.hpp" - -#include -#include -#include -#include -#include - -void VMError::show_message_box(char *buf, int buflen) { - bool yes; - do { - error_string(buf, buflen); - int len = (int)strlen(buf); - char *p = &buf[len]; - - jio_snprintf(p, buflen - len, - "\n\n" - "Do you want to debug the problem?\n\n" - "To debug, run 'gdb /proc/%d/exe %d'; then switch to thread " UINTX_FORMAT " (" INTPTR_FORMAT ")\n" - "Enter 'yes' to launch gdb automatically (PATH must include gdb)\n" - "Otherwise, press RETURN to abort...", - os::current_process_id(), os::current_process_id(), - os::current_thread_id(), os::current_thread_id()); - - yes = os::message_box("Unexpected Error", buf); - - if (yes) { - // yes, user asked VM to launch debugger - jio_snprintf(buf, buflen, "gdb /proc/%d/exe %d", - os::current_process_id(), os::current_process_id()); - - os::fork_and_exec(buf); - yes = false; - } - } while (yes); -} - -// handle all synchronous program error signals which may happen during error -// reporting. They must be unblocked, caught, handled. - -static const int SIGNALS[] = { SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP }; // add more if needed -static const int NUM_SIGNALS = sizeof(SIGNALS) / sizeof(int); - -// Space for our "saved" signal flags and handlers -static int resettedSigflags[NUM_SIGNALS]; -static address resettedSighandler[NUM_SIGNALS]; - -static void save_signal(int idx, int sig) -{ - struct sigaction sa; - sigaction(sig, NULL, &sa); - resettedSigflags[idx] = sa.sa_flags; - resettedSighandler[idx] = (sa.sa_flags & SA_SIGINFO) - ? CAST_FROM_FN_PTR(address, sa.sa_sigaction) - : CAST_FROM_FN_PTR(address, sa.sa_handler); -} - -int VMError::get_resetted_sigflags(int sig) { - for (int i = 0; i < NUM_SIGNALS; i++) { - if (SIGNALS[i] == sig) { - return resettedSigflags[i]; - } - } - return -1; -} - -address VMError::get_resetted_sighandler(int sig) { - for (int i = 0; i < NUM_SIGNALS; i++) { - if (SIGNALS[i] == sig) { - return resettedSighandler[i]; - } - } - return NULL; -} - -static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { - // unmask current signal - sigset_t newset; - sigemptyset(&newset); - sigaddset(&newset, sig); - // also unmask other synchronous signals - for (int i = 0; i < NUM_SIGNALS; i++) { - sigaddset(&newset, SIGNALS[i]); - } - pthread_sigmask(SIG_UNBLOCK, &newset, NULL); - - // support safefetch faults in error handling - ucontext_t* const uc = (ucontext_t*) ucVoid; - address const pc = uc ? os::Linux::ucontext_get_pc(uc) : NULL; - - if (uc && pc && StubRoutines::is_safefetch_fault(pc)) { - os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); - return; - } - - VMError::report_and_die(NULL, sig, pc, info, ucVoid); -} - -void VMError::reset_signal_handlers() { - // install signal handlers for all synchronous program error signals - sigset_t newset; - sigemptyset(&newset); - - for (int i = 0; i < NUM_SIGNALS; i++) { - save_signal(i, SIGNALS[i]); - os::signal(SIGNALS[i], CAST_FROM_FN_PTR(void *, crash_handler)); - sigaddset(&newset, SIGNALS[i]); - } - pthread_sigmask(SIG_UNBLOCK, &newset, NULL); - -} diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp index 63fe550518b..93c4cbb6b09 100644 --- a/hotspot/src/os/posix/vm/os_posix.cpp +++ b/hotspot/src/os/posix/vm/os_posix.cpp @@ -988,6 +988,39 @@ void os::Posix::print_siginfo_brief(outputStream* os, const siginfo_t* si) { } } +int os::Posix::unblock_thread_signal_mask(const sigset_t *set) { + return pthread_sigmask(SIG_UNBLOCK, set, NULL); +} + +address os::Posix::ucontext_get_pc(ucontext_t* ctx) { +#ifdef TARGET_OS_FAMILY_linux + return Linux::ucontext_get_pc(ctx); +#elif defined(TARGET_OS_FAMILY_solaris) + return Solaris::ucontext_get_pc(ctx); +#elif defined(TARGET_OS_FAMILY_aix) + return Aix::ucontext_get_pc(ctx); +#elif defined(TARGET_OS_FAMILY_bsd) + return Bsd::ucontext_get_pc(ctx); +#else + VMError::report_and_die("unimplemented ucontext_get_pc"); +#endif +} + +void os::Posix::ucontext_set_pc(ucontext_t* ctx, address pc) { +#ifdef TARGET_OS_FAMILY_linux + Linux::ucontext_set_pc(ctx, pc); +#elif defined(TARGET_OS_FAMILY_solaris) + Solaris::ucontext_set_pc(ctx, pc); +#elif defined(TARGET_OS_FAMILY_aix) + Aix::ucontext_set_pc(ctx, pc); +#elif defined(TARGET_OS_FAMILY_bsd) + Bsd::ucontext_set_pc(ctx, pc); +#else + VMError::report_and_die("unimplemented ucontext_get_pc"); +#endif +} + + os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() { assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread"); } diff --git a/hotspot/src/os/posix/vm/os_posix.hpp b/hotspot/src/os/posix/vm/os_posix.hpp index ed08ad74abc..84a1a6eda43 100644 --- a/hotspot/src/os/posix/vm/os_posix.hpp +++ b/hotspot/src/os/posix/vm/os_posix.hpp @@ -57,6 +57,9 @@ public: // Prints a short one-line description of a signal set. static void print_signal_set_short(outputStream* st, const sigset_t* set); + // unblocks the signal masks for current thread + static int unblock_thread_signal_mask(const sigset_t *set); + // Writes a one-line description of a combination of sigaction.sa_flags // into a user provided buffer. Returns that buffer. static const char* describe_sa_flags(int flags, char* buffer, size_t size); @@ -67,6 +70,9 @@ public: // A POSIX conform, platform-independend siginfo print routine. static void print_siginfo_brief(outputStream* os, const siginfo_t* si); + static address ucontext_get_pc(ucontext_t* ctx); + // Set PC into context. Needed for continuation after signal. + static void ucontext_set_pc(ucontext_t* ctx, address pc); }; /* diff --git a/hotspot/src/os/solaris/vm/vmError_solaris.cpp b/hotspot/src/os/posix/vm/vmError_posix.cpp similarity index 74% rename from hotspot/src/os/solaris/vm/vmError_solaris.cpp rename to hotspot/src/os/posix/vm/vmError_posix.cpp index 8358801854e..6fb04af4dd3 100644 --- a/hotspot/src/os/solaris/vm/vmError_solaris.cpp +++ b/hotspot/src/os/posix/vm/vmError_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,35 +30,23 @@ #include #include -#include #include -void VMError::show_message_box(char *buf, int buflen) { - bool yes; - do { - error_string(buf, buflen); - int len = (int)strlen(buf); - char *p = &buf[len]; +#ifdef TARGET_OS_FAMILY_linux +#include +#include +#endif +#ifdef TARGET_OS_FAMILY_solaris +#include +#endif +#ifdef TARGET_OS_FAMILY_aix +#include +#endif +#ifdef TARGET_OS_FAMILY_bsd +#include +#include +#endif - jio_snprintf(p, buflen - len, - "\n\n" - "Do you want to debug the problem?\n\n" - "To debug, run 'dbx - %d'; then switch to thread " INTX_FORMAT "\n" - "Enter 'yes' to launch dbx automatically (PATH must include dbx)\n" - "Otherwise, press RETURN to abort...", - os::current_process_id(), os::current_thread_id()); - - yes = os::message_box("Unexpected Error", buf); - - if (yes) { - // yes, user asked VM to launch debugger - jio_snprintf(buf, buflen, "dbx - %d", os::current_process_id()); - - os::fork_and_exec(buf); - yes = false; - } - } while (yes); -} // handle all synchronous program error signals which may happen during error // reporting. They must be unblocked, caught, handled. @@ -107,13 +95,14 @@ static void crash_handler(int sig, siginfo_t* info, void* ucVoid) { for (int i = 0; i < NUM_SIGNALS; i++) { sigaddset(&newset, SIGNALS[i]); } - thr_sigsetmask(SIG_UNBLOCK, &newset, NULL); + os::Posix::unblock_thread_signal_mask(&newset); // support safefetch faults in error handling ucontext_t* const uc = (ucontext_t*) ucVoid; - address const pc = uc ? os::Solaris::ucontext_get_pc(uc) : NULL; + address const pc = uc ? os::Posix::ucontext_get_pc(uc) : NULL; + if (uc && pc && StubRoutines::is_safefetch_fault(pc)) { - os::Solaris::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); + os::Posix::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); return; } @@ -130,5 +119,6 @@ void VMError::reset_signal_handlers() { os::signal(SIGNALS[i], CAST_FROM_FN_PTR(void *, crash_handler)); sigaddset(&newset, SIGNALS[i]); } - thr_sigsetmask(SIG_UNBLOCK, &newset, NULL); + os::Posix::unblock_thread_signal_mask(&newset); + } diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index de90c5ca4f8..84b5f73e60b 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -3611,7 +3611,7 @@ void os::Solaris::SR_handler(Thread* thread, ucontext_t* uc) { void os::print_statistics() { } -int os::message_box(const char* title, const char* message) { +bool os::message_box(const char* title, const char* message) { int i; fdStream err(defaultStream::error_fd()); for (i = 0; i < 78; i++) err.print_raw("="); @@ -5804,3 +5804,27 @@ void TestReserveMemorySpecial_test() { // No tests available for this platform } #endif + +bool os::start_debugging(char *buf, int buflen) { + int len = (int)strlen(buf); + char *p = &buf[len]; + + jio_snprintf(p, buflen-len, + "\n\n" + "Do you want to debug the problem?\n\n" + "To debug, run 'dbx - %d'; then switch to thread " INTX_FORMAT "\n" + "Enter 'yes' to launch dbx automatically (PATH must include dbx)\n" + "Otherwise, press RETURN to abort...", + os::current_process_id(), os::current_thread_id()); + + bool yes = os::message_box("Unexpected Error", buf); + + if (yes) { + // yes, user asked VM to launch debugger + jio_snprintf(buf, sizeof(buf), "dbx - %d", os::current_process_id()); + + os::fork_and_exec(buf); + yes = false; + } + return yes; +} diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 45a9bb11d0b..8167feed2c2 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -4005,7 +4005,7 @@ void os::wait_for_keypress_at_exit(void) { } -int os::message_box(const char* title, const char* message) { +bool os::message_box(const char* title, const char* message) { int result = MessageBox(NULL, message, title, MB_YESNO | MB_ICONERROR | MB_SYSTEMMODAL | MB_DEFAULT_DESKTOP_ONLY); return result == IDYES; @@ -5505,7 +5505,31 @@ void os::Kernel32Dll::initializeCommon() { } } +bool os::start_debugging(char *buf, int buflen) { + int len = (int)strlen(buf); + char *p = &buf[len]; + jio_snprintf(p, buflen-len, + "\n\n" + "Do you want to debug the problem?\n\n" + "To debug, attach Visual Studio to process %d; then switch to thread 0x%x\n" + "Select 'Yes' to launch Visual Studio automatically (PATH must include msdev)\n" + "Otherwise, select 'No' to abort...", + os::current_process_id(), os::current_thread_id()); + + bool yes = os::message_box("Unexpected Error", buf); + + if (yes) { + // os::breakpoint() calls DebugBreak(), which causes a breakpoint + // exception. If VM is running inside a debugger, the debugger will + // catch the exception. Otherwise, the breakpoint exception will reach + // the default windows exception handler, which can spawn a debugger and + // automatically attach to the dying VM. + os::breakpoint(); + yes = false; + } + return yes; +} #ifndef JDK6_OR_EARLIER diff --git a/hotspot/src/os/windows/vm/vmError_windows.cpp b/hotspot/src/os/windows/vm/vmError_windows.cpp index 44be12294bd..d80fe55fe3b 100644 --- a/hotspot/src/os/windows/vm/vmError_windows.cpp +++ b/hotspot/src/os/windows/vm/vmError_windows.cpp @@ -28,38 +28,6 @@ #include "runtime/thread.hpp" #include "utilities/vmError.hpp" - -void VMError::show_message_box(char *buf, int buflen) { - bool yes; - do { - error_string(buf, buflen); - int len = (int)strlen(buf); - char *p = &buf[len]; - - jio_snprintf(p, buflen - len, - "\n\n" - "Do you want to debug the problem?\n\n" - "To debug, attach Visual Studio to process %d; then switch to thread 0x%x\n" - "Select 'Yes' to launch Visual Studio automatically (PATH must include msdev)\n" - "Otherwise, select 'No' to abort...", - os::current_process_id(), os::current_thread_id()); - - yes = os::message_box("Unexpected Error", buf) != 0; - - if (yes) { - // yes, user asked VM to launch debugger - // - // os::breakpoint() calls DebugBreak(), which causes a breakpoint - // exception. If VM is running inside a debugger, the debugger will - // catch the exception. Otherwise, the breakpoint exception will reach - // the default windows exception handler, which can spawn a debugger and - // automatically attach to the dying VM. - os::breakpoint(); - yes = false; - } - } while (yes); -} - int VMError::get_resetted_sigflags(int sig) { return -1; } diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index f9b920ee822..0e104226501 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -476,6 +476,7 @@ class os: AllStatic { static ExtendedPC get_thread_pc(Thread *thread); static void breakpoint(); + static bool start_debugging(char *buf, int buflen); static address current_stack_pointer(); static address current_stack_base(); @@ -483,7 +484,7 @@ class os: AllStatic { static void verify_stack_alignment() PRODUCT_RETURN; - static int message_box(const char* title, const char* message); + static bool message_box(const char* title, const char* message); static char* do_you_want_to_debug(const char* message); // run cmd in a separate process and return its exit code; or -1 on failures diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index 6af19370b7c..c12e37526e5 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -1349,3 +1349,11 @@ void VMError::report_java_out_of_memory(const char* message) { VMThread::execute(&op); } } + +void VMError::show_message_box(char *buf, int buflen) { + bool yes; + do { + error_string(buf, buflen); + yes = os::start_debugging(buf,buflen); + } while (yes); +} From ae6fc5e37b0dbf1c56a55fe115055ef19e9d1450 Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Wed, 25 Nov 2015 21:54:05 +0100 Subject: [PATCH 084/260] 8142494: Add extension point to G1EvacuationRootClosures Reviewed-by: jmasa, mgerdin --- hotspot/src/share/vm/gc/g1/g1RootClosures.cpp | 69 +++-------------- hotspot/src/share/vm/gc/g1/g1RootClosures.hpp | 1 + .../share/vm/gc/g1/g1RootClosures.inline.hpp | 77 +++++++++++++++++++ .../src/share/vm/gc/g1/g1RootClosures_ext.cpp | 30 ++++++++ 4 files changed, 118 insertions(+), 59 deletions(-) create mode 100644 hotspot/src/share/vm/gc/g1/g1RootClosures.inline.hpp create mode 100644 hotspot/src/share/vm/gc/g1/g1RootClosures_ext.cpp diff --git a/hotspot/src/share/vm/gc/g1/g1RootClosures.cpp b/hotspot/src/share/vm/gc/g1/g1RootClosures.cpp index 2f393e425ae..3d93bf9cec9 100644 --- a/hotspot/src/share/vm/gc/g1/g1RootClosures.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RootClosures.cpp @@ -23,62 +23,7 @@ */ #include "precompiled.hpp" - -#include "gc/g1/bufferingOopClosure.hpp" -#include "gc/g1/g1CodeBlobClosure.hpp" -#include "gc/g1/g1CollectedHeap.hpp" -#include "gc/g1/g1OopClosures.inline.hpp" -#include "gc/g1/g1RootClosures.hpp" - -class G1ParScanThreadState; - -// Simple holder object for a complete set of closures used by the G1 evacuation code. -template -class G1SharedClosures VALUE_OBJ_CLASS_SPEC { -public: - G1ParCopyClosure _oops; - G1ParCopyClosure _oop_in_klass; - G1KlassScanClosure _klass_in_cld_closure; - CLDToKlassAndOopClosure _clds; - G1CodeBlobClosure _codeblobs; - BufferingOopClosure _buffered_oops; - - G1SharedClosures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, bool process_only_dirty_klasses, bool must_claim_cld) : - _oops(g1h, pss), - _oop_in_klass(g1h, pss), - _klass_in_cld_closure(&_oop_in_klass, process_only_dirty_klasses), - _clds(&_klass_in_cld_closure, &_oops, must_claim_cld), - _codeblobs(&_oops), - _buffered_oops(&_oops) {} -}; - -class G1EvacuationClosures : public G1EvacuationRootClosures { - G1SharedClosures _closures; - -public: - G1EvacuationClosures(G1CollectedHeap* g1h, - G1ParScanThreadState* pss, - bool gcs_are_young) : - _closures(g1h, pss, gcs_are_young, /* must_claim_cld */ false) {} - - OopClosure* weak_oops() { return &_closures._buffered_oops; } - OopClosure* strong_oops() { return &_closures._buffered_oops; } - - CLDClosure* weak_clds() { return &_closures._clds; } - CLDClosure* strong_clds() { return &_closures._clds; } - CLDClosure* thread_root_clds() { return NULL; } - CLDClosure* second_pass_weak_clds() { return NULL; } - - 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; } -}; +#include "gc/g1/g1RootClosures.inline.hpp" // Closures used during initial mark. // The treatment of "weak" roots is selectable through the template parameter, @@ -137,13 +82,19 @@ public: }; G1EvacuationRootClosures* G1EvacuationRootClosures::create_root_closures(G1ParScanThreadState* pss, G1CollectedHeap* g1h) { + G1EvacuationRootClosures* res = create_root_closures_ext(pss, g1h); + if (res != NULL) { + return res; + } + if (g1h->collector_state()->during_initial_mark_pause()) { if (ClassUnloadingWithConcurrentMark) { - return new G1InitalMarkClosures(g1h, pss); + res = new G1InitalMarkClosures(g1h, pss); } else { - return new G1InitalMarkClosures(g1h, pss); + res = new G1InitalMarkClosures(g1h, pss); } } else { - return new G1EvacuationClosures(g1h, pss, g1h->collector_state()->gcs_are_young()); + res = new G1EvacuationClosures(g1h, pss, g1h->collector_state()->gcs_are_young()); } + return res; } diff --git a/hotspot/src/share/vm/gc/g1/g1RootClosures.hpp b/hotspot/src/share/vm/gc/g1/g1RootClosures.hpp index e4a707f74b0..34e58f0f411 100644 --- a/hotspot/src/share/vm/gc/g1/g1RootClosures.hpp +++ b/hotspot/src/share/vm/gc/g1/g1RootClosures.hpp @@ -49,6 +49,7 @@ public: }; class G1EvacuationRootClosures : public G1RootClosures { + static G1EvacuationRootClosures* create_root_closures_ext(G1ParScanThreadState* pss, G1CollectedHeap* g1h); public: // Flush any buffered state and deferred processing virtual void flush() = 0; diff --git a/hotspot/src/share/vm/gc/g1/g1RootClosures.inline.hpp b/hotspot/src/share/vm/gc/g1/g1RootClosures.inline.hpp new file mode 100644 index 00000000000..57cf4c7c2a4 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1RootClosures.inline.hpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "gc/g1/bufferingOopClosure.hpp" +#include "gc/g1/g1CodeBlobClosure.hpp" +#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1OopClosures.inline.hpp" +#include "gc/g1/g1RootClosures.hpp" + +// Simple holder object for a complete set of closures used by the G1 evacuation code. +template +class G1SharedClosures VALUE_OBJ_CLASS_SPEC { +public: + G1ParCopyClosure _oops; + G1ParCopyClosure _oop_in_klass; + G1KlassScanClosure _klass_in_cld_closure; + CLDToKlassAndOopClosure _clds; + G1CodeBlobClosure _codeblobs; + BufferingOopClosure _buffered_oops; + + G1SharedClosures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, bool process_only_dirty_klasses, bool must_claim_cld) : + _oops(g1h, pss), + _oop_in_klass(g1h, pss), + _klass_in_cld_closure(&_oop_in_klass, process_only_dirty_klasses), + _clds(&_klass_in_cld_closure, &_oops, must_claim_cld), + _codeblobs(&_oops), + _buffered_oops(&_oops) {} +}; + +class G1EvacuationClosures : public G1EvacuationRootClosures { + G1SharedClosures _closures; + +public: + G1EvacuationClosures(G1CollectedHeap* g1h, + G1ParScanThreadState* pss, + bool gcs_are_young) : + _closures(g1h, pss, gcs_are_young, /* must_claim_cld */ false) {} + + OopClosure* weak_oops() { return &_closures._buffered_oops; } + OopClosure* strong_oops() { return &_closures._buffered_oops; } + + CLDClosure* weak_clds() { return &_closures._clds; } + CLDClosure* strong_clds() { return &_closures._clds; } + CLDClosure* thread_root_clds() { return NULL; } + CLDClosure* second_pass_weak_clds() { return NULL; } + + 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; } +}; diff --git a/hotspot/src/share/vm/gc/g1/g1RootClosures_ext.cpp b/hotspot/src/share/vm/gc/g1/g1RootClosures_ext.cpp new file mode 100644 index 00000000000..a4f81f29d03 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1RootClosures_ext.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/g1/g1RootClosures.hpp" + +G1EvacuationRootClosures* G1EvacuationRootClosures::create_root_closures_ext(G1ParScanThreadState* pss, G1CollectedHeap* g1h) { + return NULL; +} From 7bb30f51ab41bace25c87ec1ecbb2b9932cf3e17 Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Mon, 19 Oct 2015 16:33:12 +0200 Subject: [PATCH 085/260] 8139892: Allow G1CollectorPolicy to specify if reference processing should be enabled Reviewed-by: mgerdin, kbarrett, tbenson --- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 30 +++++++++++++++++-- .../src/share/vm/gc/g1/g1CollectedHeap.hpp | 2 ++ .../src/share/vm/gc/g1/g1CollectorPolicy.hpp | 4 +++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index eda9b26c939..2be6d7568ff 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -3826,7 +3826,11 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { // reference processing currently works in G1. // Enable discovery in the STW reference processor - ref_processor_stw()->enable_discovery(); + if (g1_policy()->should_process_references()) { + ref_processor_stw()->enable_discovery(); + } else { + ref_processor_stw()->disable_discovery(); + } { // We want to temporarily turn off discovery by the @@ -4973,6 +4977,17 @@ public: } }; +void G1CollectedHeap::process_weak_jni_handles() { + double ref_proc_start = os::elapsedTime(); + + G1STWIsAliveClosure is_alive(this); + G1KeepAliveClosure keep_alive(this); + JNIHandles::weak_oops_do(&is_alive, &keep_alive); + + double ref_proc_time = os::elapsedTime() - ref_proc_start; + g1_policy()->phase_times()->record_ref_proc_time(ref_proc_time * 1000.0); +} + // Weak Reference processing during an evacuation pause (part 1). void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per_thread_states) { double ref_proc_start = os::elapsedTime(); @@ -5157,7 +5172,12 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info, G // as we may have to copy some 'reachable' referent // objects (and their reachable sub-graphs) that were // not copied during the pause. - process_discovered_references(per_thread_states); + if (g1_policy()->should_process_references()) { + process_discovered_references(per_thread_states); + } else { + ref_processor_stw()->verify_no_references_recorded(); + process_weak_jni_handles(); + } if (G1StringDedup::is_enabled()) { double fixup_start = os::elapsedTime(); @@ -5188,7 +5208,11 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info, G // will log these updates (and dirty their associated // cards). We need these updates logged to update any // RSets. - enqueue_discovered_references(per_thread_states); + if (g1_policy()->should_process_references()) { + enqueue_discovered_references(per_thread_states); + } else { + g1_policy()->phase_times()->record_ref_enq_time(0); + } } void G1CollectedHeap::post_evacuate_collection_set(EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* per_thread_states) { diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index 0f0488db745..dfaac91f032 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -292,6 +292,8 @@ private: void trace_heap(GCWhen::Type when, const GCTracer* tracer); + void process_weak_jni_handles(); + // These are macros so that, if the assert fires, we get the correct // line number, file, etc. diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp index 07d92cf9afc..2453a3a8868 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp @@ -783,6 +783,10 @@ public: return _young_gen_sizer->adaptive_young_list_length(); } + virtual bool should_process_references() const { + return true; + } + private: // // Survivor regions policy. From 0580d65a1c8cbcd388785e88817530bf401cb38e Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Thu, 12 Nov 2015 14:03:14 +0100 Subject: [PATCH 086/260] 8142403: Make G1CollectorPolicy::predictor const Reviewed-by: stefank, tschatzl --- hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp index 8ed9a72502f..416d695f30d 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp @@ -272,7 +272,7 @@ class G1CollectorPolicy: public CollectorPolicy { size_t _pending_cards; public: - G1Predictions& predictor() { return _predictor; } + const G1Predictions& predictor() const { return _predictor; } // Accessors From 68ffb0bf12fc8629c9a289af7499a9c8d3295a23 Mon Sep 17 00:00:00 2001 From: Jungwoo Ha Date: Tue, 3 Nov 2015 13:03:04 -0800 Subject: [PATCH 087/260] 8141356: Explicitly stop CMS threads during VM termination GenCollectedHeap::stop() is not implemented which is supposed to stop CMS threads during VM termination. Reviewed-by: jmasa, kbarrett --- hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp | 8 ++++++++ hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp | 3 +++ 2 files changed, 11 insertions(+) diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp index 5724808b142..bfa47a3734a 100644 --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp @@ -1319,3 +1319,11 @@ jlong GenCollectedHeap::millis_since_last_gc() { } return retVal; } + +void GenCollectedHeap::stop() { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + ConcurrentMarkSweepThread::stop(); + } +#endif +} diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp index 954bc8ad281..11114dd38f0 100644 --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp @@ -499,6 +499,9 @@ private: protected: void gc_prologue(bool full); void gc_epilogue(bool full); + +public: + void stop(); }; #endif // SHARE_VM_GC_SHARED_GENCOLLECTEDHEAP_HPP From 0a4657e8c129da85040c00dd8fb9425ea69a38fe Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 5 Nov 2015 15:05:59 +0100 Subject: [PATCH 088/260] 8141529: Fix handling of _JAVA_SR_SIGNUM Reviewed-by: dholmes, stuefe, dsamersoff --- hotspot/src/os/aix/vm/jsig.c | 42 +++++++++++------------- hotspot/src/os/aix/vm/os_aix.cpp | 31 ++++++++++------- hotspot/src/os/aix/vm/os_aix.hpp | 9 ----- hotspot/src/os/bsd/vm/jsig.c | 12 ++++--- hotspot/src/os/bsd/vm/os_bsd.cpp | 31 ++++++++++------- hotspot/src/os/bsd/vm/os_bsd.hpp | 7 ---- hotspot/src/os/linux/vm/jsig.c | 21 +++++++----- hotspot/src/os/linux/vm/os_linux.cpp | 31 ++++++++++------- hotspot/src/os/linux/vm/os_linux.hpp | 8 ----- hotspot/src/os/solaris/vm/os_solaris.hpp | 3 -- 10 files changed, 97 insertions(+), 98 deletions(-) diff --git a/hotspot/src/os/aix/vm/jsig.c b/hotspot/src/os/aix/vm/jsig.c index ca15dc595ac..d39fbe311eb 100644 --- a/hotspot/src/os/aix/vm/jsig.c +++ b/hotspot/src/os/aix/vm/jsig.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,26 +36,23 @@ #include #include #include +#include #define bool int #define true 1 #define false 0 -// Highest so far on AIX 5.2 is SIGSAK (63) -#define MAXSIGNUM 63 -#define MASK(sig) ((unsigned int)1 << sig) +static struct sigaction sact[NSIG]; /* saved signal handlers */ +static sigset_t jvmsigs; /* Signals used by jvm. */ -static struct sigaction sact[MAXSIGNUM]; /* saved signal handlers */ -static unsigned int jvmsigs = 0; /* signals used by jvm */ - -/* used to synchronize the installation of signal handlers */ +/* Used to synchronize the installation of signal handlers. */ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; static pthread_t tid = 0; typedef void (*sa_handler_t)(int); typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); -// signal_t is already defined on AIX +// signal_t is already defined on AIX. typedef sa_handler_t (*signal_like_function_t)(int, sa_handler_t); typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *); @@ -68,7 +65,7 @@ static bool jvm_signal_installed = false; static void signal_lock() { pthread_mutex_lock(&mutex); /* When the jvm is installing its set of signal handlers, threads - * other than the jvm thread should wait */ + * other than the jvm thread should wait. */ if (jvm_signal_installing) { if (tid != pthread_self()) { pthread_cond_wait(&cond, &mutex); @@ -84,10 +81,10 @@ static sa_handler_t call_os_signal(int sig, sa_handler_t disp, bool is_sigset) { if (os_signal == NULL) { if (!is_sigset) { - // Aix: call functions directly instead of dlsym'ing them + // Aix: call functions directly instead of dlsym'ing them. os_signal = signal; } else { - // Aix: call functions directly instead of dlsym'ing them + // Aix: call functions directly instead of dlsym'ing them. os_signal = sigset; } if (os_signal == NULL) { @@ -112,7 +109,7 @@ static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) { signal_lock(); - sigused = (MASK(sig) & jvmsigs) != 0; + sigused = sigismember(&jvmsigs, sig); if (jvm_signal_installed && sigused) { /* jvm has installed its signal handler for this signal. */ /* Save the handler. Don't really install it. */ @@ -129,7 +126,7 @@ static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) { save_signal_handler(sig, oldhandler); /* Record the signals used by jvm */ - jvmsigs |= MASK(sig); + sigaddset(&jvmsigs, sig); signal_unlock(); return oldhandler; @@ -149,12 +146,12 @@ sa_handler_t signal(int sig, sa_handler_t disp) { sa_handler_t sigset(int sig, sa_handler_t disp) { return set_signal(sig, disp, true); - } +} static int call_os_sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { if (os_sigaction == NULL) { - // Aix: call functions directly instead of dlsym'ing them + // Aix: call functions directly instead of dlsym'ing them. os_sigaction = sigaction; if (os_sigaction == NULL) { printf("%s\n", dlerror()); @@ -171,7 +168,7 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { signal_lock(); - sigused = (MASK(sig) & jvmsigs) != 0; + sigused = sigismember(&jvmsigs, sig); if (jvm_signal_installed && sigused) { /* jvm has installed its signal handler for this signal. */ /* Save the handler. Don't really install it. */ @@ -193,8 +190,8 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { *oact = oldAct; } - /* Record the signals used by jvm */ - jvmsigs |= MASK(sig); + /* Record the signals used by jvm. */ + sigaddset(&jvmsigs, sig); signal_unlock(); return res; @@ -208,9 +205,10 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { } } -/* The three functions for the jvm to call into */ +/* The three functions for the jvm to call into. */ void JVM_begin_signal_setting() { signal_lock(); + sigemptyset(&jvmsigs); jvm_signal_installing = true; tid = pthread_self(); signal_unlock(); @@ -226,7 +224,7 @@ void JVM_end_signal_setting() { struct sigaction *JVM_get_signal_action(int sig) { /* Does race condition make sense here? */ - if ((MASK(sig) & jvmsigs) != 0) { + if (sigismember(&jvmsigs, sig)) { return &sact[sig]; } return NULL; diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index 9bc5ab02f06..b45a9d360aa 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -2769,8 +2769,12 @@ static int SR_initialize() { // Get signal number to use for suspend/resume if ((s = ::getenv("_JAVA_SR_SIGNUM")) != 0) { int sig = ::strtol(s, 0, 10); - if (sig > 0 || sig < NSIG) { + if (sig > MAX2(SIGSEGV, SIGBUS) && // See 4355769. + sig < NSIG) { // Must be legal signal and fit into sigflags[]. SR_signum = sig; + } else { + warning("You set _JAVA_SR_SIGNUM=%d. It must be in range [%d, %d]. Using %d instead.", + sig, MAX2(SIGSEGV, SIGBUS)+1, NSIG-1, SR_signum); } } @@ -2966,8 +2970,8 @@ void javaSignalHandler(int sig, siginfo_t* info, void* uc) { bool os::Aix::signal_handlers_are_installed = false; // For signal-chaining -struct sigaction os::Aix::sigact[MAXSIGNUM]; -unsigned int os::Aix::sigs = 0; +struct sigaction sigact[NSIG]; +sigset_t sigs; bool os::Aix::libjsig_is_loaded = false; typedef struct sigaction *(*get_signal_t)(int); get_signal_t os::Aix::get_signal_action = NULL; @@ -3045,29 +3049,31 @@ bool os::Aix::chained_handler(int sig, siginfo_t* siginfo, void* context) { } struct sigaction* os::Aix::get_preinstalled_handler(int sig) { - if ((((unsigned int)1 << sig) & sigs) != 0) { + if (sigismember(&sigs, sig)) { return &sigact[sig]; } return NULL; } void os::Aix::save_preinstalled_handler(int sig, struct sigaction& oldAct) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); sigact[sig] = oldAct; - sigs |= (unsigned int)1 << sig; + sigaddset(&sigs, sig); } // for diagnostic -int os::Aix::sigflags[MAXSIGNUM]; +int sigflags[NSIG]; int os::Aix::get_our_sigflags(int sig) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); return sigflags[sig]; } void os::Aix::set_our_sigflags(int sig, int flags) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); - sigflags[sig] = flags; + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); + if (sig > 0 && sig < NSIG) { + sigflags[sig] = flags; + } } void os::Aix::set_signal_handler(int sig, bool set_installed) { @@ -3107,7 +3113,7 @@ void os::Aix::set_signal_handler(int sig, bool set_installed) { sigAct.sa_flags = SA_SIGINFO|SA_RESTART; } // Save flags, which are set by ours - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); sigflags[sig] = sigAct.sa_flags; int ret = sigaction(sig, &sigAct, &oldAct); @@ -3140,10 +3146,11 @@ void os::Aix::install_signal_handlers() { assert(UseSignalChaining, "should enable signal-chaining"); } if (libjsig_is_loaded) { - // Tell libjsig jvm is setting signal handlers + // Tell libjsig jvm is setting signal handlers. (*begin_signal_setting)(); } + ::sigemptyset(&sigs); set_signal_handler(SIGSEGV, true); set_signal_handler(SIGPIPE, true); set_signal_handler(SIGBUS, true); diff --git a/hotspot/src/os/aix/vm/os_aix.hpp b/hotspot/src/os/aix/vm/os_aix.hpp index 8e96dd9f6c5..7381da500e2 100644 --- a/hotspot/src/os/aix/vm/os_aix.hpp +++ b/hotspot/src/os/aix/vm/os_aix.hpp @@ -34,15 +34,9 @@ static bool zero_page_read_protected() { return false; } class Aix { friend class os; - // For signal-chaining - // highest so far (AIX 5.2 - 6.1) is SIGSAK (63) -#define MAXSIGNUM 63 // Length of strings included in the libperfstat structures. #define IDENTIFIER_LENGTH 64 - static struct sigaction sigact[MAXSIGNUM]; // saved preinstalled sigactions - static unsigned int sigs; // mask of signals that have - // preinstalled signal handlers static bool libjsig_is_loaded; // libjsig that interposes sigaction(), // __sigaction(), signal() is loaded static struct sigaction *(*get_signal_action)(int); @@ -51,9 +45,6 @@ class Aix { static void check_signal_handler(int sig); - // For signal flags diagnostics - static int sigflags[MAXSIGNUM]; - protected: static julong _physical_memory; diff --git a/hotspot/src/os/bsd/vm/jsig.c b/hotspot/src/os/bsd/vm/jsig.c index 597e57ab75a..d7b1e8be1a7 100644 --- a/hotspot/src/os/bsd/vm/jsig.c +++ b/hotspot/src/os/bsd/vm/jsig.c @@ -36,12 +36,14 @@ #include #include #include +#include -#define MAXSIGNUM 32 -#define MASK(sig) ((unsigned int)1 << sig) - -static struct sigaction sact[MAXSIGNUM]; /* saved signal handlers */ -static unsigned int jvmsigs = 0; /* signals used by jvm */ +#define MASK(sig) ((uint32_t)1 << (sig-1)) // 0 is not a signal. +#if (32 < NSIG-1) +#error "Not all signals can be encoded in jvmsigs. Adapt its type!" +#endif +static struct sigaction sact[NSIG]; /* saved signal handlers */ +static uint32_t jvmsigs = 0; /* signals used by jvm */ static __thread bool reentry = false; /* prevent reentry deadlock (per-thread) */ /* used to synchronize the installation of signal handlers */ diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 70eef822955..a21d2c92a0b 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -2831,8 +2831,12 @@ static int SR_initialize() { // Get signal number to use for suspend/resume if ((s = ::getenv("_JAVA_SR_SIGNUM")) != 0) { int sig = ::strtol(s, 0, 10); - if (sig > 0 || sig < NSIG) { + if (sig > MAX2(SIGSEGV, SIGBUS) && // See 4355769. + sig < NSIG) { // Must be legal signal and fit into sigflags[]. SR_signum = sig; + } else { + warning("You set _JAVA_SR_SIGNUM=%d. It must be in range [%d, %d]. Using %d instead.", + sig, MAX2(SIGSEGV, SIGBUS)+1, NSIG-1, SR_signum); } } @@ -2985,8 +2989,11 @@ void signalHandler(int sig, siginfo_t* info, void* uc) { bool os::Bsd::signal_handlers_are_installed = false; // For signal-chaining -struct sigaction os::Bsd::sigact[MAXSIGNUM]; -unsigned int os::Bsd::sigs = 0; +struct sigaction sigact[NSIG]; +uint32_t sigs = 0; +#if (32 < NSIG-1) +#error "Not all signals can be encoded in sigs. Adapt its type!" +#endif bool os::Bsd::libjsig_is_loaded = false; typedef struct sigaction *(*get_signal_t)(int); get_signal_t os::Bsd::get_signal_action = NULL; @@ -3064,29 +3071,31 @@ bool os::Bsd::chained_handler(int sig, siginfo_t* siginfo, void* context) { } struct sigaction* os::Bsd::get_preinstalled_handler(int sig) { - if ((((unsigned int)1 << sig) & sigs) != 0) { + if ((((uint32_t)1 << (sig-1)) & sigs) != 0) { return &sigact[sig]; } return NULL; } void os::Bsd::save_preinstalled_handler(int sig, struct sigaction& oldAct) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); sigact[sig] = oldAct; - sigs |= (unsigned int)1 << sig; + sigs |= (uint32_t)1 << (sig-1); } // for diagnostic -int os::Bsd::sigflags[MAXSIGNUM]; +int sigflags[NSIG]; int os::Bsd::get_our_sigflags(int sig) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); return sigflags[sig]; } void os::Bsd::set_our_sigflags(int sig, int flags) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); - sigflags[sig] = flags; + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); + if (sig > 0 && sig < NSIG) { + sigflags[sig] = flags; + } } void os::Bsd::set_signal_handler(int sig, bool set_installed) { @@ -3137,7 +3146,7 @@ void os::Bsd::set_signal_handler(int sig, bool set_installed) { #endif // Save flags, which are set by ours - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); sigflags[sig] = sigAct.sa_flags; int ret = sigaction(sig, &sigAct, &oldAct); diff --git a/hotspot/src/os/bsd/vm/os_bsd.hpp b/hotspot/src/os/bsd/vm/os_bsd.hpp index 8b48cb78cf0..4c63d532043 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.hpp +++ b/hotspot/src/os/bsd/vm/os_bsd.hpp @@ -40,10 +40,6 @@ class Bsd { friend class os; // For signal-chaining -#define MAXSIGNUM 32 - static struct sigaction sigact[MAXSIGNUM]; // saved preinstalled sigactions - static unsigned int sigs; // mask of signals that have - // preinstalled signal handlers static bool libjsig_is_loaded; // libjsig that interposes sigaction(), // __sigaction(), signal() is loaded static struct sigaction *(*get_signal_action)(int); @@ -52,9 +48,6 @@ class Bsd { static void check_signal_handler(int sig); - // For signal flags diagnostics - static int sigflags[MAXSIGNUM]; - #ifdef __APPLE__ // mach_absolute_time static mach_timebase_info_data_t _timebase_info; diff --git a/hotspot/src/os/linux/vm/jsig.c b/hotspot/src/os/linux/vm/jsig.c index ae2f25b33c4..f4221355ca0 100644 --- a/hotspot/src/os/linux/vm/jsig.c +++ b/hotspot/src/os/linux/vm/jsig.c @@ -35,16 +35,19 @@ #include #include #include +#include #define bool int #define true 1 #define false 0 -#define MAXSIGNUM 32 -#define MASK(sig) ((unsigned int)1 << sig) - -static struct sigaction sact[MAXSIGNUM]; /* saved signal handlers */ -static unsigned int jvmsigs = 0; /* signals used by jvm */ +#define MASK(sig) ((uint64_t)1 << (sig-1)) // 0 is not a signal. +// Check whether all signals fit into jvmsigs. -1 as MASK shifts by -1. +#if (64 < NSIG-1) +#error "Not all signals can be encoded in jvmsigs. Adapt its type!" +#endif +static struct sigaction sact[NSIG]; /* saved signal handlers */ +static uint64_t jvmsigs = 0; /* signals used by jvm */ /* used to synchronize the installation of signal handlers */ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; @@ -107,7 +110,7 @@ static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) { signal_lock(); - sigused = (sig < MAXSIGNUM) && ((MASK(sig) & jvmsigs) != 0); + sigused = (sig < NSIG) && ((MASK(sig) & jvmsigs) != 0); if (jvm_signal_installed && sigused) { /* jvm has installed its signal handler for this signal. */ /* Save the handler. Don't really install it. */ @@ -116,7 +119,7 @@ static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) { signal_unlock(); return oldhandler; - } else if (sig < MAXSIGNUM && jvm_signal_installing) { + } else if (sig < NSIG && jvm_signal_installing) { /* jvm is installing its signal handlers. Install the new * handlers and save the old ones. jvm uses sigaction(). * Leave the piece here just in case. */ @@ -165,7 +168,7 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { signal_lock(); - sigused = (sig < MAXSIGNUM) && ((MASK(sig) & jvmsigs) != 0); + sigused = (sig < NSIG) && ((MASK(sig) & jvmsigs) != 0); if (jvm_signal_installed && sigused) { /* jvm has installed its signal handler for this signal. */ /* Save the handler. Don't really install it. */ @@ -178,7 +181,7 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { signal_unlock(); return 0; - } else if (sig < MAXSIGNUM && jvm_signal_installing) { + } else if (sig < NSIG && jvm_signal_installing) { /* jvm is installing its signal handlers. Install the new * handlers and save the old ones. */ res = call_os_sigaction(sig, act, &oldAct); diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 8c5486f5d19..b81aa765dee 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -3989,15 +3989,19 @@ static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) { errno = old_errno; } - static int SR_initialize() { struct sigaction act; char *s; + // Get signal number to use for suspend/resume if ((s = ::getenv("_JAVA_SR_SIGNUM")) != 0) { int sig = ::strtol(s, 0, 10); - if (sig > 0 || sig < _NSIG) { + if (sig > MAX2(SIGSEGV, SIGBUS) && // See 4355769. + sig < NSIG) { // Must be legal signal and fit into sigflags[]. SR_signum = sig; + } else { + warning("You set _JAVA_SR_SIGNUM=%d. It must be in range [%d, %d]. Using %d instead.", + sig, MAX2(SIGSEGV, SIGBUS)+1, NSIG-1, SR_signum); } } @@ -4151,8 +4155,11 @@ void signalHandler(int sig, siginfo_t* info, void* uc) { bool os::Linux::signal_handlers_are_installed = false; // For signal-chaining -struct sigaction os::Linux::sigact[MAXSIGNUM]; -unsigned int os::Linux::sigs = 0; +struct sigaction sigact[NSIG]; +uint64_t sigs = 0; +#if (64 < NSIG-1) +#error "Not all signals can be encoded in sigs. Adapt its type!" +#endif bool os::Linux::libjsig_is_loaded = false; typedef struct sigaction *(*get_signal_t)(int); get_signal_t os::Linux::get_signal_action = NULL; @@ -4230,29 +4237,29 @@ bool os::Linux::chained_handler(int sig, siginfo_t* siginfo, void* context) { } struct sigaction* os::Linux::get_preinstalled_handler(int sig) { - if ((((unsigned int)1 << sig) & sigs) != 0) { + if ((((uint64_t)1 << (sig-1)) & sigs) != 0) { return &sigact[sig]; } return NULL; } void os::Linux::save_preinstalled_handler(int sig, struct sigaction& oldAct) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); sigact[sig] = oldAct; - sigs |= (unsigned int)1 << sig; + sigs |= (uint64_t)1 << (sig-1); } // for diagnostic -int os::Linux::sigflags[MAXSIGNUM]; +int sigflags[NSIG]; int os::Linux::get_our_sigflags(int sig) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); return sigflags[sig]; } void os::Linux::set_our_sigflags(int sig, int flags) { - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); - if (sig > 0 && sig < MAXSIGNUM) { + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); + if (sig > 0 && sig < NSIG) { sigflags[sig] = flags; } } @@ -4292,7 +4299,7 @@ void os::Linux::set_signal_handler(int sig, bool set_installed) { sigAct.sa_flags = SA_SIGINFO|SA_RESTART; } // Save flags, which are set by ours - assert(sig > 0 && sig < MAXSIGNUM, "vm signal out of expected range"); + assert(sig > 0 && sig < NSIG, "vm signal out of expected range"); sigflags[sig] = sigAct.sa_flags; int ret = sigaction(sig, &sigAct, &oldAct); diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp index b8104e75ebc..cbb649179fb 100644 --- a/hotspot/src/os/linux/vm/os_linux.hpp +++ b/hotspot/src/os/linux/vm/os_linux.hpp @@ -34,11 +34,6 @@ class Linux { friend class os; friend class TestReserveMemorySpecial; - // For signal-chaining -#define MAXSIGNUM 32 - static struct sigaction sigact[MAXSIGNUM]; // saved preinstalled sigactions - static unsigned int sigs; // mask of signals that have - // preinstalled signal handlers static bool libjsig_is_loaded; // libjsig that interposes sigaction(), // __sigaction(), signal() is loaded static struct sigaction *(*get_signal_action)(int); @@ -47,9 +42,6 @@ class Linux { static void check_signal_handler(int sig); - // For signal flags diagnostics - static int sigflags[MAXSIGNUM]; - static int (*_clock_gettime)(clockid_t, struct timespec *); static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *); static int (*_pthread_setname_np)(pthread_t, const char*); diff --git a/hotspot/src/os/solaris/vm/os_solaris.hpp b/hotspot/src/os/solaris/vm/os_solaris.hpp index 0f9b86d9ca8..9f5a450fb9a 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.hpp +++ b/hotspot/src/os/solaris/vm/os_solaris.hpp @@ -113,9 +113,6 @@ class Solaris { static void try_enable_extended_io(); - // For signal-chaining - static unsigned long sigs; // mask of signals that have - // preinstalled signal handlers static struct sigaction *(*get_signal_action)(int); static struct sigaction *get_preinstalled_handler(int); static int (*get_libjsig_version)(); From 6c10034f4bfb70e995db4c16b4e2c5391238ea74 Mon Sep 17 00:00:00 2001 From: Sangheon Kim Date: Thu, 12 Nov 2015 09:52:04 -0800 Subject: [PATCH 089/260] 8134631: G1DummyRegionsPerGC fires assert of assert(words <= filler_array_max_size()) failed: too big for a single object Change filler max value temporarily for G1DummyRegionsPerGC flag. Reviewed-by: tbenson, tschatzl --- hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index 5b779becfee..14846eaa4a6 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -2278,6 +2278,10 @@ void G1CollectedHeap::allocate_dummy_regions() { // And as a result the region we'll allocate will be humongous. guarantee(is_humongous(word_size), "sanity"); + // _filler_array_max_size is set to humongous object threshold + // but temporarily change it to use CollectedHeap::fill_with_object(). + SizeTFlagSetting fs(_filler_array_max_size, word_size); + for (uintx i = 0; i < G1DummyRegionsPerGC; ++i) { // Let's use the existing mechanism for the allocation HeapWord* dummy_obj = humongous_obj_allocate(word_size, From 7b6f3bbed85892d3078dc69717e6a5acf00d71d0 Mon Sep 17 00:00:00 2001 From: Peter Brunet Date: Thu, 12 Nov 2015 12:27:36 -0600 Subject: [PATCH 090/260] 8134116: Add more comprehensive fix and regression test for JDK-8133897 Use getTitleAt instead of Page.title field; add regression test Reviewed-by: alexsch, serb --- .../classes/javax/swing/JTabbedPane.java | 27 ++-- .../swing/JTabbedPane/8134116/Bug8134116.java | 130 ++++++++++++++++++ 2 files changed, 145 insertions(+), 12 deletions(-) create mode 100644 jdk/test/javax/swing/JTabbedPane/8134116/Bug8134116.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JTabbedPane.java b/jdk/src/java.desktop/share/classes/javax/swing/JTabbedPane.java index d50e660e413..de917a34e00 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JTabbedPane.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JTabbedPane.java @@ -2095,9 +2095,10 @@ public class JTabbedPane extends JComponent */ void setDisplayedMnemonicIndex(int mnemonicIndex) { if (this.mnemonicIndex != mnemonicIndex) { - if (mnemonicIndex != -1 && (title == null || + String t = getTitle(); + if (mnemonicIndex != -1 && (t == null || mnemonicIndex < 0 || - mnemonicIndex >= title.length())) { + mnemonicIndex >= t.length())) { throw new IllegalArgumentException( "Invalid mnemonic index: " + mnemonicIndex); } @@ -2116,7 +2117,7 @@ public class JTabbedPane extends JComponent void updateDisplayedMnemonicIndex() { setDisplayedMnemonicIndex( - SwingUtilities.findDisplayedMnemonicIndex(title, mnemonic)); + SwingUtilities.findDisplayedMnemonicIndex(getTitle(), mnemonic)); } ///////////////// @@ -2133,10 +2134,9 @@ public class JTabbedPane extends JComponent public String getAccessibleName() { if (accessibleName != null) { return accessibleName; - } else if (title != null) { - return title; + } else { + return getTitle(); } - return null; } public String getAccessibleDescription() { @@ -2156,7 +2156,7 @@ public class JTabbedPane extends JComponent AccessibleStateSet states; states = parent.getAccessibleContext().getAccessibleStateSet(); states.add(AccessibleState.SELECTABLE); - int i = parent.indexOfTab(title); + int i = parent.indexOfTabComponent(tabComponent); if (i == parent.getSelectedIndex()) { states.add(AccessibleState.SELECTED); } @@ -2164,7 +2164,7 @@ public class JTabbedPane extends JComponent } public int getAccessibleIndexInParent() { - return parent.indexOfTab(title); + return parent.indexOfTabComponent(tabComponent); } public int getAccessibleChildrenCount() { @@ -2272,10 +2272,8 @@ public class JTabbedPane extends JComponent } public Rectangle getBounds() { - int i = parent.indexOfTab(title); - // Check for no title. Even though that's a bug in the app we should - // inhibit an ArrayIndexOutOfBoundsException from getTabBounds. - return (i == -1) ? null : parent.getUI().getTabBounds(parent, i); + return parent.getUI(). + getTabBounds(parent, parent.indexOfTabComponent(tabComponent)); } public void setBounds(Rectangle r) { @@ -2343,6 +2341,11 @@ public class JTabbedPane extends JComponent return null; } } + + private String getTitle() { + return getTitleAt(parent.indexOfComponent(component)); + } + } /** diff --git a/jdk/test/javax/swing/JTabbedPane/8134116/Bug8134116.java b/jdk/test/javax/swing/JTabbedPane/8134116/Bug8134116.java new file mode 100644 index 00000000000..15aa9f43260 --- /dev/null +++ b/jdk/test/javax/swing/JTabbedPane/8134116/Bug8134116.java @@ -0,0 +1,130 @@ + +import java.awt.*; +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.List; +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleComponent; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; +import javax.swing.*; +import javax.swing.plaf.nimbus.NimbusLookAndFeel; + +/* + * @test + * @bug 8134116 + * @summary JTabbedPane$Page.getBounds throws IndexOutOfBoundsException + * @run main Bug8134116 + */ +public class Bug8134116 { + + public static void main(String args[]) throws Exception { + + try { + UIManager.setLookAndFeel(new NimbusLookAndFeel()); + } catch (Exception e) { + throw new RuntimeException(e); + } + + SwingUtilities.invokeAndWait(() -> { + JPanel panel0 = new JPanel(); + BadPane badPane = new BadPane(); + badPane.add("zero", panel0); + badPane.add("one", null); + JFrame frame = new JFrame(); + frame.add(badPane); + frame.setSize(300, 300); + frame.setVisible(true); + + AccessibleContext ac = badPane.getAccessibleContext(); + Accessible page0 = ac.getAccessibleChild(0); + if (page0 == null) { + // Not something being tested, but checking anyway + throw new RuntimeException("getAccessibleChild(0) is null"); + } + Accessible page1 = ac.getAccessibleChild(1); + if (page1 == null) { + // Not something being tested, but checking anyway + throw new RuntimeException("getAccessibleChild(1) is null"); + } + // page0 and page1 are a JTabbedPane.Page, a private inner class + // and is an AccessibleContext + // and implements Accessible and AccessibleComponent + AccessibleContext pac0 = page0.getAccessibleContext(); + AccessibleContext pac1 = page1.getAccessibleContext(); + + // the following would fail if JDK-8134116 fix not present + + // test Page.getBounds + // ensure no IndexOutOfBoundsException + pac0.getAccessibleComponent().getBounds(); + + // test Page.getAccessibleStateSet + // At this point page 0 is selected + AccessibleStateSet accSS0 = pac0.getAccessibleStateSet(); + if (!accSS0.contains(AccessibleState.SELECTED)) { + String msg = "Empty title -> AccessibleState.SELECTED not set"; + throw new RuntimeException(msg); + } + + // test Page.getAccessibleIndexInParent + if (pac0.getAccessibleIndexInParent() == -1) { + String msg = "Empty title -> negative AccessibleIndexInParent"; + throw new RuntimeException(msg); + } + + // test Page.getAccessibleName + String accName = pac0.getAccessibleName(); + if (!accName.equals("zero")) { + String msg = "Empty title -> empty AccessibleName"; + throw new RuntimeException(msg); + } + // test Page.getAccessibleName when component is null + accName = pac1.getAccessibleName(); + if (!accName.equals("one")) { + String msg = "AccessibleName of null panel not 'one'"; + throw new RuntimeException(msg); + } + + // test Page.setDisplayedMnemonicIndex + // Empty title -> IllegalArgumnetException + badPane.setDisplayedMnemonicIndexAt(0, 1); + + // test Page.updateDisplayedMnemonicIndex + badPane.setMnemonicAt(0, KeyEvent.VK_Z); + if (badPane.getDisplayedMnemonicIndexAt(0) == -1) { + String msg="Empty title -> getDisplayedMnemonicIndexAt failure"; + throw new RuntimeException(msg); + } + }); + } + + // The following is likely what is being done in Burp Suite + // https://portswigger.net/burp/ which fails in the same way, i.e. the + // pages List in JTabbedPane is not being managed properly and thus + // Page.title is "" for each page. The overridden insertTab manages titles + // in the subclass passing a "" title to the superclass JTabbedPane through + // its insertTab. Later an overridden getTitleAt returns the titles as + // managed by the subclass. + static class BadPane extends JTabbedPane { + private List titles; + + BadPane() { + titles = new ArrayList(1); + } + + @Override + public void insertTab( String title, Icon icon, Component component, + String tip, int index ) { + titles.add(index, title); + super.insertTab("", icon, component, tip, index); + } + + @Override + public String getTitleAt(int i) { + return titles.get(i); + } + } + +} From 4d9dfbeb1d43e3a5951064eda9aec926a846001a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 13 Nov 2015 09:12:06 +0100 Subject: [PATCH 091/260] 8138684: G1 decision about taking regions into the collection set is too aggressive Factor in expected waste and uncertainty of our guess in the decision whether to take another region into the collection set. Reviewed-by: mgerdin, jmasa --- hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index ee558818f83..2a5ec5e9366 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -467,8 +467,19 @@ bool G1CollectorPolicy::predict_will_fit(uint young_length, } size_t free_bytes = (base_free_regions - young_length) * HeapRegion::GrainBytes; - if ((2.0 /* magic */ * _predictor.sigma()) * bytes_to_copy > free_bytes) { - // end condition 3: out-of-space (conservatively!) + + // When copying, we will likely need more bytes free than is live in the region. + // Add some safety margin to factor in the confidence of our guess, and the + // natural expected waste. + // (100.0 / G1ConfidencePercent) is a scale factor that expresses the uncertainty + // of the calculation: the lower the confidence, the more headroom. + // (100 + TargetPLABWastePct) represents the increase in expected bytes during + // copying due to anticipated waste in the PLABs. + double safety_factor = (100.0 / G1ConfidencePercent) * (100 + TargetPLABWastePct) / 100.0; + size_t expected_bytes_to_copy = safety_factor * bytes_to_copy; + + if (expected_bytes_to_copy > free_bytes) { + // end condition 3: out-of-space return false; } From 6983acfb5f19b4873ec144ad9a38a27c2b0bb402 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Fri, 13 Nov 2015 09:28:53 +0100 Subject: [PATCH 092/260] 8139424: SIGSEGV, Problematic frame: # V [libjvm.so+0xd0c0cc] void InstanceKlass::oop_oop_iterate_oop_maps_specialized The crash was caused by a faulty eager humongous reclaim. The reason for reclaiming a live object was that the call to cleanupHRRS was done after dirtying cards and clearing the remembered sets for the humongous object. This could lead to one or many cards being missed. Reviewed-by: tbenson, kbarrett, tschatzl --- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 10 ++ hotspot/src/share/vm/gc/g1/g1RemSet.cpp | 1 - .../TestNoEagerReclaimOfHumongousRegions.java | 91 +++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 hotspot/test/gc/g1/TestNoEagerReclaimOfHumongousRegions.java diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index 5b779becfee..153c11a8a56 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -3561,6 +3561,9 @@ class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure { } } } + assert(hrrs.n_yielded() == r->rem_set()->occupied(), + "Remembered set hash maps out of sync, cur: " SIZE_FORMAT " entries, next: " SIZE_FORMAT " entries", + hrrs.n_yielded(), r->rem_set()->occupied()); r->rem_set()->clear_locked(); } assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty."); @@ -3848,6 +3851,13 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { evacuation_info.set_collectionset_regions(g1_policy()->cset_region_length()); + // Make sure the remembered sets are up to date. This needs to be + // done before register_humongous_regions_with_cset(), because the + // remembered sets are used there to choose eager reclaim candidates. + // If the remembered sets are not up to date we might miss some + // entries that need to be handled. + g1_rem_set()->cleanupHRRS(); + register_humongous_regions_with_cset(); assert(check_cset_fast_test(), "Inconsistency in the InCSetState table."); diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp index 87605532e51..8ea400204c4 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp @@ -307,7 +307,6 @@ size_t G1RemSet::oops_into_collection_set_do(G1ParPushHeapRSClosure* oc, } void G1RemSet::prepare_for_oops_into_collection_set_do() { - cleanupHRRS(); _g1->set_refine_cte_cl_concurrency(false); DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); dcqs.concatenate_logs(); diff --git a/hotspot/test/gc/g1/TestNoEagerReclaimOfHumongousRegions.java b/hotspot/test/gc/g1/TestNoEagerReclaimOfHumongousRegions.java new file mode 100644 index 00000000000..7d505d5ae5c --- /dev/null +++ b/hotspot/test/gc/g1/TestNoEagerReclaimOfHumongousRegions.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestNoEagerReclaimOfHumongousRegions + * @bug 8139424 + * @summary Test to check that a live humongous object is not eagerly reclaimed. This is a regression test for + * 8139424 and the test will crash if an eager reclaim occur. The test is not 100% deterministic and + * might pass even if there are problems in the code, but it will never crash unless there is a problem. + * @requires vm.gc=="G1" | vm.gc=="null" + * @key gc + * @library /testlibrary /test/lib + * @modules java.base/sun.misc + * @build TestNoEagerReclaimOfHumongousRegions + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+PrintGC -XX:+UseG1GC -XX:MaxTenuringThreshold=0 -XX:G1RSetSparseRegionEntries=32 -XX:G1HeapRegionSize=1m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+G1TraceEagerReclaimHumongousObjects TestNoEagerReclaimOfHumongousRegions + */ + +import java.util.LinkedList; + +import sun.hotspot.WhiteBox; + +public class TestNoEagerReclaimOfHumongousRegions { + // Helper class to keep reference to humongous byte[]. + static class LargeRef { + private byte[] _ref; + + LargeRef(byte[] ref) { + _ref = ref; + } + + byte[] ref() { return _ref; } + } + + static LargeRef humongous_reference_holder; + + public static void main(String[] args) throws InterruptedException{ + WhiteBox wb = WhiteBox.getWhiteBox(); + LinkedList garbageAndRefList = new LinkedList(); + // Creating a 1M large byte array. Since the test specifies the heap + // region size to be 1m this will be a humongous object. We then + // store a pointer to the array in the static object to keep it live + // during the whole test. + humongous_reference_holder = new LargeRef(new byte[1 * 1024 * 1024]); + + // Create some garbage and a reference to the humongous object each round. + for (int i = 0; i < 32; i++) { + garbageAndRefList.add(new byte[400*1000]); + garbageAndRefList.add(new LargeRef(humongous_reference_holder.ref())); + + // Promote to old, goal is to get rem-set entries for the humongous + // object from different regions. The test specifies MaxTenuringThreshold=0, + // this will make sure we get objects promoted to old at once. + wb.youngGC(); + } + // Clear the garbage and reference list. + garbageAndRefList.clear(); + + // Run a concurrent mark cycle to mark all references but the static one as dead. + wb.g1StartConcMarkCycle(); + while (wb.g1InConcurrentMark()) { + Thread.sleep(100); + } + + // Run a young collection to make sure humongous object still can't be eagerly reclaimed. + wb.youngGC(); + // Will crash/assert if humongous object has been reclaimed. + wb.fullGC(); + } +} From 396cd88e2f9ad2302b0ef20e87fe72d2e0c1fe8e Mon Sep 17 00:00:00 2001 From: Marcus Larsson Date: Fri, 13 Nov 2015 09:49:28 +0100 Subject: [PATCH 093/260] 8142482: Improve the support for prefix functions in unified logging Reviewed-by: brutisso, pliden --- hotspot/src/share/vm/logging/logPrefix.hpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/hotspot/src/share/vm/logging/logPrefix.hpp b/hotspot/src/share/vm/logging/logPrefix.hpp index 2bdd290c7e0..443f20a0a4d 100644 --- a/hotspot/src/share/vm/logging/logPrefix.hpp +++ b/hotspot/src/share/vm/logging/logPrefix.hpp @@ -27,12 +27,17 @@ #include "gc/shared/gcId.hpp" #include "logging/logTag.hpp" -// Prefixes prepend each log message for a specified tagset with the given prefix. -// A prefix consists of a format string and a value or callback. Prefixes are added -// after the decorations but before the log message. +// Prefixes prepend each log message for a specified tagset with a given prefix. +// These prefixes are written before the log message but after the log decorations. +// +// A prefix is defined as a function that takes a buffer (with some size) as argument. +// This function will be called for each log message, and should write the prefix +// to the given buffer. The function should return how many characters it wrote, +// which should never exceed the given size. // // List of prefixes for specific tags and/or tagsets. -// Syntax: LOG_PREFIX(, , LOG_TAGS()) +// Syntax: LOG_PREFIX(, LOG_TAGS()) +// Where the prefixer function matches the following signature: size_t (*)(char*, size_t) #define LOG_PREFIX_LIST // Currently unused/empty // The empty prefix, used when there's no prefix defined. @@ -44,12 +49,12 @@ struct LogPrefix : public AllStatic { } }; -#define LOG_PREFIX(fmt, fn, ...) \ +#define LOG_PREFIX(fn, ...) \ template <> struct LogPrefix<__VA_ARGS__> { \ static size_t prefix(char* buf, size_t len) { \ - int ret = jio_snprintf(buf, len, fmt, fn); \ - assert(ret >= 0, \ - "Failed to prefix log message using prefix ('%s', '%s'), log buffer too small?", fmt, #fn); \ + DEBUG_ONLY(buf[0] = '\0';) \ + size_t ret = fn(buf, len); \ + assert(ret == strlen(buf), "Length mismatch ret (" SIZE_FORMAT ") != buf length (" SIZE_FORMAT ")", ret, strlen(buf)); \ return ret; \ } \ }; From a00e011325156ae93660cb2ebbaba543fa545c33 Mon Sep 17 00:00:00 2001 From: Alexander Scherbatiy Date: Fri, 13 Nov 2015 05:02:26 -0800 Subject: [PATCH 094/260] 8073320: Windows HiDPI Graphics support Reviewed-by: flar, serb --- .../windows/native/launcher/java.manifest | 2 +- .../sun/java2d/opengl/CGLSurfaceData.java | 7 +- .../classes/sun/lwawt/LWWindowPeer.java | 4 +- .../sun/awt/image/BufImgSurfaceData.java | 101 +++++-- .../image/BufferedImageGraphicsConfig.java | 31 ++- .../sun/awt/image/SunVolatileImage.java | 13 +- .../classes/sun/awt/image/SurfaceManager.java | 24 +- .../sun/awt/image/VolatileSurfaceManager.java | 12 +- .../classes/sun/java2d/SunGraphics2D.java | 183 ++++++++----- .../sun/java2d/SunGraphicsEnvironment.java | 48 ++++ .../share/classes/sun/java2d/SurfaceData.java | 16 +- .../classes/sun/java2d/pipe/DrawImage.java | 7 +- .../classes/sun/awt/Win32GraphicsConfig.java | 6 +- .../classes/sun/awt/Win32GraphicsDevice.java | 40 +++ .../sun/awt/Win32GraphicsEnvironment.java | 18 ++ .../classes/sun/awt/windows/WWindowPeer.java | 9 +- .../sun/java2d/d3d/D3DSurfaceData.java | 38 ++- .../sun/java2d/opengl/WGLSurfaceData.java | 27 +- .../java2d/windows/GDIWindowSurfaceData.java | 22 +- .../native/libawt/windows/MouseInfo.cpp | 13 +- .../native/libawt/windows/awt_Choice.cpp | 9 +- .../native/libawt/windows/awt_Component.cpp | 63 ++++- .../native/libawt/windows/awt_Component.h | 5 + .../native/libawt/windows/awt_Font.cpp | 58 +++- .../native/libawt/windows/awt_Robot.cpp | 24 +- .../native/libawt/windows/awt_Toolkit.cpp | 14 +- .../windows/awt_Win32GraphicsConfig.cpp | 24 +- .../windows/awt_Win32GraphicsDevice.cpp | 168 ++++++++++++ .../libawt/windows/awt_Win32GraphicsDevice.h | 10 + .../native/libawt/windows/awt_Window.cpp | 93 +++++-- .../native/libawt/windows/awt_Window.h | 1 + .../HiDPIMouseClick/HiDPIRobotMouseClick.java | 87 ++++++ .../HiDPIRobotScreenCaptureTest.java | 115 ++++++++ .../HiDPIPropertiesWindowsTest.java | 139 ++++++++++ ...iResolutionDrawImageWithTransformTest.java | 248 ++++++++++++++++++ 35 files changed, 1498 insertions(+), 181 deletions(-) create mode 100644 jdk/test/java/awt/Robot/HiDPIMouseClick/HiDPIRobotMouseClick.java create mode 100644 jdk/test/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java create mode 100644 jdk/test/java/awt/hidpi/properties/HiDPIPropertiesWindowsTest.java create mode 100644 jdk/test/java/awt/image/MultiResolutionImage/MultiResolutionDrawImageWithTransformTest.java diff --git a/jdk/src/java.base/windows/native/launcher/java.manifest b/jdk/src/java.base/windows/native/launcher/java.manifest index eee6045f3f8..882d93c9a68 100644 --- a/jdk/src/java.base/windows/native/launcher/java.manifest +++ b/jdk/src/java.base/windows/native/launcher/java.manifest @@ -37,7 +37,7 @@ - true + true/PM diff --git a/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java b/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java index c260e60ad68..b59349f9cb8 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java +++ b/jdk/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java @@ -166,7 +166,12 @@ public abstract class CGLSurfaceData extends OGLSurfaceData { } @Override - public int getDefaultScale() { + public double getDefaultScaleX() { + return scale; + } + + @Override + public double getDefaultScaleY() { return scale; } diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java index 676726863f8..fabc2a21ba1 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java @@ -1156,7 +1156,9 @@ public class LWWindowPeer && !(dst instanceof NullSurfaceData) && !(src instanceof NullSurfaceData) && src.getSurfaceType().equals(dst.getSurfaceType()) - && src.getDefaultScale() == dst.getDefaultScale()) { + && src.getDefaultScaleX() == dst.getDefaultScaleX() + && src.getDefaultScaleY() == dst.getDefaultScaleY()) + { final Rectangle size = src.getBounds(); final Blit blit = Blit.locate(src.getSurfaceType(), CompositeType.Src, diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/BufImgSurfaceData.java b/jdk/src/java.desktop/share/classes/sun/awt/image/BufImgSurfaceData.java index ac26802b027..8d37a2d6a1d 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/BufImgSurfaceData.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/BufImgSurfaceData.java @@ -50,6 +50,8 @@ public class BufImgSurfaceData extends SurfaceData { BufferedImage bufImg; private BufferedImageGraphicsConfig graphicsConfig; RenderLoops solidloops; + private final double scaleX; + private final double scaleY; private static native void initIDs(Class ICM, Class ICMColorData); @@ -73,6 +75,12 @@ public class BufImgSurfaceData extends SurfaceData { } public static SurfaceData createData(BufferedImage bufImg) { + return createData(bufImg, 1, 1); + } + + public static SurfaceData createData(BufferedImage bufImg, + double scaleX, double scaleY) + { if (bufImg == null) { throw new NullPointerException("BufferedImage cannot be null"); } @@ -82,31 +90,36 @@ public class BufImgSurfaceData extends SurfaceData { // REMIND: Check the image type and pick an appropriate subclass switch (type) { case BufferedImage.TYPE_INT_BGR: - sData = createDataIC(bufImg, SurfaceType.IntBgr); + sData = createDataIC(bufImg, SurfaceType.IntBgr, scaleX, scaleY); break; case BufferedImage.TYPE_INT_RGB: - sData = createDataIC(bufImg, SurfaceType.IntRgb); + sData = createDataIC(bufImg, SurfaceType.IntRgb, scaleX, scaleY); break; case BufferedImage.TYPE_INT_ARGB: - sData = createDataIC(bufImg, SurfaceType.IntArgb); + sData = createDataIC(bufImg, SurfaceType.IntArgb, scaleX, scaleY); break; case BufferedImage.TYPE_INT_ARGB_PRE: - sData = createDataIC(bufImg, SurfaceType.IntArgbPre); + sData = createDataIC(bufImg, SurfaceType.IntArgbPre, scaleX, scaleY); break; case BufferedImage.TYPE_3BYTE_BGR: - sData = createDataBC(bufImg, SurfaceType.ThreeByteBgr, 2); + sData = createDataBC(bufImg, SurfaceType.ThreeByteBgr, 2, + scaleX, scaleY); break; case BufferedImage.TYPE_4BYTE_ABGR: - sData = createDataBC(bufImg, SurfaceType.FourByteAbgr, 3); + sData = createDataBC(bufImg, SurfaceType.FourByteAbgr, 3, + scaleX, scaleY); break; case BufferedImage.TYPE_4BYTE_ABGR_PRE: - sData = createDataBC(bufImg, SurfaceType.FourByteAbgrPre, 3); + sData = createDataBC(bufImg, SurfaceType.FourByteAbgrPre, 3, + scaleX, scaleY); break; case BufferedImage.TYPE_USHORT_565_RGB: - sData = createDataSC(bufImg, SurfaceType.Ushort565Rgb, null); + sData = createDataSC(bufImg, SurfaceType.Ushort565Rgb, null, + scaleX, scaleY); break; case BufferedImage.TYPE_USHORT_555_RGB: - sData = createDataSC(bufImg, SurfaceType.Ushort555Rgb, null); + sData = createDataSC(bufImg, SurfaceType.Ushort555Rgb, null, + scaleX, scaleY); break; case BufferedImage.TYPE_BYTE_INDEXED: { @@ -128,14 +141,16 @@ public class BufImgSurfaceData extends SurfaceData { default: throw new InternalError("Unrecognized transparency"); } - sData = createDataBC(bufImg, sType, 0); + sData = createDataBC(bufImg, sType, 0, scaleX, scaleY); } break; case BufferedImage.TYPE_BYTE_GRAY: - sData = createDataBC(bufImg, SurfaceType.ByteGray, 0); + sData = createDataBC(bufImg, SurfaceType.ByteGray, 0, + scaleX, scaleY); break; case BufferedImage.TYPE_USHORT_GRAY: - sData = createDataSC(bufImg, SurfaceType.UshortGray, null); + sData = createDataSC(bufImg, SurfaceType.UshortGray, null, + scaleX, scaleY); break; case BufferedImage.TYPE_BYTE_BINARY: { @@ -154,7 +169,7 @@ public class BufImgSurfaceData extends SurfaceData { default: throw new InternalError("Unrecognized pixel size"); } - sData = createDataBP(bufImg, sType); + sData = createDataBP(bufImg, sType, scaleX, scaleY); } break; case BufferedImage.TYPE_CUSTOM: @@ -191,7 +206,7 @@ public class BufImgSurfaceData extends SurfaceData { sType = SurfaceType.AnyDcm; } } - sData = createDataIC(bufImg, sType); + sData = createDataIC(bufImg, sType, scaleX, scaleY); break; } else if (raster instanceof ShortComponentRaster && raster.getNumDataElements() == 1 && @@ -233,11 +248,12 @@ public class BufImgSurfaceData extends SurfaceData { icm = null; } } - sData = createDataSC(bufImg, sType, icm); + sData = createDataSC(bufImg, sType, icm, scaleX, scaleY); break; } - sData = new BufImgSurfaceData(raster.getDataBuffer(), - bufImg, SurfaceType.Custom); + sData = new BufImgSurfaceData(raster.getDataBuffer(), bufImg, + SurfaceType.Custom, + scaleX, scaleY); } break; } @@ -250,11 +266,15 @@ public class BufImgSurfaceData extends SurfaceData { } public static SurfaceData createDataIC(BufferedImage bImg, - SurfaceType sType) { + SurfaceType sType, + double scaleX, + double scaleY) + { IntegerComponentRaster icRaster = (IntegerComponentRaster)bImg.getRaster(); BufImgSurfaceData bisd = - new BufImgSurfaceData(icRaster.getDataBuffer(), bImg, sType); + new BufImgSurfaceData(icRaster.getDataBuffer(), bImg, sType, + scaleX, scaleY); bisd.initRaster(icRaster.getDataStorage(), icRaster.getDataOffset(0) * 4, 0, icRaster.getWidth(), @@ -267,11 +287,14 @@ public class BufImgSurfaceData extends SurfaceData { public static SurfaceData createDataSC(BufferedImage bImg, SurfaceType sType, - IndexColorModel icm) { + IndexColorModel icm, + double scaleX, double scaleY) + { ShortComponentRaster scRaster = (ShortComponentRaster)bImg.getRaster(); BufImgSurfaceData bisd = - new BufImgSurfaceData(scRaster.getDataBuffer(), bImg, sType); + new BufImgSurfaceData(scRaster.getDataBuffer(), bImg, sType, + scaleX, scaleY); bisd.initRaster(scRaster.getDataStorage(), scRaster.getDataOffset(0) * 2, 0, scRaster.getWidth(), @@ -284,11 +307,14 @@ public class BufImgSurfaceData extends SurfaceData { public static SurfaceData createDataBC(BufferedImage bImg, SurfaceType sType, - int primaryBank) { + int primaryBank, + double scaleX, double scaleY) + { ByteComponentRaster bcRaster = (ByteComponentRaster)bImg.getRaster(); BufImgSurfaceData bisd = - new BufImgSurfaceData(bcRaster.getDataBuffer(), bImg, sType); + new BufImgSurfaceData(bcRaster.getDataBuffer(), bImg, sType, + scaleX, scaleY); ColorModel cm = bImg.getColorModel(); IndexColorModel icm = ((cm instanceof IndexColorModel) ? (IndexColorModel) cm @@ -304,11 +330,14 @@ public class BufImgSurfaceData extends SurfaceData { } public static SurfaceData createDataBP(BufferedImage bImg, - SurfaceType sType) { + SurfaceType sType, + double scaleX, double scaleY) + { BytePackedRaster bpRaster = (BytePackedRaster)bImg.getRaster(); BufImgSurfaceData bisd = - new BufImgSurfaceData(bpRaster.getDataBuffer(), bImg, sType); + new BufImgSurfaceData(bpRaster.getDataBuffer(), bImg, sType, + scaleX, scaleY); ColorModel cm = bImg.getColorModel(); IndexColorModel icm = ((cm instanceof IndexColorModel) ? (IndexColorModel) cm @@ -350,15 +379,22 @@ public class BufImgSurfaceData extends SurfaceData { IndexColorModel icm); public BufImgSurfaceData(DataBuffer db, - BufferedImage bufImg, SurfaceType sType) + BufferedImage bufImg, + SurfaceType sType, + double scaleX, + double scaleY) { super(SunWritableRaster.stealTrackable(db), sType, bufImg.getColorModel()); this.bufImg = bufImg; + this.scaleX = scaleX; + this.scaleY = scaleY; } protected BufImgSurfaceData(SurfaceType surfaceType, ColorModel cm) { super(surfaceType, cm); + this.scaleX = 1; + this.scaleY = 1; } public void initSolidLoops() { @@ -395,7 +431,8 @@ public class BufImgSurfaceData extends SurfaceData { public synchronized GraphicsConfiguration getDeviceConfiguration() { if (graphicsConfig == null) { - graphicsConfig = BufferedImageGraphicsConfig.getConfig(bufImg); + graphicsConfig = BufferedImageGraphicsConfig + .getConfig(bufImg, scaleX, scaleY); } return graphicsConfig; } @@ -418,6 +455,16 @@ public class BufImgSurfaceData extends SurfaceData { return bufImg; } + @Override + public double getDefaultScaleX() { + return scaleX; + } + + @Override + public double getDefaultScaleY() { + return scaleY; + } + public static final class ICMColorData { private long pData = 0L; diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/BufferedImageGraphicsConfig.java b/jdk/src/java.desktop/share/classes/sun/awt/image/BufferedImageGraphicsConfig.java index bddb83f6999..973eef76af2 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/BufferedImageGraphicsConfig.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/BufferedImageGraphicsConfig.java @@ -45,19 +45,32 @@ public class BufferedImageGraphicsConfig extends GraphicsConfiguration { private static final int numconfigs = BufferedImage.TYPE_BYTE_BINARY; - private static BufferedImageGraphicsConfig configs[] = + private static BufferedImageGraphicsConfig standardConfigs[] = + new BufferedImageGraphicsConfig[numconfigs]; + private static BufferedImageGraphicsConfig scaledConfigs[] = new BufferedImageGraphicsConfig[numconfigs]; public static BufferedImageGraphicsConfig getConfig(BufferedImage bImg) { + return getConfig(bImg, 1, 1); + } + + public static BufferedImageGraphicsConfig getConfig(BufferedImage bImg, + double scaleX, + double scaleY) + { BufferedImageGraphicsConfig ret; int type = bImg.getType(); + + BufferedImageGraphicsConfig[] configs = (scaleX == 1 && scaleY == 1) + ? standardConfigs : scaledConfigs; + if (type > 0 && type < numconfigs) { ret = configs[type]; - if (ret != null) { + if (ret != null && ret.scaleX == scaleX && ret.scaleY == scaleY) { return ret; } } - ret = new BufferedImageGraphicsConfig(bImg, null); + ret = new BufferedImageGraphicsConfig(bImg, null, scaleX, scaleY); if (type > 0 && type < numconfigs) { configs[type] = ret; } @@ -67,8 +80,16 @@ public class BufferedImageGraphicsConfig GraphicsDevice gd; ColorModel model; Raster raster; + private final double scaleX; + private final double scaleY; public BufferedImageGraphicsConfig(BufferedImage bufImg, Component comp) { + this(bufImg, comp, 1, 1); + } + + public BufferedImageGraphicsConfig(BufferedImage bufImg, Component comp, + double scaleX, double scaleY) + { if (comp == null) { this.gd = new BufferedImageDevice(this); } else { @@ -77,6 +98,8 @@ public class BufferedImageGraphicsConfig } this.model = bufImg.getColorModel(); this.raster = bufImg.getRaster().createCompatibleWritableRaster(1, 1); + this.scaleX = scaleX; + this.scaleY = scaleY; } /** @@ -138,7 +161,7 @@ public class BufferedImageGraphicsConfig * For image buffers, this Transform will be the Identity transform. */ public AffineTransform getDefaultTransform() { - return new AffineTransform(); + return AffineTransform.getScaleInstance(scaleX, scaleY); } /** diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java b/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java index 97e201124a5..00c8911f696 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java @@ -233,8 +233,17 @@ public class SunVolatileImage extends VolatileImage * or a backup surface. */ public BufferedImage getBackupImage() { - return graphicsConfig.createCompatibleImage(getWidth(), getHeight(), - getTransparency()); + return getBackupImage(1, 1); + } + + /** + * This method creates a BufferedImage intended for use as a "snapshot" + * or a backup surface with the given horizontal and vertical scale factors. + */ + public BufferedImage getBackupImage(double scaleX, double scaleY) { + int w = (int) Math.ceil(getWidth() * scaleX); + int h = (int) Math.ceil(getHeight() * scaleY); + return graphicsConfig.createCompatibleImage(w, h, getTransparency()); } public BufferedImage getSnapshot() { diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java b/jdk/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java index 1b2db0f867f..6cf567cd5e8 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java @@ -290,16 +290,30 @@ public abstract class SurfaceManager { } /** - * Returns a scale factor of the image. This is utility method, which - * fetches information from the SurfaceData of the image. + * Returns a horizontal scale factor of the image. This is utility method, + * which fetches information from the SurfaceData of the image. * - * @see SurfaceData#getDefaultScale + * @see SurfaceData#getDefaultScaleX */ - public static int getImageScale(final Image img) { + public static double getImageScaleX(final Image img) { if (!(img instanceof VolatileImage)) { return 1; } final SurfaceManager sm = getManager(img); - return sm.getPrimarySurfaceData().getDefaultScale(); + return sm.getPrimarySurfaceData().getDefaultScaleX(); + } + + /** + * Returns a vertical scale factor of the image. This is utility method, + * which fetches information from the SurfaceData of the image. + * + * @see SurfaceData#getDefaultScaleY + */ + public static double getImageScaleY(final Image img) { + if (!(img instanceof VolatileImage)) { + return 1; + } + final SurfaceManager sm = getManager(img); + return sm.getPrimarySurfaceData().getDefaultScaleY(); } } diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/VolatileSurfaceManager.java b/jdk/src/java.desktop/share/classes/sun/awt/image/VolatileSurfaceManager.java index e3aa4fdb990..ef2abf1caf7 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/VolatileSurfaceManager.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/VolatileSurfaceManager.java @@ -25,18 +25,16 @@ package sun.awt.image; -import java.awt.Color; import java.awt.Graphics; import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.awt.ImageCapabilities; +import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.VolatileImage; import sun.awt.DisplayChangedListener; -import sun.awt.image.SunVolatileImage; import sun.java2d.SunGraphicsEnvironment; import sun.java2d.SurfaceData; -import sun.java2d.loops.CompositeType; import static sun.java2d.pipe.hw.AccelSurface.*; /** @@ -260,12 +258,16 @@ public abstract class VolatileSurfaceManager */ protected SurfaceData getBackupSurface() { if (sdBackup == null) { - BufferedImage bImg = vImg.getBackupImage(); + GraphicsConfiguration gc = vImg.getGraphicsConfig(); + AffineTransform tx = gc.getDefaultTransform(); + double scaleX = tx.getScaleX(); + double scaleY = tx.getScaleY(); + BufferedImage bImg = vImg.getBackupImage(scaleX, scaleY); // Sabotage the acceleration capabilities of the BufImg surface SunWritableRaster.stealTrackable(bImg .getRaster() .getDataBuffer()).setUntrackable(); - sdBackup = BufImgSurfaceData.createData(bImg); + sdBackup = BufImgSurfaceData.createData(bImg, scaleX, scaleY); } return sdBackup; } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java index 7ed0e3a7033..c7facaf62b6 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java @@ -61,7 +61,6 @@ import java.awt.FontMetrics; import java.awt.Rectangle; import java.text.AttributedCharacterIterator; import java.awt.Font; -import java.awt.Point; import java.awt.image.ImageObserver; import java.awt.Transparency; import java.awt.font.GlyphVector; @@ -99,6 +98,7 @@ import java.awt.image.MultiResolutionImage; import static java.awt.geom.AffineTransform.TYPE_FLIP; import static java.awt.geom.AffineTransform.TYPE_MASK_SCALE; import static java.awt.geom.AffineTransform.TYPE_TRANSLATION; +import java.awt.image.VolatileImage; import sun.awt.image.MultiResolutionToolkitImage; import sun.awt.image.ToolkitImage; @@ -3086,30 +3086,50 @@ public final class SunGraphics2D } // end of text rendering methods - private boolean isHiDPIImage(final Image img) { - return (SurfaceManager.getImageScale(img) != 1) - || img instanceof MultiResolutionImage; - } + private Boolean drawHiDPIImage(Image img, + int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer, + AffineTransform xform) { - private boolean drawHiDPIImage(Image img, int dx1, int dy1, int dx2, - int dy2, int sx1, int sy1, int sx2, int sy2, - Color bgcolor, ImageObserver observer) { + if (img instanceof VolatileImage) { + final SurfaceData sd = SurfaceManager.getManager(img) + .getPrimarySurfaceData(); + final double scaleX = sd.getDefaultScaleX(); + final double scaleY = sd.getDefaultScaleY(); + if (scaleX == 1 && scaleY == 1) { + return null; + } + sx1 = Region.clipScale(sx1, scaleX); + sx2 = Region.clipScale(sx2, scaleX); + sy1 = Region.clipScale(sy1, scaleY); + sy2 = Region.clipScale(sy2, scaleY); - if (SurfaceManager.getImageScale(img) != 1) { // Volatile Image - final int scale = SurfaceManager.getImageScale(img); - sx1 = Region.clipScale(sx1, scale); - sx2 = Region.clipScale(sx2, scale); - sy1 = Region.clipScale(sy1, scale); - sy2 = Region.clipScale(sy2, scale); - } else if (img instanceof MultiResolutionImage) { + AffineTransform tx = null; + if (xform != null) { + tx = new AffineTransform(transform); + transform(xform); + } + boolean result = scaleImage(img, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, + bgcolor, observer); + if (tx != null) { + transform.setTransform(tx); + invalidateTransform(); + } + return result; + } else if (resolutionVariantHint != SunHints.INTVAL_RESOLUTION_VARIANT_BASE + && (img instanceof MultiResolutionImage)) { // get scaled destination image size int width = img.getWidth(observer); int height = img.getHeight(observer); - Image resolutionVariant = getResolutionVariant( - (MultiResolutionImage) img, width, height, - dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2); + MultiResolutionImage mrImage = (MultiResolutionImage) img; + Image resolutionVariant = getResolutionVariant(mrImage, width, height, + dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, + xform); if (resolutionVariant != img && resolutionVariant != null) { // recalculate source region for the resolution variant @@ -3123,8 +3143,8 @@ public final class SunGraphics2D if (0 < width && 0 < height && 0 < rvWidth && 0 < rvHeight) { - float widthScale = ((float) rvWidth) / width; - float heightScale = ((float) rvHeight) / height; + double widthScale = ((double) rvWidth) / width; + double heightScale = ((double) rvHeight) / height; sx1 = Region.clipScale(sx1, widthScale); sy1 = Region.clipScale(sy1, heightScale); @@ -3133,10 +3153,29 @@ public final class SunGraphics2D observer = rvObserver; img = resolutionVariant; + + if (xform != null) { + assert dx1 == 0 && dy1 == 0; + assert dx2 == img.getWidth(observer); + assert dy2 == img.getHeight(observer); + AffineTransform renderTX = new AffineTransform(xform); + renderTX.scale(1 / widthScale, 1 / heightScale); + return transformImage(img, renderTX, observer); + } + + return scaleImage(img, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, + bgcolor, observer); } } } + return null; + } + private boolean scaleImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer) + { try { return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer); @@ -3156,9 +3195,30 @@ public final class SunGraphics2D } } + private boolean transformImage(Image img, + AffineTransform xform, + ImageObserver observer) + { + try { + return imagepipe.transformImage(this, img, xform, observer); + } catch (InvalidPipeException e) { + try { + revalidateAll(); + return imagepipe.transformImage(this, img, xform, observer); + } catch (InvalidPipeException e2) { + // Still catching the exception; we are not yet ready to + // validate the surfaceData correctly. Fail for now and + // try again next time around. + return false; + } + } finally { + surfaceData.markDirty(); + } + } + private Image getResolutionVariant(MultiResolutionImage img, int srcWidth, int srcHeight, int dx1, int dy1, int dx2, int dy2, - int sx1, int sy1, int sx2, int sy2) { + int sx1, int sy1, int sx2, int sy2, AffineTransform xform) { if (srcWidth <= 0 || srcHeight <= 0) { return null; @@ -3171,7 +3231,16 @@ public final class SunGraphics2D return null; } - int type = transform.getType(); + AffineTransform tx; + + if (xform == null) { + tx = transform; + } else { + tx = new AffineTransform(transform); + tx.concatenate(xform); + } + + int type = tx.getType(); int dw = dx2 - dx1; int dh = dy2 - dy1; @@ -3198,13 +3267,13 @@ public final class SunGraphics2D destRegionWidth = dw; destRegionHeight = dh; } else if ((type & ~(TYPE_TRANSLATION | TYPE_FLIP | TYPE_MASK_SCALE)) == 0) { - destRegionWidth = dw * transform.getScaleX(); - destRegionHeight = dh * transform.getScaleY(); + destRegionWidth = dw * tx.getScaleX(); + destRegionHeight = dh * tx.getScaleY(); } else { destRegionWidth = dw * Math.hypot( - transform.getScaleX(), transform.getShearY()); + tx.getScaleX(), tx.getShearY()); destRegionHeight = dh * Math.hypot( - transform.getShearX(), transform.getScaleY()); + tx.getShearX(), tx.getScaleY()); } destImageWidth = Math.abs(srcWidth * destRegionWidth / sw); destImageHeight = Math.abs(srcHeight * destRegionHeight / sh); @@ -3277,9 +3346,11 @@ public final class SunGraphics2D final int imgW = img.getWidth(null); final int imgH = img.getHeight(null); - if (isHiDPIImage(img)) { - return drawHiDPIImage(img, x, y, x + width, y + height, 0, 0, imgW, - imgH, bg, observer); + Boolean hidpiImageDrawn = drawHiDPIImage(img, x, y, x + width, y + height, + 0, 0, imgW, imgH, bg, observer, + null); + if (hidpiImageDrawn != null) { + return hidpiImageDrawn; } if (width == imgW && height == imgH) { @@ -3323,11 +3394,13 @@ public final class SunGraphics2D return true; } - if (isHiDPIImage(img)) { - final int imgW = img.getWidth(null); - final int imgH = img.getHeight(null); - return drawHiDPIImage(img, x, y, x + imgW, y + imgH, 0, 0, imgW, - imgH, bg, observer); + final int imgW = img.getWidth(null); + final int imgH = img.getHeight(null); + Boolean hidpiImageDrawn = drawHiDPIImage(img, x, y, x + imgW, y + imgH, + 0, 0, imgW, imgH, bg, observer, + null); + if (hidpiImageDrawn != null) { + return hidpiImageDrawn; } try { @@ -3378,9 +3451,12 @@ public final class SunGraphics2D return true; } - if (isHiDPIImage(img)) { - return drawHiDPIImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, - bgcolor, observer); + Boolean hidpiImageDrawn = drawHiDPIImage(img, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, + bgcolor, observer, null); + + if (hidpiImageDrawn != null) { + return hidpiImageDrawn; } if (((sx2 - sx1) == (dx2 - dx1)) && @@ -3461,33 +3537,16 @@ public final class SunGraphics2D return drawImage(img, 0, 0, null, observer); } - if (isHiDPIImage(img)) { - final int w = img.getWidth(null); - final int h = img.getHeight(null); - final AffineTransform tx = new AffineTransform(transform); - transform(xform); - boolean result = drawHiDPIImage(img, 0, 0, w, h, 0, 0, w, h, null, - observer); - transform.setTransform(tx); - invalidateTransform(); - return result; + final int w = img.getWidth(null); + final int h = img.getHeight(null); + Boolean hidpiImageDrawn = drawHiDPIImage(img, 0, 0, w, h, 0, 0, w, h, + null, observer, xform); + + if (hidpiImageDrawn != null) { + return hidpiImageDrawn; } - try { - return imagepipe.transformImage(this, img, xform, observer); - } catch (InvalidPipeException e) { - try { - revalidateAll(); - return imagepipe.transformImage(this, img, xform, observer); - } catch (InvalidPipeException e2) { - // Still catching the exception; we are not yet ready to - // validate the surfaceData correctly. Fail for now and - // try again next time around. - return false; - } - } finally { - surfaceData.markDirty(); - } + return transformImage(img, xform, observer); } public void drawImage(BufferedImage bImg, diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java index 6a170c95d88..679f801d2e4 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java @@ -66,6 +66,8 @@ import sun.font.FontManager; import sun.font.FontManagerFactory; import sun.font.FontManagerForSGE; import sun.font.NativeFont; +import java.security.AccessController; +import sun.security.action.GetPropertyAction; /** * This is an implementation of a GraphicsEnvironment object for the @@ -80,6 +82,15 @@ public abstract class SunGraphicsEnvironment extends GraphicsEnvironment public static boolean isOpenSolaris; private static Font defaultFont; + private static final boolean uiScaleEnabled; + private static final double debugScale; + + static { + uiScaleEnabled = "true".equals(AccessController.doPrivileged( + new GetPropertyAction("sun.java2d.uiScale.enabled", "true"))); + debugScale = uiScaleEnabled ? getScaleFactor("sun.java2d.uiScale") : -1; + } + public SunGraphicsEnvironment() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { @@ -341,4 +352,41 @@ public abstract class SunGraphicsEnvironment extends GraphicsEnvironment public boolean isFlipStrategyPreferred(ComponentPeer peer) { return false; } + + public static boolean isUIScaleEnabled() { + return uiScaleEnabled; + } + + public static double getDebugScale() { + return debugScale; + } + + public static double getScaleFactor(String propertyName) { + + String scaleFactor = AccessController.doPrivileged( + new GetPropertyAction(propertyName, "-1")); + + if (scaleFactor == null || scaleFactor.equals("-1")) { + return -1; + } + + try { + double units = 1.0; + + if (scaleFactor.endsWith("x")) { + scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 1); + } else if (scaleFactor.endsWith("dpi")) { + units = 96; + scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 3); + } else if (scaleFactor.endsWith("%")) { + units = 100; + scaleFactor = scaleFactor.substring(0, scaleFactor.length() - 1); + } + + double scale = Double.parseDouble(scaleFactor); + return scale <= 0 ? -1 : scale / units; + } catch (NumberFormatException ignored) { + return -1; + } + } } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/SurfaceData.java b/jdk/src/java.desktop/share/classes/sun/java2d/SurfaceData.java index 81794b5d490..8250d09a43d 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/SurfaceData.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/SurfaceData.java @@ -1059,12 +1059,22 @@ public abstract class SurfaceData public abstract Object getDestination(); /** - * Returns default scale factor of the destination surface. Scale factor - * describes the mapping between virtual and physical coordinates of the + * Returns default horizontal scale factor of the destination surface. Scale + * factor describes the mapping between virtual and physical coordinates of the * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be * doubled for physical pixels. */ - public int getDefaultScale() { + public double getDefaultScaleX() { + return 1; + } + + /** + * Returns default vertical scale factor of the destination surface. Scale + * factor describes the mapping between virtual and physical coordinates of the + * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be + * doubled for physical pixels. + */ + public double getDefaultScaleY() { return 1; } } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/DrawImage.java b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/DrawImage.java index cfa130b8199..a7e181e9d2a 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/DrawImage.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/DrawImage.java @@ -736,9 +736,10 @@ public class DrawImage implements DrawImagePipe atfm.scale(m00, m11); atfm.translate(srcX-sx1, srcY-sy1); - final int scale = SurfaceManager.getImageScale(img); - final int imgW = img.getWidth(null) * scale; - final int imgH = img.getHeight(null) * scale; + final double scaleX = SurfaceManager.getImageScaleX(img); + final double scaleY = SurfaceManager.getImageScaleY(img); + final int imgW = (int) Math.ceil(img.getWidth(null) * scaleX); + final int imgH = (int) Math.ceil(img.getHeight(null) * scaleY); srcW += srcX; srcH += srcY; // Make sure we are not out of bounds diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsConfig.java b/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsConfig.java index 2ec0d1b1944..4773934e39e 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsConfig.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsConfig.java @@ -106,7 +106,7 @@ public class Win32GraphicsConfig extends GraphicsConfiguration /** * Return the graphics device associated with this configuration. */ - public GraphicsDevice getDevice() { + public Win32GraphicsDevice getDevice() { return screen; } @@ -182,7 +182,9 @@ public class Win32GraphicsConfig extends GraphicsConfiguration * For image buffers, this Transform will be the Identity transform. */ public AffineTransform getDefaultTransform() { - return new AffineTransform(); + double scaleX = screen.getDefaultScaleX(); + double scaleY = screen.getDefaultScaleY(); + return AffineTransform.getScaleInstance(scaleX, scaleY); } /** diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java b/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java index 85c1453b196..e7548a6f169 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java @@ -37,13 +37,19 @@ import java.awt.Window; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; +import java.awt.geom.Point2D; import java.awt.image.ColorModel; import java.util.ArrayList; import java.util.Vector; import java.awt.peer.WindowPeer; +import java.security.AccessController; import sun.awt.windows.WWindowPeer; +import sun.java2d.SunGraphicsEnvironment; import sun.java2d.opengl.WGLGraphicsConfig; import sun.java2d.windows.WindowsFlags; +import sun.security.action.GetPropertyAction; +import static sun.awt.Win32GraphicsEnvironment.debugScaleX; +import static sun.awt.Win32GraphicsEnvironment.debugScaleY; /** * This is an implementation of a GraphicsDevice object for a single @@ -81,6 +87,9 @@ public class Win32GraphicsDevice extends GraphicsDevice implements // activation/deactivation listener for the full-screen window private WindowListener fsWindowListener; + private float scaleX; + private float scaleY; + static { // 4455041 - Even when ddraw is disabled, ddraw.dll is loaded when @@ -97,6 +106,10 @@ public class Win32GraphicsDevice extends GraphicsDevice implements private static native void initIDs(); native void initDevice(int screen); + native void initNativeScale(int screen); + native void setNativeScale(int screen, float scaleX, float scaleY); + native float getNativeScaleX(int screen); + native float getNativeScaleY(int screen); public Win32GraphicsDevice(int screennum) { this.screen = screennum; @@ -109,6 +122,7 @@ public class Win32GraphicsDevice extends GraphicsDevice implements valid = true; initDevice(screennum); + initScaleFactors(); } /** @@ -128,6 +142,31 @@ public class Win32GraphicsDevice extends GraphicsDevice implements return screen; } + public float getDefaultScaleX() { + return scaleX; + } + + public float getDefaultScaleY() { + return scaleY; + } + + private void initScaleFactors() { + if (SunGraphicsEnvironment.isUIScaleEnabled()) { + if (debugScaleX > 0 && debugScaleY > 0) { + scaleX = debugScaleX; + scaleY = debugScaleY; + setNativeScale(screen, scaleX, scaleY); + } else { + initNativeScale(screen); + scaleX = getNativeScaleX(screen); + scaleY = getNativeScaleY(screen); + } + } else { + scaleX = 1; + scaleY = 1; + } + } + /** * Returns whether this is a valid devicie. Device can become * invalid as a result of device removal event. @@ -486,6 +525,7 @@ public class Win32GraphicsDevice extends GraphicsDevice implements configs = null; // pass on to all top-level windows on this display topLevels.notifyListeners(); + initScaleFactors(); } /** diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java b/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java index d98f2afeb5b..464541c2b53 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java @@ -51,6 +51,9 @@ import sun.java2d.windows.WindowsFlags; public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment { + static final float debugScaleX; + static final float debugScaleY; + static { // Ensure awt is loaded already. Also, this forces static init // of WToolkit and Toolkit, which we depend upon @@ -61,6 +64,21 @@ public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment { // Install correct surface manager factory. SurfaceManagerFactory.setInstance(new WindowsSurfaceManagerFactory()); + + double sx = -1; + double sy = -1; + if (isUIScaleEnabled()) { + sx = getScaleFactor("sun.java2d.win.uiScaleX"); + sy = getScaleFactor("sun.java2d.win.uiScaleY"); + if (sx <= 0 || sy <= 0) { + double s = getDebugScale(); + sx = s; + sy = s; + } + } + + debugScaleX = (float) sx; + debugScaleY = (float) sy; } /** diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java index 5605ecd04bd..12885ad2a61 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java @@ -294,6 +294,12 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer, synchronized native void reshapeFrame(int x, int y, int width, int height); + native Dimension getNativeWindowSize(); + + public Dimension getScaledWindowSize() { + return getNativeWindowSize(); + } + public boolean requestWindowFocus(CausedFocusEvent.Cause cause) { if (!focusAllowedFor()) { return false; @@ -490,8 +496,7 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer, } // get current GD - Win32GraphicsDevice oldDev = (Win32GraphicsDevice)winGraphicsConfig - .getDevice(); + Win32GraphicsDevice oldDev = winGraphicsConfig.getDevice(); Win32GraphicsDevice newDev; GraphicsDevice devs[] = GraphicsEnvironment diff --git a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java index 4ff6f4c54c5..c6b25970951 100644 --- a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java +++ b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java @@ -63,9 +63,12 @@ import static sun.java2d.d3d.D3DContext.D3DContextCaps.*; import static sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.*; import sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType; import java.awt.BufferCapabilities.FlipContents; +import java.awt.Dimension; import java.awt.Window; +import java.awt.geom.AffineTransform; import sun.awt.SunToolkit; import sun.awt.image.SunVolatileImage; +import sun.awt.windows.WWindowPeer; import sun.java2d.ScreenUpdateManager; import sun.java2d.StateTracker; import sun.java2d.SurfaceDataProxy; @@ -162,6 +165,8 @@ public class D3DSurfaceData extends SurfaceData implements AccelSurface { private int type; private int width, height; + private final double scaleX; + private final double scaleY; // these fields are set from the native code when the surface is // initialized private int nativeWidth, nativeHeight; @@ -218,16 +223,29 @@ public class D3DSurfaceData extends SurfaceData implements AccelSurface { { super(getCustomSurfaceType(type), cm); this.graphicsDevice = gc.getD3DDevice(); + this.scaleX = type == TEXTURE ? 1 : graphicsDevice.getDefaultScaleX(); + this.scaleY = type == TEXTURE ? 1 : graphicsDevice.getDefaultScaleY(); this.peer = peer; this.type = type; - this.width = width; - this.height = height; + + if (scaleX == 1 && scaleY == 1) { + this.width = width; + this.height = height; + } else if (peer instanceof WWindowPeer) { + Dimension scaledSize = ((WWindowPeer) peer).getScaledWindowSize(); + this.width = scaledSize.width; + this.height = scaledSize.height; + } else { + this.width = (int) Math.ceil(width * scaleX); + this.height = (int) Math.ceil(height * scaleY); + } + this.offscreenImage = image; this.backBuffersNum = numBackBuffers; this.swapEffect = swapEffect; this.syncType = vSyncType; - initOps(graphicsDevice.getScreen(), width, height); + initOps(graphicsDevice.getScreen(), this.width, this.height); if (type == WINDOW) { // we put the surface into the "lost" // state; it will be restored by the D3DScreenUpdateManager @@ -240,6 +258,16 @@ public class D3DSurfaceData extends SurfaceData implements AccelSurface { setBlitProxyKey(gc.getProxyKey()); } + @Override + public double getDefaultScaleX() { + return scaleX; + } + + @Override + public double getDefaultScaleY() { + return scaleY; + } + @Override public SurfaceDataProxy makeProxyFor(SurfaceData srcData) { return D3DSurfaceDataProxy. @@ -777,8 +805,12 @@ public class D3DSurfaceData extends SurfaceData implements AccelSurface { public Rectangle getBounds() { if (type == FLIP_BACKBUFFER || type == WINDOW) { + double scaleX = getDefaultScaleX(); + double scaleY = getDefaultScaleY(); Rectangle r = peer.getBounds(); r.x = r.y = 0; + r.width = (int) Math.ceil(r.width * scaleX); + r.height = (int) Math.ceil(r.height * scaleY); return r; } else { return new Rectangle(width, height); diff --git a/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java b/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java index b415cf8f36d..d27b7d1cc6b 100644 --- a/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java +++ b/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java @@ -31,8 +31,10 @@ import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.Rectangle; +import java.awt.geom.AffineTransform; import java.awt.image.ColorModel; import sun.awt.SunToolkit; +import sun.awt.Win32GraphicsDevice; import sun.awt.windows.WComponentPeer; import sun.java2d.SurfaceData; @@ -40,6 +42,8 @@ public abstract class WGLSurfaceData extends OGLSurfaceData { protected WComponentPeer peer; private WGLGraphicsConfig graphicsConfig; + protected double scaleX = 1; + protected double scaleY = 1; private native void initOps(long pConfigInfo, WComponentPeer peer, long hwnd); @@ -50,6 +54,9 @@ public abstract class WGLSurfaceData extends OGLSurfaceData { super(gc, cm, type); this.peer = peer; this.graphicsConfig = gc; + Win32GraphicsDevice device = gc.getDevice(); + this.scaleX = type == TEXTURE ? 1 : device.getDefaultScaleX(); + this.scaleY = type == TEXTURE ? 1 : device.getDefaultScaleY(); long pConfigInfo = gc.getNativeConfigInfo(); long hwnd = peer != null ? peer.getHWnd() : 0L; @@ -57,6 +64,16 @@ public abstract class WGLSurfaceData extends OGLSurfaceData { initOps(pConfigInfo, peer, hwnd); } + @Override + public double getDefaultScaleX() { + return scaleX; + } + + @Override + public double getDefaultScaleY() { + return scaleY; + } + public GraphicsConfiguration getDeviceConfiguration() { return graphicsConfig; } @@ -148,6 +165,8 @@ public abstract class WGLSurfaceData extends OGLSurfaceData { public Rectangle getBounds() { Rectangle r = peer.getBounds(); r.x = r.y = 0; + r.width = (int) Math.ceil(r.width * scaleX); + r.height = (int) Math.ceil(r.height * scaleY); return r; } @@ -208,11 +227,11 @@ public abstract class WGLSurfaceData extends OGLSurfaceData { { super(peer, gc, cm, type); - this.width = width; - this.height = height; + this.width = (int) Math.ceil(width * scaleX); + this.height = (int) Math.ceil(height * scaleY); offscreenImage = image; - initSurface(width, height); + initSurface(this.width, this.height); } public SurfaceData getReplacement() { @@ -222,6 +241,8 @@ public abstract class WGLSurfaceData extends OGLSurfaceData { public Rectangle getBounds() { if (type == FLIP_BACKBUFFER) { Rectangle r = peer.getBounds(); + r.width = (int) Math.ceil(r.width * scaleX); + r.height = (int) Math.ceil(r.height * scaleY); r.x = r.y = 0; return r; } else { diff --git a/jdk/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java b/jdk/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java index 04ba1464001..2ba2b11aa59 100644 --- a/jdk/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java +++ b/jdk/src/java.desktop/windows/classes/sun/java2d/windows/GDIWindowSurfaceData.java @@ -28,6 +28,7 @@ package sun.java2d.windows; import java.awt.Rectangle; import java.awt.GraphicsConfiguration; import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; import java.awt.image.ColorModel; import java.awt.image.ComponentColorModel; import java.awt.image.DirectColorModel; @@ -77,6 +78,9 @@ public class GDIWindowSurfaceData extends SurfaceData { private static native void initIDs(Class xorComp); + private final double scaleX; + private final double scaleY; + static { initIDs(XORComposite.class); if (WindowsFlags.isGdiBlitEnabled()) { @@ -265,13 +269,23 @@ public class GDIWindowSurfaceData extends SurfaceData { this.graphicsConfig = (Win32GraphicsConfig) peer.getGraphicsConfiguration(); this.solidloops = graphicsConfig.getSolidLoops(sType); - - Win32GraphicsDevice gd = - (Win32GraphicsDevice)graphicsConfig.getDevice(); + Win32GraphicsDevice gd = graphicsConfig.getDevice(); + scaleX = gd.getDefaultScaleX(); + scaleY = gd.getDefaultScaleY(); initOps(peer, depth, rMask, gMask, bMask, gd.getScreen()); setBlitProxyKey(graphicsConfig.getProxyKey()); } + @Override + public double getDefaultScaleX() { + return scaleX; + } + + @Override + public double getDefaultScaleY() { + return scaleY; + } + /** * {@inheritDoc} * @@ -288,6 +302,8 @@ public class GDIWindowSurfaceData extends SurfaceData { public Rectangle getBounds() { Rectangle r = peer.getBounds(); r.x = r.y = 0; + r.width = (int) Math.ceil(r.width * scaleX); + r.height = (int) Math.ceil(r.height * scaleY); return r; } diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp index b109f28ded8..e43f6ea3f5f 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp @@ -94,12 +94,21 @@ Java_sun_awt_DefaultMouseInfoPeer_fillPointWithCoords(JNIEnv *env, jclass cls, j pointClass = (jclass)env->NewGlobalRef(pointClassLocal); env->DeleteLocalRef(pointClassLocal); } + + int screen = AwtWin32GraphicsDevice::GetDefaultDeviceIndex(); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice *device = devices->GetDevice(screen); + xID = env->GetFieldID(pointClass, "x", "I"); CHECK_NULL_RETURN(xID, (jint)0); yID = env->GetFieldID(pointClass, "y", "I"); CHECK_NULL_RETURN(yID, (jint)0); - env->SetIntField(point, xID, pt.x); - env->SetIntField(point, yID, pt.y); + + int x = (device == NULL) ? pt.x : device->ScaleDownX(pt.x); + int y = (device == NULL) ? pt.y : device->ScaleDownY(pt.y); + + env->SetIntField(point, xID, x); + env->SetIntField(point, yID, y); // Always return 0 on Windows: we assume there's always a // virtual screen device used. diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Choice.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Choice.cpp index 6a597475148..be1c41e840f 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Choice.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Choice.cpp @@ -206,9 +206,10 @@ int AwtChoice::GetDropDownHeight() int itemHeight =(int)::SendMessage(GetHWnd(), CB_GETITEMHEIGHT, (UINT)0,0); int numItemsToShow = (int)::SendMessage(GetHWnd(), CB_GETCOUNT, 0,0); numItemsToShow = min(MINIMUM_NUMBER_OF_VISIBLE_ITEMS, numItemsToShow); + // drop-down height snaps to nearest line, so add a // fudge factor of 1/2 line to ensure last line shows - return itemHeight*numItemsToShow + itemHeight/2; + return ScaleDownY(itemHeight * numItemsToShow + itemHeight / 2); } // get the height of the field portion of the combobox @@ -221,7 +222,7 @@ int AwtChoice::GetFieldHeight() // Win 4.x (3d edge) vs 3.x (1 pixel line) borderHeight = ::GetSystemMetrics(SM_CYEDGE); fieldHeight += borderHeight*2; - return fieldHeight; + return ScaleDownY(fieldHeight); } // gets the total height of the combobox, including drop down @@ -325,8 +326,8 @@ void AwtChoice::Reshape(int x, int y, int w, int h) * Fix: Set the Choice to its actual size in the component. */ ::GetClientRect(GetHWnd(), &rc); - env->SetIntField(target, AwtComponent::widthID, (jint)rc.right); - env->SetIntField(target, AwtComponent::heightID, (jint)rc.bottom); + env->SetIntField(target, AwtComponent::widthID, ScaleDownX(rc.right)); + env->SetIntField(target, AwtComponent::heightID, ScaleDownY(rc.bottom)); env->DeleteLocalRef(target); env->DeleteLocalRef(parent); diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp index b234ec0221b..a36db45b72f 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp @@ -963,6 +963,12 @@ void AwtComponent::Reshape(int x, int y, int w, int h) ::MapWindowPoints(HWND_DESKTOP, ::GetParent(GetHWnd()), (LPPOINT)&rc, 2); DTRACE_PRINTLN4("AwtComponent::Reshape from %d, %d, %d, %d", rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top); #endif + + x = ScaleUpX(x); + y = ScaleUpY(y); + w = ScaleUpX(w); + h = ScaleUpY(h); + AwtWindow* container = GetContainer(); AwtComponent* parent = GetParent(); if (container != NULL && container == parent) { @@ -2212,8 +2218,11 @@ void AwtComponent::PaintUpdateRgn(const RECT *insets) } for(i = 0; i < 2; i++) { if (un[i] != 0) { - DoCallback("handleExpose", "(IIII)V", un[i]->left, un[i]->top, - un[i]->right-un[i]->left, un[i]->bottom-un[i]->top); + DoCallback("handleExpose", "(IIII)V", + ScaleDownX(un[i]->left), + ScaleDownY(un[i]->top), + ScaleDownX(un[i]->right - un[i]->left), + ScaleDownY(un[i]->bottom - un[i]->top)); } } delete [] buffer; @@ -4608,6 +4617,34 @@ void AwtComponent::FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha) } } +int AwtComponent::ScaleUpX(int x) { + int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd()); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice* device = devices->GetDevice(screen); + return device == NULL ? x : device->ScaleUpX(x); +} + +int AwtComponent::ScaleUpY(int y) { + int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd()); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice* device = devices->GetDevice(screen); + return device == NULL ? y : device->ScaleUpY(y); +} + +int AwtComponent::ScaleDownX(int x) { + int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd()); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice* device = devices->GetDevice(screen); + return device == NULL ? x : device->ScaleDownX(x); +} + +int AwtComponent::ScaleDownY(int y) { + int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd()); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice* device = devices->GetDevice(screen); + return device == NULL ? y : device->ScaleDownY(y); +} + jintArray AwtComponent::CreatePrintedPixels(SIZE &loc, SIZE &size, int alpha) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); @@ -4901,8 +4938,9 @@ void AwtComponent::SendMouseEvent(jint id, jlong when, jint x, jint y, jobject mouseEvent = env->NewObject(mouseEventCls, mouseEventConst, target, id, when, modifiers, - x+insets.left, y+insets.top, - xAbs, yAbs, + ScaleDownX(x + insets.left), + ScaleDownY(y + insets.top), + ScaleDownX(xAbs), ScaleDownY(yAbs), clickCount, popupTrigger, button); if (safe_ExceptionOccurred(env)) { @@ -4969,8 +5007,10 @@ AwtComponent::SendMouseWheelEvent(jint id, jlong when, jint x, jint y, mouseWheelEventConst, target, id, when, modifiers, - x+insets.left, y+insets.top, - xAbs, yAbs, + ScaleDownX(x + insets.left), + ScaleDownY(y + insets.top), + ScaleDownX(xAbs), + ScaleDownY(yAbs), clickCount, popupTrigger, scrollType, scrollAmount, roundedWheelRotation, preciseWheelRotation); @@ -5476,7 +5516,8 @@ jobject AwtComponent::_GetLocationOnScreen(void *param) RECT rect; VERIFY(::GetWindowRect(p->GetHWnd(),&rect)); result = JNU_NewObjectByName(env, "java/awt/Point", "(II)V", - rect.left, rect.top); + p->ScaleDownX(rect.left), + p->ScaleDownY(rect.top)); } ret: env->DeleteGlobalRef(self); @@ -7064,6 +7105,11 @@ void AwtComponent::VerifyState() target = parent; } + x = ScaleUpX(x); + y = ScaleUpY(y); + width = ScaleUpX(width); + height = ScaleUpY(height); + // Test whether component's bounds match the native window's RECT rect; VERIFY(::GetWindowRect(GetHWnd(), &rect)); @@ -7256,5 +7302,4 @@ void ReleaseDCList(HWND hwnd, DCList &list) { removedDCs = removedDCs->next; delete tmpDCList; } -} - +} \ No newline at end of file diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h index f09b41f5b54..83c6d8b8a4e 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h @@ -746,6 +746,11 @@ protected: virtual void FillBackground(HDC hMemoryDC, SIZE &size); virtual void FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha); + int ScaleUpX(int x); + int ScaleUpY(int y); + int ScaleDownX(int x); + int ScaleDownY(int y); + private: /* A bitmask keeps the button's numbers as MK_LBUTTON, MK_MBUTTON, MK_RBUTTON * which are allowed to diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp index 163283f0ef7..a8d7fd1bcb6 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Font.cpp @@ -398,6 +398,38 @@ static void strip_tail(wchar_t* text, wchar_t* tail) { // strips tail and any po } +static int ScaleUpX(float x) { + int deviceIndex = AwtWin32GraphicsDevice::DeviceIndexForWindow( + ::GetDesktopWindow()); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice *device = devices->GetDevice(deviceIndex); + return device == NULL ? x : device->ScaleUpX(x); +} + +static int ScaleUpY(int y) { + int deviceIndex = AwtWin32GraphicsDevice::DeviceIndexForWindow( + ::GetDesktopWindow()); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice *device = devices->GetDevice(deviceIndex); + return device == NULL ? y : device->ScaleUpY(y); +} + +static int ScaleDownX(int x) { + int deviceIndex = AwtWin32GraphicsDevice::DeviceIndexForWindow( + ::GetDesktopWindow()); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice *device = devices->GetDevice(deviceIndex); + return device == NULL ? x : device->ScaleDownX(x); +} + +static int ScaleDownY(int y) { + int deviceIndex = AwtWin32GraphicsDevice::DeviceIndexForWindow( + ::GetDesktopWindow()); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice *device = devices->GetDevice(deviceIndex); + return device == NULL ? y : device->ScaleDownY(y); +} + static HFONT CreateHFont_sub(LPCWSTR name, int style, int height, int angle=0, float awScale=1.0f) { @@ -424,7 +456,7 @@ static HFONT CreateHFont_sub(LPCWSTR name, int style, int height, logFont.lfUnderline = 0;//(style & java_awt_Font_UNDERLINE) != 0; // Get point size - logFont.lfHeight = -height; + logFont.lfHeight = ScaleUpY(-height); // Set font name WCHAR tmpname[80]; @@ -451,7 +483,7 @@ static HFONT CreateHFont_sub(LPCWSTR name, int style, int height, VERIFY(::DeleteObject(oldFont)); } avgWidth = tm.tmAveCharWidth; - logFont.lfWidth = (LONG)((fabs)(avgWidth*awScale)); + logFont.lfWidth = (LONG) ScaleUpX((fabs) (avgWidth * awScale)); hFont = ::CreateFontIndirect(&logFont); DASSERT(hFont != NULL); VERIFY(::ReleaseDC(0, hDC)); @@ -535,19 +567,20 @@ void AwtFont::LoadMetrics(JNIEnv *env, jobject fontMetrics) int ascent = metrics.tmAscent; int descent = metrics.tmDescent; int leading = metrics.tmExternalLeading; - env->SetIntField(fontMetrics, AwtFont::ascentID, ascent); - env->SetIntField(fontMetrics, AwtFont::descentID, descent); - env->SetIntField(fontMetrics, AwtFont::leadingID, leading); - env->SetIntField(fontMetrics, AwtFont::heightID, metrics.tmAscent + - metrics.tmDescent + leading); - env->SetIntField(fontMetrics, AwtFont::maxAscentID, ascent); - env->SetIntField(fontMetrics, AwtFont::maxDescentID, descent); + + env->SetIntField(fontMetrics, AwtFont::ascentID, ScaleDownY(ascent)); + env->SetIntField(fontMetrics, AwtFont::descentID, ScaleDownY(descent)); + env->SetIntField(fontMetrics, AwtFont::leadingID, ScaleDownX(leading)); + env->SetIntField(fontMetrics, AwtFont::heightID, + ScaleDownY(metrics.tmAscent + metrics.tmDescent + leading)); + env->SetIntField(fontMetrics, AwtFont::maxAscentID, ScaleDownY(ascent)); + env->SetIntField(fontMetrics, AwtFont::maxDescentID, ScaleDownY(descent)); int maxHeight = ascent + descent + leading; - env->SetIntField(fontMetrics, AwtFont::maxHeightID, maxHeight); + env->SetIntField(fontMetrics, AwtFont::maxHeightID, ScaleDownY(maxHeight)); int maxAdvance = metrics.tmMaxCharWidth; - env->SetIntField(fontMetrics, AwtFont::maxAdvanceID, maxAdvance); + env->SetIntField(fontMetrics, AwtFont::maxAdvanceID, ScaleDownX(maxAdvance)); awtFont->m_overhang = metrics.tmOverhang; @@ -818,6 +851,7 @@ Java_sun_awt_windows_WFontMetrics_stringWidth(JNIEnv *env, jobject self, jobject font = env->GetObjectField(self, AwtFont::fontID); long ret = AwtFont::getMFStringWidth(hDC, font, str); + ret = ScaleDownX(ret); VERIFY(::ReleaseDC(0, hDC)); return ret; @@ -924,7 +958,7 @@ Java_sun_awt_windows_WFontMetrics_bytesWidth(JNIEnv *env, jobject self, } env->ReleasePrimitiveArrayCritical(str, pStrBody, 0); - return result; + return ScaleDownX(result); CATCH_BAD_ALLOC_RET(0); } diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp index 7739af44b7a..0528148e23e 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp @@ -80,6 +80,13 @@ void AwtRobot::MouseMove( jint x, jint y) (PVOID)newSpeed, SPIF_SENDCHANGE); + int primaryIndex = AwtWin32GraphicsDevice::GetDefaultDeviceIndex(); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice *device = devices->GetDevice(primaryIndex); + + x = (device == NULL) ? x : device->ScaleUpX(x); + y = (device == NULL) ? y : device->ScaleUpY(y); + POINT curPos; ::GetCursorPos(&curPos); x -= curPos.x; @@ -217,11 +224,24 @@ void AwtRobot::GetRGBPixels(jint x, jint y, jint width, jint height, jintArray p AwtWin32GraphicsDevice::SelectPalette(hdcMem, primaryIndex); AwtWin32GraphicsDevice::RealizePalette(hdcMem, primaryIndex); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice *device = devices->GetDevice(primaryIndex); + int sWidth = (device == NULL) ? width : device->ScaleUpX(width); + int sHeight = (device == NULL) ? height : device->ScaleUpY(height); + // copy screen image to offscreen bitmap // CAPTUREBLT flag is required to capture WS_EX_LAYERED windows' contents // correctly on Win2K/XP - VERIFY(::BitBlt(hdcMem, 0, 0, width, height, hdcScreen, x, y, - SRCCOPY|CAPTUREBLT) != 0); + if (width == sWidth && height == sHeight) { + VERIFY(::BitBlt(hdcMem, 0, 0, width, height, hdcScreen, x, y, + SRCCOPY | CAPTUREBLT) != 0); + } else { + int sX = (device == NULL) ? x : device->ScaleUpX(x); + int sY = (device == NULL) ? y : device->ScaleUpY(y); + VERIFY(::StretchBlt(hdcMem, 0, 0, width, height, + hdcScreen, sX, sY, sWidth, sHeight, + SRCCOPY | CAPTUREBLT) != 0); + } static const int BITS_PER_PIXEL = 32; static const int BYTES_PER_PIXEL = BITS_PER_PIXEL/8; diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp index dcb4ea71f8d..3dedda934c9 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp @@ -2355,8 +2355,13 @@ Java_sun_awt_windows_WToolkit_getScreenWidth(JNIEnv *env, jobject self) { TRY; - return ::GetSystemMetrics(SM_CXSCREEN); + int width = ::GetSystemMetrics(SM_CXSCREEN); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice *device = devices->GetDevice( + AwtWin32GraphicsDevice::GetDefaultDeviceIndex()); + + return (device == NULL) ? width : device->ScaleDownX(width); CATCH_BAD_ALLOC_RET(0); } @@ -2370,7 +2375,12 @@ Java_sun_awt_windows_WToolkit_getScreenHeight(JNIEnv *env, jobject self) { TRY; - return ::GetSystemMetrics(SM_CYSCREEN); + int height = ::GetSystemMetrics(SM_CYSCREEN); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice *device = devices->GetDevice( + AwtWin32GraphicsDevice::GetDefaultDeviceIndex()); + + return (device == NULL) ? height : device->ScaleDownY(height); CATCH_BAD_ALLOC_RET(0); } diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsConfig.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsConfig.cpp index 918ed08b626..7d13fbe2d87 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsConfig.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsConfig.cpp @@ -95,19 +95,31 @@ JNIEXPORT jobject JNICALL mid = env->GetMethodID(clazz, "", "(IIII)V"); if (mid != 0) { RECT rRW = {0, 0, 0, 0}; + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice *device = devices->GetDevice(screen); + if (TRUE == MonitorBounds(AwtWin32GraphicsDevice::GetMonitor(screen), &rRW)) { - bounds = env->NewObject(clazz, mid, - rRW.left, rRW.top, - rRW.right - rRW.left, - rRW.bottom - rRW.top); + + int x = (device == NULL) ? rRW.left : device->ScaleDownX(rRW.left); + int y = (device == NULL) ? rRW.top : device->ScaleDownY(rRW.top); + int w = (device == NULL) ? rRW.right - rRW.left + : device->ScaleDownX(rRW.right - rRW.left); + int h = (device == NULL) ? rRW.bottom - rRW.top + : device->ScaleDownY(rRW.bottom - rRW.top); + + bounds = env->NewObject(clazz, mid, x, y, w, h); + } else { // 4910760 - don't return a null bounds, return the bounds of the // primary screen + int w = ::GetSystemMetrics(SM_CXSCREEN); + int h = ::GetSystemMetrics(SM_CYSCREEN); + bounds = env->NewObject(clazz, mid, 0, 0, - ::GetSystemMetrics(SM_CXSCREEN), - ::GetSystemMetrics(SM_CYSCREEN)); + device == NULL ? w : device->ScaleDownX(w), + device == NULL ? h : device->ScaleDownY(h)); } if (safe_ExceptionOccurred(env)) { return 0; diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp index 825a69c8c42..95f1b73e930 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp @@ -49,6 +49,12 @@ #include "dither.h" #include "img_util_md.h" #include "Devices.h" +#include +#pragma comment(lib, "d2d1") + +#ifndef MDT_Effective_DPI +#define MDT_Effective_DPI 0 +#endif uns_ordered_dither_array img_oda_alpha; @@ -74,6 +80,8 @@ AwtWin32GraphicsDevice::AwtWin32GraphicsDevice(int screen, { this->screen = screen; this->devicesArray = arr; + this->scaleX = 1; + this->scaleY = 1; javaDevice = NULL; colorData = new ImgColorData; colorData->grayscale = GS_NOTGRAY; @@ -616,6 +624,104 @@ void AwtWin32GraphicsDevice::SetJavaDevice(JNIEnv *env, jobject objPtr) javaDevice = env->NewWeakGlobalRef(objPtr); } +/** + * Sets horizontal and vertical scale factors + */ +void AwtWin32GraphicsDevice::SetScale(float sx, float sy) +{ + scaleX = sx; + scaleY = sy; +} + +int AwtWin32GraphicsDevice::ScaleUpX(int x) +{ + return (int)ceil(x * scaleX); +} + +int AwtWin32GraphicsDevice::ScaleUpY(int y) +{ + return (int)ceil(y * scaleY); +} + +int AwtWin32GraphicsDevice::ScaleDownX(int x) +{ + return (int)ceil(x / scaleX); +} + +int AwtWin32GraphicsDevice::ScaleDownY(int y) +{ + return (int)ceil(y / scaleY); +} + +void AwtWin32GraphicsDevice::InitDesktopScales() +{ + unsigned x = 0; + unsigned y = 0; + float dpiX = -1.0f; + float dpiY = -1.0f; + + // for debug purposes + static float scale = -2.0f; + if (scale == -2) { + scale = -1; + char *uiScale = getenv("J2D_UISCALE"); + if (uiScale != NULL) { + scale = (float)strtod(uiScale, NULL); + if (errno == ERANGE || scale <= 0) { + scale = -1; + } + } + } + + if (scale > 0) { + SetScale(scale, scale); + return; + } + + typedef HRESULT(WINAPI GetDpiForMonitorFunc)(HMONITOR, int, UINT*, UINT*); + static HMODULE hLibSHCoreDll = NULL; + static GetDpiForMonitorFunc *lpGetDpiForMonitor = NULL; + + if (hLibSHCoreDll == NULL) { + hLibSHCoreDll = JDK_LoadSystemLibrary("shcore.dll"); + if (hLibSHCoreDll != NULL) { + lpGetDpiForMonitor = (GetDpiForMonitorFunc*)GetProcAddress( + hLibSHCoreDll, "GetDpiForMonitor"); + } + } + + if (lpGetDpiForMonitor != NULL) { + HRESULT hResult = lpGetDpiForMonitor(GetMonitor(), + MDT_Effective_DPI, &x, &y); + if (hResult == S_OK) { + dpiX = static_cast(x); + dpiY = static_cast(y); + } + } else { + ID2D1Factory* m_pDirect2dFactory; + HRESULT res = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, + &m_pDirect2dFactory); + if (res == S_OK) { + m_pDirect2dFactory->GetDesktopDpi(&dpiX, &dpiY); + m_pDirect2dFactory->Release(); + } + } + + if (dpiX > 0 && dpiY > 0) { + SetScale(dpiX / 96, dpiY / 96); + } +} + +float AwtWin32GraphicsDevice::GetScaleX() +{ + return scaleX; +} + +float AwtWin32GraphicsDevice::GetScaleY() +{ + return scaleY; +} + /** * Disables offscreen acceleration for this device. This * sets a flag in the java object that is used to determine @@ -1304,3 +1410,65 @@ JNIEXPORT void JNICALL Devices::InstanceAccess devices; devices->GetDevice(screen)->SetJavaDevice(env, thisPtr); } + +/* + * Class: sun_awt_Win32GraphicsDevice + * Method: setNativeScale + * Signature: (I,F,F)V + */ +JNIEXPORT void JNICALL + Java_sun_awt_Win32GraphicsDevice_setNativeScale + (JNIEnv *env, jobject thisPtr, jint screen, jfloat scaleX, jfloat scaleY) +{ + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice *device = devices->GetDevice(screen); + + if (device != NULL ) { + device->SetScale(scaleX, scaleY); + } +} + +/* + * Class: sun_awt_Win32GraphicsDevice + * Method: getNativeScaleX + * Signature: (I)F + */ +JNIEXPORT jfloat JNICALL + Java_sun_awt_Win32GraphicsDevice_getNativeScaleX + (JNIEnv *env, jobject thisPtr, jint screen) +{ + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice *device = devices->GetDevice(screen); + return (device == NULL) ? 1 : device->GetScaleX(); +} + +/* + * Class: sun_awt_Win32GraphicsDevice + * Method: getNativeScaleY + * Signature: (I)F + */ +JNIEXPORT jfloat JNICALL + Java_sun_awt_Win32GraphicsDevice_getNativeScaleY + (JNIEnv *env, jobject thisPtr, jint screen) +{ + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice *device = devices->GetDevice(screen); + return (device == NULL) ? 1 : device->GetScaleY(); +} + +/* +* Class: sun_awt_Win32GraphicsDevice +* Method: initNativeScale +* Signature: (I)V; +*/ +JNIEXPORT void JNICALL +Java_sun_awt_Win32GraphicsDevice_initNativeScale +(JNIEnv *env, jobject thisPtr, jint screen) +{ + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice *device = devices->GetDevice(screen); + + if (device != NULL) { + device->InitDesktopScales(); + } +} \ No newline at end of file diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h index e09b4fc794c..250df7af727 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h @@ -66,6 +66,14 @@ public: void Release(); void DisableOffscreenAcceleration(); void Invalidate(JNIEnv *env); + void InitDesktopScales(); + void SetScale(float scaleX, float scaleY); + float GetScaleX(); + float GetScaleY(); + int ScaleUpX(int x); + int ScaleUpY(int y); + int ScaleDownX(int x); + int ScaleDownY(int y); static int DeviceIndexForWindow(HWND hWnd); static jobject GetColorModel(JNIEnv *env, jboolean dynamic, @@ -107,6 +115,8 @@ private: LPMONITORINFO pMonitorInfo; jobject javaDevice; Devices *devicesArray; + float scaleX; + float scaleY; static HDC MakeDCFromMonitor(HMONITOR); }; diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp index 4a3bcfcad7d..096bf4f9f14 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp @@ -1407,19 +1407,19 @@ BOOL AwtWindow::UpdateInsets(jobject insets) /* Get insets into our peer directly */ jobject peerInsets = (env)->GetObjectField(peer, AwtPanel::insets_ID); DASSERT(!safe_ExceptionOccurred(env)); + if (peerInsets != NULL) { // may have been called during creation - (env)->SetIntField(peerInsets, AwtInsets::topID, m_insets.top); - (env)->SetIntField(peerInsets, AwtInsets::bottomID, - m_insets.bottom); - (env)->SetIntField(peerInsets, AwtInsets::leftID, m_insets.left); - (env)->SetIntField(peerInsets, AwtInsets::rightID, m_insets.right); + (env)->SetIntField(peerInsets, AwtInsets::topID, ScaleDownY(m_insets.top)); + (env)->SetIntField(peerInsets, AwtInsets::bottomID, ScaleDownY(m_insets.bottom)); + (env)->SetIntField(peerInsets, AwtInsets::leftID, ScaleDownX(m_insets.left)); + (env)->SetIntField(peerInsets, AwtInsets::rightID, ScaleDownX(m_insets.right)); } /* Get insets into the Inset object (if any) that was passed */ if (insets != NULL) { - (env)->SetIntField(insets, AwtInsets::topID, m_insets.top); - (env)->SetIntField(insets, AwtInsets::bottomID, m_insets.bottom); - (env)->SetIntField(insets, AwtInsets::leftID, m_insets.left); - (env)->SetIntField(insets, AwtInsets::rightID, m_insets.right); + (env)->SetIntField(insets, AwtInsets::topID, ScaleDownY(m_insets.top)); + (env)->SetIntField(insets, AwtInsets::bottomID, ScaleDownY(m_insets.bottom)); + (env)->SetIntField(insets, AwtInsets::leftID, ScaleDownX(m_insets.left)); + (env)->SetIntField(insets, AwtInsets::rightID, ScaleDownX(m_insets.right)); } env->DeleteLocalRef(peerInsets); @@ -1735,10 +1735,10 @@ MsgRouting AwtWindow::WmMove(int x, int y) RECT rect; ::GetWindowRect(GetHWnd(), &rect); - (env)->SetIntField(target, AwtComponent::xID, rect.left); - (env)->SetIntField(target, AwtComponent::yID, rect.top); - (env)->SetIntField(peer, AwtWindow::sysXID, rect.left); - (env)->SetIntField(peer, AwtWindow::sysYID, rect.top); + (env)->SetIntField(target, AwtComponent::xID, ScaleDownX(rect.left)); + (env)->SetIntField(target, AwtComponent::yID, ScaleDownY(rect.top)); + (env)->SetIntField(peer, AwtWindow::sysXID, ScaleDownX(rect.left)); + (env)->SetIntField(peer, AwtWindow::sysYID, ScaleDownY(rect.top)); SendComponentEvent(java_awt_event_ComponentEvent_COMPONENT_MOVED); env->DeleteLocalRef(target); @@ -1803,12 +1803,12 @@ MsgRouting AwtWindow::WmSize(UINT type, int w, int h) int newWidth = w + m_insets.left + m_insets.right; int newHeight = h + m_insets.top + m_insets.bottom; - (env)->SetIntField(target, AwtComponent::widthID, newWidth); - (env)->SetIntField(target, AwtComponent::heightID, newHeight); + (env)->SetIntField(target, AwtComponent::widthID, ScaleDownX(newWidth)); + (env)->SetIntField(target, AwtComponent::heightID, ScaleDownY(newHeight)); jobject peer = GetPeer(env); - (env)->SetIntField(peer, AwtWindow::sysWID, newWidth); - (env)->SetIntField(peer, AwtWindow::sysHID, newHeight); + (env)->SetIntField(peer, AwtWindow::sysWID, ScaleDownX(newWidth)); + (env)->SetIntField(peer, AwtWindow::sysHID, ScaleDownY(newHeight)); if (!AwtWindow::IsResizing()) { WindowResized(); @@ -3072,6 +3072,25 @@ void AwtWindow::_SetFullScreenExclusiveModeState(void *param) delete data; } +void AwtWindow::_GetNativeWindowSize(void* param) { + + JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); + + SizeStruct *ss = (SizeStruct *)param; + jobject self = ss->window; + AwtWindow *window = NULL; + PDATA pData; + JNI_CHECK_PEER_RETURN(self); + window = (AwtWindow *)pData; + + RECT rc; + ::GetWindowRect(window->GetHWnd(), &rc); + ss->w = rc.right - rc.left; + ss->h = rc.bottom - rc.top; + + env->DeleteGlobalRef(self); +} + extern "C" { /* @@ -3301,6 +3320,46 @@ Java_sun_awt_windows_WWindowPeer_reshapeFrame(JNIEnv *env, jobject self, CATCH_BAD_ALLOC; } +/* + * Class: sun_awt_windows_WWindowPeer +* Method: getNativeWindowSize +* Signature: ()Ljava/awt/Dimension; +*/ +JNIEXPORT jobject JNICALL Java_sun_awt_windows_WWindowPeer_getNativeWindowSize +(JNIEnv *env, jobject self) { + + jobject res = NULL; + TRY; + SizeStruct *ss = new SizeStruct; + ss->window = env->NewGlobalRef(self); + + AwtToolkit::GetInstance().SyncCall(AwtWindow::_GetNativeWindowSize, ss); + + int w = ss->w; + int h = ss->h; + + delete ss; + // global ref is deleted in _GetNativeWindowSize() + + static jmethodID dimMID = NULL; + static jclass dimClassID = NULL; + if (dimClassID == NULL) { + jclass dimClassIDLocal = env->FindClass("java/awt/Dimension"); + CHECK_NULL_RETURN(dimClassIDLocal, NULL); + dimClassID = (jclass)env->NewGlobalRef(dimClassIDLocal); + env->DeleteLocalRef(dimClassIDLocal); + } + + if (dimMID == NULL) { + dimMID = env->GetMethodID(dimClassID, "", "(II)V"); + CHECK_NULL_RETURN(dimMID, NULL); + } + + return env->NewObject(dimClassID, dimMID, w, h); + + CATCH_BAD_ALLOC_RET(NULL); +} + /* * Class: sun_awt_windows_WWindowPeer * Method: getSysMinWidth diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.h b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.h index 1a92a672c9f..c1ce65be4e4 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.h +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Window.h @@ -241,6 +241,7 @@ public: static void _UpdateWindow(void* param); static void _RepositionSecurityWarning(void* param); static void _SetFullScreenExclusiveModeState(void* param); + static void _GetNativeWindowSize(void* param); inline static BOOL IsResizing() { return sm_resizing; diff --git a/jdk/test/java/awt/Robot/HiDPIMouseClick/HiDPIRobotMouseClick.java b/jdk/test/java/awt/Robot/HiDPIMouseClick/HiDPIRobotMouseClick.java new file mode 100644 index 00000000000..b551b155450 --- /dev/null +++ b/jdk/test/java/awt/Robot/HiDPIMouseClick/HiDPIRobotMouseClick.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Frame; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.UIManager; + +/* @test + * @bug 8073320 + * @summary Windows HiDPI support + * @author Alexander Scherbatiy + * @requires (os.family == "windows") + * @run main/othervm -Dsun.java2d.win.uiScale=2 HiDPIRobotMouseClick + */ +public class HiDPIRobotMouseClick { + + private static volatile int mouseX; + private static volatile int mouseY; + + public static void main(String[] args) throws Exception { + + try { + UIManager.setLookAndFeel( + "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + } catch (Exception e) { + return; + } + + Frame frame = new Frame(); + frame.setBounds(30, 20, 400, 300); + frame.setUndecorated(true); + + frame.addMouseListener(new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + mouseX = e.getXOnScreen(); + mouseY = e.getYOnScreen(); + } + }); + + frame.setVisible(true); + + Robot robot = new Robot(); + robot.waitForIdle(); + Thread.sleep(200); + + Rectangle rect = frame.getBounds(); + rect.setLocation(frame.getLocationOnScreen()); + + int x = (int) rect.getCenterX(); + int y = (int) rect.getCenterY(); + + robot.mouseMove(x, y); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.waitForIdle(); + + if (x != mouseX || y != mouseY) { + throw new RuntimeException("Wrong mouse click point!"); + } + } +} diff --git a/jdk/test/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java b/jdk/test/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java new file mode 100644 index 00000000000..03a346abff1 --- /dev/null +++ b/jdk/test/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import javax.swing.UIManager; + +/* @test + * @bug 8073320 + * @summary Windows HiDPI support + * @author Alexander Scherbatiy + * @requires (os.family == "windows") + * @run main/othervm -Dsun.java2d.win.uiScaleX=3 -Dsun.java2d.win.uiScaleY=2 + * HiDPIRobotScreenCaptureTest + */ +public class HiDPIRobotScreenCaptureTest { + + private static final Color[] COLORS = { + Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED}; + + public static void main(String[] args) throws Exception { + + try { + UIManager.setLookAndFeel( + "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + } catch (Exception e) { + return; + } + + Frame frame = new Frame(); + frame.setBounds(40, 30, 400, 300); + frame.setUndecorated(true); + + Panel panel = new Panel(new BorderLayout()); + Canvas canvas = new Canvas() { + @Override + public void paint(Graphics g) { + super.paint(g); + int w = getWidth(); + int h = getHeight(); + g.setColor(COLORS[0]); + g.fillRect(0, 0, w / 2, h / 2); + g.setColor(COLORS[1]); + g.fillRect(w / 2, 0, w / 2, h / 2); + g.setColor(COLORS[2]); + g.fillRect(0, h / 2, w / 2, h / 2); + g.setColor(COLORS[3]); + g.fillRect(w / 2, h / 2, w / 2, h / 2); + } + }; + + panel.add(canvas); + frame.add(panel); + frame.setVisible(true); + Robot robot = new Robot(); + robot.waitForIdle(); + Thread.sleep(200); + + Rectangle rect = canvas.getBounds(); + rect.setLocation(canvas.getLocationOnScreen()); + + BufferedImage image = robot.createScreenCapture(rect); + frame.dispose(); + + int w = image.getWidth(); + int h = image.getHeight(); + + if (w != frame.getWidth() || h != frame.getHeight()) { + throw new RuntimeException("Wrong image size!"); + } + + if (image.getRGB(w / 4, h / 4) != COLORS[0].getRGB()) { + throw new RuntimeException("Wrong image color!"); + } + + if (image.getRGB(3 * w / 4, h / 4) != COLORS[1].getRGB()) { + throw new RuntimeException("Wrong image color!"); + } + + if (image.getRGB(w / 4, 3 * h / 4) != COLORS[2].getRGB()) { + throw new RuntimeException("Wrong image color!"); + } + + if (image.getRGB(3 * w / 4, 3 * h / 4) != COLORS[3].getRGB()) { + throw new RuntimeException("Wrong image color!"); + } + } +} \ No newline at end of file diff --git a/jdk/test/java/awt/hidpi/properties/HiDPIPropertiesWindowsTest.java b/jdk/test/java/awt/hidpi/properties/HiDPIPropertiesWindowsTest.java new file mode 100644 index 00000000000..56aa9a3b92c --- /dev/null +++ b/jdk/test/java/awt/hidpi/properties/HiDPIPropertiesWindowsTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import javax.swing.UIManager; + +/* @test + * @bug 8073320 + * @summary Windows HiDPI support + * @author Alexander Scherbatiy + * @requires (os.family == "windows") + * @run main/othervm -Dsun.java2d.uiScale.enabled=false + * -Dsun.java2d.win.uiScaleX=3 -Dsun.java2d.win.uiScaleY=2 + * HiDPIPropertiesWindowsTest UISCALE_DISABLED + * @run main/othervm -Dsun.java2d.uiScale.enabled=false + * -Dsun.java2d.uiScale=3 + * HiDPIPropertiesWindowsTest UISCALE_DISABLED + * @run main/othervm -Dsun.java2d.uiScale.enabled=false + * -Dsun.java2d.uiScale=3 + * -Dsun.java2d.win.uiScaleX=5 -Dsun.java2d.win.uiScaleY=6 + * HiDPIPropertiesWindowsTest UISCALE_DISABLED + * @run main/othervm -Dsun.java2d.uiScale.enabled=true + * -Dsun.java2d.uiScale=3 + * HiDPIPropertiesWindowsTest UISCALE_3 + * @run main/othervm -Dsun.java2d.uiScale.enabled=true + * -Dsun.java2d.uiScale=4 + * -Dsun.java2d.win.uiScaleX=2 -Dsun.java2d.win.uiScaleY=3 + * HiDPIPropertiesWindowsTest UISCALE_2X3 + * @run main/othervm -Dsun.java2d.uiScale.enabled=true + * -Dsun.java2d.win.uiScaleX=3 -Dsun.java2d.win.uiScaleY=2 + * HiDPIPropertiesWindowsTest UISCALE_3X2 + * @run main/othervm -Dsun.java2d.uiScale=4 + * HiDPIPropertiesWindowsTest UISCALE_4 + * @run main/othervm -Dsun.java2d.uiScale=4 + * -Dsun.java2d.win.uiScaleX=2 -Dsun.java2d.win.uiScaleY=3 + * HiDPIPropertiesWindowsTest UISCALE_2X3 + * @run main/othervm -Dsun.java2d.win.uiScaleX=4 -Dsun.java2d.win.uiScaleY=5 + * HiDPIPropertiesWindowsTest UISCALE_4X5 + * @run main/othervm -Dsun.java2d.uiScale=3 + * -Dsun.java2d.win.uiScaleX=0 -Dsun.java2d.win.uiScaleY=0 + * HiDPIPropertiesWindowsTest UISCALE_3 + * @run main/othervm -Dsun.java2d.uiScale=4 + * -Dsun.java2d.win.uiScaleX=-7 -Dsun.java2d.win.uiScaleY=-8 + * HiDPIPropertiesWindowsTest UISCALE_4 + * @run main/othervm -Dsun.java2d.uiScale=4x + * HiDPIPropertiesWindowsTest UISCALE_4 + * @run main/othervm -Dsun.java2d.win.uiScaleX=4x -Dsun.java2d.win.uiScaleY=5x + * HiDPIPropertiesWindowsTest UISCALE_4X5 + * @run main/othervm -Dsun.java2d.uiScale=384dpi + * HiDPIPropertiesWindowsTest UISCALE_4 + * @run main/othervm -Dsun.java2d.uiScale=300% + * HiDPIPropertiesWindowsTest UISCALE_3 + * @run main/othervm -Dsun.java2d.win.uiScaleX=400% -Dsun.java2d.win.uiScaleY=500% + * HiDPIPropertiesWindowsTest UISCALE_4X5 + * @run main/othervm -Dsun.java2d.win.uiScaleX=288dpi -Dsun.java2d.win.uiScaleY=192dpi + * HiDPIPropertiesWindowsTest UISCALE_3X2 + * @run main/othervm -Dsun.java2d.win.uiScaleX=200% -Dsun.java2d.win.uiScaleY=288dpi + * HiDPIPropertiesWindowsTest UISCALE_2X3 + */ +public class HiDPIPropertiesWindowsTest { + + public static void main(String[] args) throws Exception { + + try { + UIManager.setLookAndFeel( + "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + } catch (Exception e) { + return; + } + + String testCase = args[0]; + switch (testCase) { + case "UISCALE_DISABLED": + testScale(1.0, 1.0); + break; + case "UISCALE_3": + testScale(3.0, 3.0); + break; + case "UISCALE_4": + testScale(4.0, 4.0); + break; + case "UISCALE_2X3": + testScale(2.0, 3.0); + break; + case "UISCALE_3X2": + testScale(3.0, 2.0); + break; + case "UISCALE_4X5": + testScale(4.0, 5.0); + break; + default: + throw new RuntimeException("Unknown test case: " + testCase); + } + } + + private static void testScale(double scaleX, double scaleY) { + + Dialog dialog = new Dialog((Frame) null, true) { + + @Override + public void paint(Graphics g) { + super.paint(g); + AffineTransform tx = ((Graphics2D) g).getTransform(); + dispose(); + if (scaleX != tx.getScaleX() || scaleY != tx.getScaleY()) { + throw new RuntimeException(String.format("Wrong scale:" + + "[%f, %f] instead of [%f, %f].", + tx.getScaleX(), tx.getScaleY(), scaleX, scaleY)); + } + } + }; + dialog.setSize(200, 300); + dialog.setVisible(true); + } +} diff --git a/jdk/test/java/awt/image/MultiResolutionImage/MultiResolutionDrawImageWithTransformTest.java b/jdk/test/java/awt/image/MultiResolutionImage/MultiResolutionDrawImageWithTransformTest.java new file mode 100644 index 00000000000..aa4a932d281 --- /dev/null +++ b/jdk/test/java/awt/image/MultiResolutionImage/MultiResolutionDrawImageWithTransformTest.java @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.awt.image.BaseMultiResolutionImage; +import static java.awt.RenderingHints.KEY_RESOLUTION_VARIANT; +import static java.awt.RenderingHints.VALUE_RESOLUTION_VARIANT_SIZE_FIT; +import java.awt.geom.AffineTransform; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import sun.java2d.StateTrackable; +import sun.java2d.SunGraphics2D; +import sun.java2d.SurfaceData; +import sun.java2d.loops.SurfaceType; + +/** + * @test + * @bug 8073320 + * @author Alexander Scherbatiy + * @summary Windows HiDPI support + * @modules java.desktop/sun.java2d java.desktop/sun.java2d.loops + * @run main MultiResolutionDrawImageWithTransformTest + */ +public class MultiResolutionDrawImageWithTransformTest { + + private static final int SCREEN_SIZE = 400; + private static final int IMAGE_SIZE = SCREEN_SIZE / 4; + private static final Color BACKGROUND_COLOR = Color.PINK; + private static final Color[] COLORS = { + Color.CYAN, Color.GREEN, Color.BLUE, Color.ORANGE + }; + + public static void main(String[] args) throws Exception { + + int length = COLORS.length; + BufferedImage[] resolutionVariants = new BufferedImage[length]; + for (int i = 0; i < length; i++) { + resolutionVariants[i] = createRVImage(getSize(i), COLORS[i]); + } + + BaseMultiResolutionImage mrImage = new BaseMultiResolutionImage( + resolutionVariants); + + // scale 1, transform 1, resolution variant 1 + Color color = getImageColor(mrImage, 1, 1); + if (!getColorForScale(1).equals(color)) { + throw new RuntimeException("Wrong resolution variant!"); + } + + // scale 1, transform 2, resolution variant 2 + color = getImageColor(mrImage, 1, 2); + if (!getColorForScale(2).equals(color)) { + throw new RuntimeException("Wrong resolution variant!"); + } + + // scale 2, transform 1, resolution variant 2 + color = getImageColor(mrImage, 2, 1); + if (!getColorForScale(2).equals(color)) { + throw new RuntimeException("Wrong resolution variant!"); + } + + // scale 2, transform 2, resolution variant 4 + color = getImageColor(mrImage, 2, 2); + if (!getColorForScale(4).equals(color)) { + throw new RuntimeException("Wrong resolution variant!"); + } + } + + private static Color getColorForScale(int scale) { + return COLORS[scale - 1]; + } + + private static Color getImageColor(Image image, double configScale, + double transformScale) { + + TestSurfaceData surface = new TestSurfaceData(SCREEN_SIZE, SCREEN_SIZE, + configScale); + SunGraphics2D g2d = new SunGraphics2D(surface, + Color.BLACK, Color.BLACK, null); + g2d.setRenderingHint(KEY_RESOLUTION_VARIANT, + VALUE_RESOLUTION_VARIANT_SIZE_FIT); + AffineTransform tx = AffineTransform.getScaleInstance(transformScale, + transformScale); + g2d.drawImage(image, tx, null); + g2d.dispose(); + + int backgroundX = (int) (1.5 * image.getWidth(null) * transformScale); + int backgroundY = (int) (1.5 * image.getHeight(null) * transformScale); + Color backgroundColor = surface.getColor(backgroundX, backgroundY); + //surface.show(String.format("Config: %f, transform: %f", configScale, transformScale)); + if (!BACKGROUND_COLOR.equals(backgroundColor)) { + throw new RuntimeException("Wrong background color!"); + } + return surface.getColor(IMAGE_SIZE / 4, IMAGE_SIZE / 4); + } + + private static int getSize(int i) { + return (i + 1) * IMAGE_SIZE; + } + + private static BufferedImage createRVImage(int size, Color color) { + BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB); + Graphics g = image.createGraphics(); + g.setColor(color); + g.fillRect(0, 0, size, size); + g.dispose(); + return image; + } + + static class TestGraphicsConfig extends GraphicsConfiguration { + + private final double scale; + + TestGraphicsConfig(double scale) { + this.scale = scale; + } + + @Override + public GraphicsDevice getDevice() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ColorModel getColorModel() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ColorModel getColorModel(int transparency) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public AffineTransform getDefaultTransform() { + return AffineTransform.getScaleInstance(scale, scale); + } + + @Override + public AffineTransform getNormalizingTransform() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Rectangle getBounds() { + throw new UnsupportedOperationException("Not supported yet."); + } + } + + static class TestSurfaceData extends SurfaceData { + + private final int width; + private final int height; + private final GraphicsConfiguration gc; + private final BufferedImage buffImage; + private final double scale; + + public TestSurfaceData(int width, int height, double scale) { + super(StateTrackable.State.DYNAMIC, SurfaceType.Custom, ColorModel.getRGBdefault()); + this.scale = scale; + gc = new TestGraphicsConfig(scale); + this.width = (int) Math.ceil(scale * width); + this.height = (int) Math.ceil(scale * height); + buffImage = new BufferedImage(this.width, this.height, + BufferedImage.TYPE_INT_RGB); + + Graphics imageGraphics = buffImage.createGraphics(); + imageGraphics.setColor(BACKGROUND_COLOR); + imageGraphics.fillRect(0, 0, this.width, this.height); + imageGraphics.dispose(); + } + + Color getColor(int x, int y) { + int sx = (int) Math.ceil(x * scale); + int sy = (int) Math.ceil(y * scale); + return new Color(buffImage.getRGB(sx, sy)); + } + + @Override + public SurfaceData getReplacement() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public GraphicsConfiguration getDeviceConfiguration() { + return gc; + } + + @Override + public Raster getRaster(int x, int y, int w, int h) { + return buffImage.getRaster(); + } + + @Override + public Rectangle getBounds() { + return new Rectangle(0, 0, width, height); + } + + @Override + public Object getDestination() { + throw new UnsupportedOperationException("Not supported yet."); + } + + private void show(String title) { + Frame frame = new Frame() { + + @Override + public void paint(Graphics g) { + super.paint(g); + g.drawImage(buffImage, 0, 0, this); + g.setColor(Color.GRAY); + g.drawRect(0, 0, width, height); + g.drawRect(0, height / 2, width, height / 2); + g.drawRect(width / 2, 0, width / 2, height); + } + }; + frame.setTitle(title); + frame.setSize(width, height); + frame.setVisible(true); + } + } +} From 11e31407a5b9024a07e5aa6d83e62ef9f3059a15 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Sun, 29 Nov 2015 20:27:38 +0000 Subject: [PATCH 095/260] 8144210: Runtime.currentRuntime should be final Reviewed-by: dl, dholmes --- jdk/src/java.base/share/classes/java/lang/Runtime.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/classes/java/lang/Runtime.java b/jdk/src/java.base/share/classes/java/lang/Runtime.java index e75fcb439cf..668357e7067 100644 --- a/jdk/src/java.base/share/classes/java/lang/Runtime.java +++ b/jdk/src/java.base/share/classes/java/lang/Runtime.java @@ -44,7 +44,7 @@ import sun.reflect.Reflection; */ public class Runtime { - private static Runtime currentRuntime = new Runtime(); + private static final Runtime currentRuntime = new Runtime(); /** * Returns the runtime object associated with the current Java application. From 5bb97261178371daad555233e7b3cb57b7ca7b01 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Fri, 13 Nov 2015 14:44:05 +0100 Subject: [PATCH 096/260] 8043138: Attach API should not require jvmstat rmi protocol Reviewed-by: alanb, mchung, erikj, ihse --- jdk/make/gensrc/Gensrc-jdk.jvmstat.gmk | 55 +++++++++++++++++++ ...mstat.gmk => Launcher-jdk.jvmstat.rmi.gmk} | 0 .../sun.jvmstat.monitor.MonitoredHostService | 1 + .../jvmstat/monitor/remote/RemoteHost.java | 0 .../sun/jvmstat/monitor/remote/RemoteVm.java | 0 .../sun/jvmstat/monitor/remote/package.html | 0 .../protocol/rmi/MonitoredHostProvider.java | 0 .../protocol/rmi/MonitoredHostRmiService.java | 0 .../monitor/protocol/rmi/PerfDataBuffer.java | 0 .../protocol/rmi/RemoteMonitoredVm.java | 0 .../monitor/protocol/rmi/RemoteVmManager.java | 0 .../monitor/protocol/rmi/package.html | 0 .../classes/sun/tools/jstatd/Jstatd.java | 0 .../sun/tools/jstatd/RemoteHostImpl.java | 0 .../sun/tools/jstatd/RemoteVmImpl.java | 0 .../sun.jvmstat.monitor.MonitoredHostService | 1 - .../perfdata/monitor/AbstractMonitoredVm.java | 3 - 17 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 jdk/make/gensrc/Gensrc-jdk.jvmstat.gmk rename jdk/make/launcher/{Launcher-jdk.jvmstat.gmk => Launcher-jdk.jvmstat.rmi.gmk} (100%) create mode 100644 jdk/src/jdk.jvmstat.rmi/share/classes/META-INF/services/sun.jvmstat.monitor.MonitoredHostService rename jdk/src/{jdk.jvmstat => jdk.jvmstat.rmi}/share/classes/sun/jvmstat/monitor/remote/RemoteHost.java (100%) rename jdk/src/{jdk.jvmstat => jdk.jvmstat.rmi}/share/classes/sun/jvmstat/monitor/remote/RemoteVm.java (100%) rename jdk/src/{jdk.jvmstat => jdk.jvmstat.rmi}/share/classes/sun/jvmstat/monitor/remote/package.html (100%) rename jdk/src/{jdk.jvmstat => jdk.jvmstat.rmi}/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostProvider.java (100%) rename jdk/src/{jdk.jvmstat => jdk.jvmstat.rmi}/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostRmiService.java (100%) rename jdk/src/{jdk.jvmstat => jdk.jvmstat.rmi}/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/PerfDataBuffer.java (100%) rename jdk/src/{jdk.jvmstat => jdk.jvmstat.rmi}/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteMonitoredVm.java (100%) rename jdk/src/{jdk.jvmstat => jdk.jvmstat.rmi}/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteVmManager.java (100%) rename jdk/src/{jdk.jvmstat => jdk.jvmstat.rmi}/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/package.html (100%) rename jdk/src/{jdk.jvmstat => jdk.jvmstat.rmi}/share/classes/sun/tools/jstatd/Jstatd.java (100%) rename jdk/src/{jdk.jvmstat => jdk.jvmstat.rmi}/share/classes/sun/tools/jstatd/RemoteHostImpl.java (100%) rename jdk/src/{jdk.jvmstat => jdk.jvmstat.rmi}/share/classes/sun/tools/jstatd/RemoteVmImpl.java (100%) diff --git a/jdk/make/gensrc/Gensrc-jdk.jvmstat.gmk b/jdk/make/gensrc/Gensrc-jdk.jvmstat.gmk new file mode 100644 index 00000000000..11e54a6f635 --- /dev/null +++ b/jdk/make/gensrc/Gensrc-jdk.jvmstat.gmk @@ -0,0 +1,55 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +include GensrcCommon.gmk + +################################################################################ + +define merge-providers + $(MKDIR) -p $(@D) + $(CAT) $^ > $@ +endef + +PROVIDER_FILE := META-INF/services/sun.jvmstat.monitor.MonitoredHostService + +# Merge the local and remote sevice providers into jdk.jvmstat/META-INF/services +$(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat/$(PROVIDER_FILE): \ + $(JDK_TOPDIR)/src/jdk.jvmstat/share/classes/$(PROVIDER_FILE) \ + $(JDK_TOPDIR)/src/jdk.jvmstat.rmi/share/classes/$(PROVIDER_FILE) + $(merge-providers) + +# Copy the same service file into jdk.jvmstat.rmi so that they are kept the same. +$(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat.rmi/$(PROVIDER_FILE): \ + $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat/$(PROVIDER_FILE) + $(install-file) + +################################################################################ + +jdk.jvmstat: $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat/$(PROVIDER_FILE) \ + $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat.rmi/$(PROVIDER_FILE) + +all: jdk.jvmstat + +.PHONY: all \ No newline at end of file diff --git a/jdk/make/launcher/Launcher-jdk.jvmstat.gmk b/jdk/make/launcher/Launcher-jdk.jvmstat.rmi.gmk similarity index 100% rename from jdk/make/launcher/Launcher-jdk.jvmstat.gmk rename to jdk/make/launcher/Launcher-jdk.jvmstat.rmi.gmk diff --git a/jdk/src/jdk.jvmstat.rmi/share/classes/META-INF/services/sun.jvmstat.monitor.MonitoredHostService b/jdk/src/jdk.jvmstat.rmi/share/classes/META-INF/services/sun.jvmstat.monitor.MonitoredHostService new file mode 100644 index 00000000000..9ae6583ef3e --- /dev/null +++ b/jdk/src/jdk.jvmstat.rmi/share/classes/META-INF/services/sun.jvmstat.monitor.MonitoredHostService @@ -0,0 +1 @@ +sun.jvmstat.perfdata.monitor.protocol.rmi.MonitoredHostRmiService diff --git a/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/monitor/remote/RemoteHost.java b/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/monitor/remote/RemoteHost.java similarity index 100% rename from jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/monitor/remote/RemoteHost.java rename to jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/monitor/remote/RemoteHost.java diff --git a/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/monitor/remote/RemoteVm.java b/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/monitor/remote/RemoteVm.java similarity index 100% rename from jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/monitor/remote/RemoteVm.java rename to jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/monitor/remote/RemoteVm.java diff --git a/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/monitor/remote/package.html b/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/monitor/remote/package.html similarity index 100% rename from jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/monitor/remote/package.html rename to jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/monitor/remote/package.html diff --git a/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostProvider.java b/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostProvider.java similarity index 100% rename from jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostProvider.java rename to jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostProvider.java diff --git a/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostRmiService.java b/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostRmiService.java similarity index 100% rename from jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostRmiService.java rename to jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/MonitoredHostRmiService.java diff --git a/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/PerfDataBuffer.java b/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/PerfDataBuffer.java similarity index 100% rename from jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/PerfDataBuffer.java rename to jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/PerfDataBuffer.java diff --git a/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteMonitoredVm.java b/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteMonitoredVm.java similarity index 100% rename from jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteMonitoredVm.java rename to jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteMonitoredVm.java diff --git a/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteVmManager.java b/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteVmManager.java similarity index 100% rename from jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteVmManager.java rename to jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/RemoteVmManager.java diff --git a/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/package.html b/jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/package.html similarity index 100% rename from jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/package.html rename to jdk/src/jdk.jvmstat.rmi/share/classes/sun/jvmstat/perfdata/monitor/protocol/rmi/package.html diff --git a/jdk/src/jdk.jvmstat/share/classes/sun/tools/jstatd/Jstatd.java b/jdk/src/jdk.jvmstat.rmi/share/classes/sun/tools/jstatd/Jstatd.java similarity index 100% rename from jdk/src/jdk.jvmstat/share/classes/sun/tools/jstatd/Jstatd.java rename to jdk/src/jdk.jvmstat.rmi/share/classes/sun/tools/jstatd/Jstatd.java diff --git a/jdk/src/jdk.jvmstat/share/classes/sun/tools/jstatd/RemoteHostImpl.java b/jdk/src/jdk.jvmstat.rmi/share/classes/sun/tools/jstatd/RemoteHostImpl.java similarity index 100% rename from jdk/src/jdk.jvmstat/share/classes/sun/tools/jstatd/RemoteHostImpl.java rename to jdk/src/jdk.jvmstat.rmi/share/classes/sun/tools/jstatd/RemoteHostImpl.java diff --git a/jdk/src/jdk.jvmstat/share/classes/sun/tools/jstatd/RemoteVmImpl.java b/jdk/src/jdk.jvmstat.rmi/share/classes/sun/tools/jstatd/RemoteVmImpl.java similarity index 100% rename from jdk/src/jdk.jvmstat/share/classes/sun/tools/jstatd/RemoteVmImpl.java rename to jdk/src/jdk.jvmstat.rmi/share/classes/sun/tools/jstatd/RemoteVmImpl.java diff --git a/jdk/src/jdk.jvmstat/share/classes/META-INF/services/sun.jvmstat.monitor.MonitoredHostService b/jdk/src/jdk.jvmstat/share/classes/META-INF/services/sun.jvmstat.monitor.MonitoredHostService index b106c0fc9a9..f559e14c4b4 100644 --- a/jdk/src/jdk.jvmstat/share/classes/META-INF/services/sun.jvmstat.monitor.MonitoredHostService +++ b/jdk/src/jdk.jvmstat/share/classes/META-INF/services/sun.jvmstat.monitor.MonitoredHostService @@ -1,3 +1,2 @@ sun.jvmstat.perfdata.monitor.protocol.file.MonitoredHostFileService sun.jvmstat.perfdata.monitor.protocol.local.MonitoredHostLocalService -sun.jvmstat.perfdata.monitor.protocol.rmi.MonitoredHostRmiService diff --git a/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/AbstractMonitoredVm.java b/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/AbstractMonitoredVm.java index 85365ce056c..8df13ca7f30 100644 --- a/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/AbstractMonitoredVm.java +++ b/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/AbstractMonitoredVm.java @@ -26,11 +26,8 @@ package sun.jvmstat.perfdata.monitor; import java.util.List; -import java.lang.reflect.*; -import java.io.*; import sun.jvmstat.monitor.*; -import sun.jvmstat.monitor.remote.*; import sun.jvmstat.monitor.event.VmListener; /** From d48c3fcafbf93177919b0e37785a340e0789789b Mon Sep 17 00:00:00 2001 From: Alexander Scherbatiy Date: Fri, 13 Nov 2015 18:36:14 +0400 Subject: [PATCH 097/260] 8137571: Linux HiDPI Graphics support Reviewed-by: flar, serb --- jdk/make/mapfiles/libawt/mapfile-vers-linux | 1 + jdk/make/mapfiles/libawt_xawt/mapfile-vers | 1 + .../unix/classes/sun/awt/X11/InfoWindow.java | 4 +- .../unix/classes/sun/awt/X11/XBaseWindow.java | 80 ++++++++++------ .../unix/classes/sun/awt/X11/XChoicePeer.java | 2 +- .../classes/sun/awt/X11/XComponentPeer.java | 10 +- .../classes/sun/awt/X11/XDecoratedPeer.java | 19 ++-- .../sun/awt/X11/XDragSourceContextPeer.java | 36 +++++--- .../sun/awt/X11/XEmbedClientHelper.java | 2 +- .../sun/awt/X11/XEmbeddedFramePeer.java | 28 +++--- .../classes/sun/awt/X11/XMenuBarPeer.java | 2 +- .../unix/classes/sun/awt/X11/XMenuWindow.java | 2 +- .../classes/sun/awt/X11/XMouseInfoPeer.java | 7 ++ .../classes/sun/awt/X11/XPopupMenuPeer.java | 2 +- .../unix/classes/sun/awt/X11/XRobotPeer.java | 10 +- .../unix/classes/sun/awt/X11/XToolkit.java | 65 ++++++++----- .../unix/classes/sun/awt/X11/XWM.java | 22 ++++- .../classes/sun/awt/X11/XWarningWindow.java | 8 +- .../unix/classes/sun/awt/X11/XWindow.java | 81 ++++++++++------ .../unix/classes/sun/awt/X11/XWindowPeer.java | 62 ++++++++----- .../unix/classes/sun/awt/X11/XlibUtil.java | 24 +++-- .../classes/sun/awt/X11GraphicsConfig.java | 26 +++++- .../classes/sun/awt/X11GraphicsDevice.java | 25 +++++ .../classes/sun/java2d/xr/XRSurfaceData.java | 42 +++++++-- .../sun/java2d/xr/XRSurfaceDataProxy.java | 5 +- .../java2d/xr/XRVolatileSurfaceManager.java | 8 +- .../native/libawt_xawt/awt/awt_GraphicsEnv.c | 35 +++++++ .../unix/native/libawt_xawt/awt/awt_Robot.c | 49 +++++++--- .../native/libawt_xawt/awt/gtk2_interface.c | 2 + .../native/libawt_xawt/awt/gtk2_interface.h | 9 ++ .../properties/HiDPIPropertiesLinuxTest.java | 92 +++++++++++++++++++ 31 files changed, 567 insertions(+), 194 deletions(-) create mode 100644 jdk/test/java/awt/hidpi/properties/HiDPIPropertiesLinuxTest.java diff --git a/jdk/make/mapfiles/libawt/mapfile-vers-linux b/jdk/make/mapfiles/libawt/mapfile-vers-linux index 81f5f037e51..5645cbd18d9 100644 --- a/jdk/make/mapfiles/libawt/mapfile-vers-linux +++ b/jdk/make/mapfiles/libawt/mapfile-vers-linux @@ -206,6 +206,7 @@ SUNWprivate_1.1 { Java_sun_awt_X11GraphicsDevice_enumDisplayModes; Java_sun_awt_X11GraphicsDevice_configDisplayMode; Java_sun_awt_X11GraphicsDevice_resetNativeData; + Java_sun_awt_X11GraphicsDevice_getNativeScaleFactor; Java_sun_awt_X11GraphicsEnvironment_checkShmExt; Java_sun_awt_X11GraphicsEnvironment_getDefaultScreenNum; Java_sun_awt_X11GraphicsEnvironment_getDisplayString; diff --git a/jdk/make/mapfiles/libawt_xawt/mapfile-vers b/jdk/make/mapfiles/libawt_xawt/mapfile-vers index 7e29cb3cb65..182ed0acfd7 100644 --- a/jdk/make/mapfiles/libawt_xawt/mapfile-vers +++ b/jdk/make/mapfiles/libawt_xawt/mapfile-vers @@ -214,6 +214,7 @@ SUNWprivate_1.1 { Java_sun_awt_X11GraphicsDevice_enumDisplayModes; Java_sun_awt_X11GraphicsDevice_configDisplayMode; Java_sun_awt_X11GraphicsDevice_resetNativeData; + Java_sun_awt_X11GraphicsDevice_getNativeScaleFactor; Java_sun_awt_X11GraphicsConfig_initIDs; Java_sun_awt_X11GraphicsConfig_getXResolution; Java_sun_awt_X11GraphicsConfig_getYResolution; diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java index 42fd317d69d..a7870a95b6a 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java @@ -80,9 +80,7 @@ public abstract class InfoWindow extends Window { pack(); Dimension size = getSize(); - // TODO: When 6356322 is fixed we should get screen bounds in - // this way: eframe.getGraphicsConfiguration().getBounds(). - Dimension scrSize = Toolkit.getDefaultToolkit().getScreenSize(); + Rectangle scrSize = getGraphicsConfiguration().getBounds(); if (corner.x < scrSize.width/2 && corner.y < scrSize.height/2) { // 1st square setLocation(corner.x + indent, corner.y + indent); diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XBaseWindow.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XBaseWindow.java index ecca4d3081c..94cb9fdacaf 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XBaseWindow.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XBaseWindow.java @@ -299,6 +299,22 @@ public class XBaseWindow { params.put(EVENT_MASK, Long.valueOf(eventMask)); } + /** + * Returns scale factor of the window. It is used to convert native + * coordinates to local and vice verse. + */ + protected int getScale() { + return 1; + } + + protected int scaleUp(int x) { + return x; + } + + protected int scaleDown(int x) { + return x; + } + /** * Creates window with parameters specified by params * @see #init @@ -366,15 +382,17 @@ public class XBaseWindow { log.fine("Creating window for " + this + " with the following attributes: \n" + params); } window = XlibWrapper.XCreateWindow(XToolkit.getDisplay(), - parentWindow.longValue(), - bounds.x, bounds.y, // location - bounds.width, bounds.height, // size - 0, // border - depth.intValue(), // depth - visual_class.intValue(), // class - visual.longValue(), // visual - value_mask, // value mask - xattr.pData); // attributes + parentWindow.longValue(), + scaleUp(bounds.x), + scaleUp(bounds.y), + scaleUp(bounds.width), + scaleUp(bounds.height), + 0, // border + depth.intValue(), // depth + visual_class.intValue(), // class + visual.longValue(), // visual + value_mask, // value mask + xattr.pData); // attributes if (window == 0) { throw new IllegalStateException("Couldn't create window because of wrong parameters. Run with NOISY_AWT to see details"); @@ -492,18 +510,18 @@ public class XBaseWindow { // we want to reset PPosition in hints. This is necessary // for locationByPlatform functionality if ((flags & XUtilConstants.PPosition) != 0) { - hints.set_x(x); - hints.set_y(y); + hints.set_x(scaleUp(x)); + hints.set_y(scaleUp(y)); } if ((flags & XUtilConstants.PSize) != 0) { - hints.set_width(width); - hints.set_height(height); + hints.set_width(scaleUp(width)); + hints.set_height(scaleUp(height)); } else if ((hints.get_flags() & XUtilConstants.PSize) != 0) { flags |= XUtilConstants.PSize; } if ((flags & XUtilConstants.PMinSize) != 0) { - hints.set_min_width(width); - hints.set_min_height(height); + hints.set_min_width(scaleUp(width)); + hints.set_min_height(scaleUp(height)); } else if ((hints.get_flags() & XUtilConstants.PMinSize) != 0) { flags |= XUtilConstants.PMinSize; //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced. @@ -512,31 +530,31 @@ public class XBaseWindow { if ((flags & XUtilConstants.PMaxSize) != 0) { if (maxBounds != null) { if (maxBounds.width != Integer.MAX_VALUE) { - hints.set_max_width(maxBounds.width); + hints.set_max_width(scaleUp(maxBounds.width)); } else { hints.set_max_width(XToolkit.getDefaultScreenWidth()); } if (maxBounds.height != Integer.MAX_VALUE) { - hints.set_max_height(maxBounds.height); + hints.set_max_height(scaleUp(maxBounds.height)); } else { hints.set_max_height(XToolkit.getDefaultScreenHeight()); } } else { - hints.set_max_width(width); - hints.set_max_height(height); + hints.set_max_width(scaleUp(width)); + hints.set_max_height(scaleUp(height)); } } else if ((hints.get_flags() & XUtilConstants.PMaxSize) != 0) { flags |= XUtilConstants.PMaxSize; if (maxBounds != null) { if (maxBounds.width != Integer.MAX_VALUE) { - hints.set_max_width(maxBounds.width); + hints.set_max_width(scaleUp(maxBounds.width)); } else { - hints.set_max_width(XToolkit.getDefaultScreenWidth()); + hints.set_max_width(scaleUp(XToolkit.getDefaultScreenWidth())); } if (maxBounds.height != Integer.MAX_VALUE) { - hints.set_max_height(maxBounds.height); + hints.set_max_height(scaleUp(maxBounds.height)); } else { - hints.set_max_height(XToolkit.getDefaultScreenHeight()); + hints.set_max_height(scaleUp(XToolkit.getDefaultScreenHeight())); } } else { // Leave intact @@ -723,7 +741,9 @@ public class XBaseWindow { height = Math.max(MIN_SIZE, height); XToolkit.awtLock(); try { - XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getWindow(), x,y,width,height); + XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getWindow(), + scaleUp(x), scaleUp(y), + scaleUp(width), scaleUp(height)); } finally { XToolkit.awtUnlock(); } @@ -756,7 +776,8 @@ public class XBaseWindow { rpt.x = x + srcPeer.getAbsoluteX(); rpt.y = y + srcPeer.getAbsoluteY(); } else { - rpt = XlibUtil.translateCoordinates(src, dst, new Point(x, y)); + int scale = srcPeer == null ? 1 : srcPeer.getScale(); + rpt = XlibUtil.translateCoordinates(src, dst, new Point(x, y), scale); } return rpt; } @@ -1042,10 +1063,11 @@ public class XBaseWindow { if (insLog.isLoggable(PlatformLogger.Level.FINER)) { insLog.finer("Configure, {0}", xe); } - x = xe.get_x(); - y = xe.get_y(); - width = xe.get_width(); - height = xe.get_height(); + + x = scaleDown(xe.get_x()); + y = scaleDown(xe.get_y()); + width = scaleDown(xe.get_width()); + height = scaleDown(xe.get_height()); } /** * Checks ButtonRelease released all Mouse buttons diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XChoicePeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XChoicePeer.java index b38297278c6..54155cf128e 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XChoicePeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XChoicePeer.java @@ -785,7 +785,7 @@ public class XChoicePeer extends XComponentPeer implements ChoicePeer, ToplevelS numItemsDisplayed = Math.min(MAX_UNFURLED_ITEMS, numItems); } Point global = XChoicePeer.this.toGlobal(0,0); - Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); + Rectangle screen = graphicsConfig.getBounds(); if (alignUnder != null) { Rectangle choiceRec = XChoicePeer.this.getBounds(); diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java index 5e8937436c0..e1331c7fdd0 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java @@ -158,7 +158,9 @@ public class XComponentPeer extends XWindow implements ComponentPeer, DropTarget XComponentPeer newPeer = (XComponentPeer)newNativeParent; XToolkit.awtLock(); try { - XlibWrapper.XReparentWindow(XToolkit.getDisplay(), getWindow(), newPeer.getContentWindow(), x, y); + XlibWrapper.XReparentWindow(XToolkit.getDisplay(), + getWindow(), newPeer.getContentWindow(), + scaleUp(x), scaleUp(y)); parentWindow = newPeer; } finally { XToolkit.awtUnlock(); @@ -1394,6 +1396,12 @@ public class XComponentPeer extends XWindow implements ComponentPeer, DropTarget XToolkit.awtLock(); try { if (shape != null) { + + int scale = getScale(); + if (scale != 1) { + shape = shape.getScaledRegion(scale, scale); + } + XlibWrapper.SetRectangularShape( XToolkit.getDisplay(), getWindow(), diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java index d5e2a0be3cd..74ee97f4f89 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDecoratedPeer.java @@ -737,16 +737,12 @@ abstract class XDecoratedPeer extends XWindowPeer { updateChildrenSizes(); - // Bounds of the window - Rectangle targetBounds = AWTAccessor.getComponentAccessor().getBounds(target); - Point newLocation = getNewLocation(xe, currentInsets.left, currentInsets.top); - WindowDimensions newDimensions = new WindowDimensions(newLocation, - new Dimension(xe.get_width(), xe.get_height()), - copy(currentInsets), - true); + new Dimension(scaleDown(xe.get_width()), + scaleDown(xe.get_height())), + copy(currentInsets), true); if (insLog.isLoggable(PlatformLogger.Level.FINER)) { insLog.finer("Insets are {0}, new dimensions {1}", @@ -793,7 +789,8 @@ abstract class XDecoratedPeer extends XWindowPeer { try { updateSizeHints(rec.x, rec.y, rec.width, rec.height); XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getShell(), - rec.x, rec.y, rec.width, rec.height); + scaleUp(rec.x), scaleUp(rec.y), + scaleUp(rec.width), scaleUp(rec.height)); } finally { XToolkit.awtUnlock(); @@ -806,7 +803,8 @@ abstract class XDecoratedPeer extends XWindowPeer { XToolkit.awtLock(); try { updateSizeHints(rec.x, rec.y, rec.width, rec.height); - XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), rec.width, rec.height); + XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), + scaleUp(rec.width), scaleUp(rec.height)); } finally { XToolkit.awtUnlock(); @@ -819,7 +817,8 @@ abstract class XDecoratedPeer extends XWindowPeer { XToolkit.awtLock(); try { updateSizeHints(rec.x, rec.y, rec.width, rec.height); - XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), rec.x, rec.y); + XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), + scaleUp(rec.x), scaleUp(rec.y)); } finally { XToolkit.awtUnlock(); diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDragSourceContextPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDragSourceContextPeer.java index 5b52c86b75d..5dcf06c59bf 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDragSourceContextPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XDragSourceContextPeer.java @@ -83,6 +83,8 @@ public final class XDragSourceContextPeer private long[] sourceFormats = null; /* The XID of the root subwindow that contains the current target. */ private long targetRootSubwindow = 0; + /* window scale factor */ + int windowScale = 1; /* The pointer location. */ private int xRoot = 0; private int yRoot = 0; @@ -130,8 +132,8 @@ public final class XDragSourceContextPeer long xcursor = 0; long rootWindow = 0; - long dragWindow = 0; long timeStamp = 0; + windowScale = wpeer.getScale(); /* Retrieve the X cursor for the drag operation. */ { @@ -156,8 +158,6 @@ public final class XDragSourceContextPeer rootWindow = XlibWrapper.RootWindow(XToolkit.getDisplay(), screen); } - dragWindow = XWindow.getXAWTRootWindow().getWindow(); - timeStamp = XToolkit.getCurrentServerTime(); int dropActions = getDragSourceContext().getSourceActions(); @@ -441,8 +441,8 @@ public final class XDragSourceContextPeer private void updateTargetWindow(XMotionEvent xmotion) { assert XToolkit.isAWTLockHeldByCurrentThread(); - int x = xmotion.get_x_root(); - int y = xmotion.get_y_root(); + int x = scaleDown(xmotion.get_x_root()); + int y = scaleDown(xmotion.get_y_root()); long time = xmotion.get_time(); long subwindow = xmotion.get_subwindow(); @@ -498,9 +498,13 @@ public final class XDragSourceContextPeer if (!dragInProgress) { return; } - if (xRoot != xmotion.get_x_root() || yRoot != xmotion.get_y_root()) { - xRoot = xmotion.get_x_root(); - yRoot = xmotion.get_y_root(); + + int motionXRoot = scaleDown(xmotion.get_x_root()); + int motionYRoot = scaleDown(xmotion.get_y_root()); + + if (xRoot != motionXRoot || yRoot != motionYRoot) { + xRoot = motionXRoot; + yRoot = motionYRoot; postDragSourceDragEvent(targetAction, XWindow.getModifiers(xmotion.get_state(),0,0), @@ -519,8 +523,8 @@ public final class XDragSourceContextPeer updateTargetWindow(xmotion); if (dragProtocol != null) { - dragProtocol.sendMoveMessage(xmotion.get_x_root(), - xmotion.get_y_root(), + dragProtocol.sendMoveMessage(scaleDown(xmotion.get_x_root()), + scaleDown(xmotion.get_y_root()), sourceAction, sourceActions, xmotion.get_time()); } @@ -528,8 +532,8 @@ public final class XDragSourceContextPeer private void processDrop(XButtonEvent xbutton) { try { - dragProtocol.initiateDrop(xbutton.get_x_root(), - xbutton.get_y_root(), + dragProtocol.initiateDrop(scaleDown(xbutton.get_x_root()), + scaleDown(xbutton.get_y_root()), sourceAction, sourceActions, xbutton.get_time()); } catch (XException e) { @@ -805,4 +809,12 @@ public final class XDragSourceContextPeer dndInProgress = false; cleanup(XConstants.CurrentTime); } + + public int scaleUp(int x) { + return x * windowScale; + } + + public int scaleDown(int x) { + return x / windowScale; + } } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbedClientHelper.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbedClientHelper.java index afbaaaaeb43..f8a8c8a5e03 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbedClientHelper.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbedClientHelper.java @@ -182,7 +182,7 @@ public class XEmbedClientHelper extends XEmbedHelper implements XEventDispatcher embedded.notifyStopped(); // check if newParent is a root window X11GraphicsConfig gc = (X11GraphicsConfig)embedded.getGraphicsConfiguration(); - X11GraphicsDevice gd = (X11GraphicsDevice)gc.getDevice(); + X11GraphicsDevice gd = gc.getDevice(); if ((newParent == XlibUtil.getRootWindow(gd.getScreen())) || (newParent == XToolkit.getDefaultRootWindow())) { diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbeddedFramePeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbeddedFramePeer.java index 72f0bc658b5..937c3a36cfc 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbeddedFramePeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XEmbeddedFramePeer.java @@ -146,18 +146,18 @@ public class XEmbeddedFramePeer extends XFramePeer { // fix for 5063031 // if we use super.handleConfigureNotifyEvent() we would get wrong // size and position because embedded frame really is NOT a decorated one - checkIfOnNewScreen(toGlobal(new Rectangle(xe.get_x(), - xe.get_y(), - xe.get_width(), - xe.get_height()))); + checkIfOnNewScreen(toGlobal(new Rectangle(scaleDown(xe.get_x()), + scaleDown(xe.get_y()), + scaleDown(xe.get_width()), + scaleDown(xe.get_height())))); Rectangle oldBounds = getBounds(); synchronized (getStateLock()) { - x = xe.get_x(); - y = xe.get_y(); - width = xe.get_width(); - height = xe.get_height(); + x = scaleDown(xe.get_x()); + y = scaleDown(xe.get_y()); + width = scaleDown(xe.get_width()); + height = scaleDown(xe.get_height()); dimensions.setClientSize(width, height); dimensions.setLocation(x, y); @@ -215,10 +215,10 @@ public class XEmbeddedFramePeer extends XFramePeer { try { XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), getWindow(), attr.pData); - x = attr.get_x(); - y = attr.get_y(); - w = attr.get_width(); - h = attr.get_height(); + x = scaleDown(attr.get_x()); + y = scaleDown(attr.get_y()); + w = scaleDown(attr.get_width()); + h = scaleDown(attr.get_height()); } finally { XToolkit.awtUnlock(); } @@ -276,7 +276,7 @@ public class XEmbeddedFramePeer extends XFramePeer { { Point absoluteLoc = XlibUtil.translateCoordinates(getWindow(), XToolkit.getDefaultRootWindow(), - new Point(0, 0)); + new Point(0, 0), getScale()); return absoluteLoc != null ? absoluteLoc.x : 0; } @@ -284,7 +284,7 @@ public class XEmbeddedFramePeer extends XFramePeer { { Point absoluteLoc = XlibUtil.translateCoordinates(getWindow(), XToolkit.getDefaultRootWindow(), - new Point(0, 0)); + new Point(0, 0), getScale()); return absoluteLoc != null ? absoluteLoc.y : 0; } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuBarPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuBarPeer.java index 2936b2af0c1..c9a8108a2e9 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuBarPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuBarPeer.java @@ -296,7 +296,7 @@ public class XMenuBarPeer extends XBaseMenuWindow implements MenuBarPeer { */ protected Rectangle getSubmenuBounds(Rectangle itemBounds, Dimension windowSize) { Rectangle globalBounds = toGlobal(itemBounds); - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension screenSize = graphicsConfig.getBounds().getSize(); Rectangle res; res = fitWindowBelow(globalBounds, windowSize, screenSize); if (res != null) { diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java index 7bd63917663..76d034adf89 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java @@ -278,7 +278,7 @@ public class XMenuWindow extends XBaseMenuWindow { */ protected Rectangle getSubmenuBounds(Rectangle itemBounds, Dimension windowSize) { Rectangle globalBounds = toGlobal(itemBounds); - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension screenSize = graphicsConfig.getBounds().getSize(); Rectangle res; res = fitWindowRight(globalBounds, windowSize, screenSize); if (res != null) { diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMouseInfoPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMouseInfoPeer.java index 1ff294fd9fd..09c9450a176 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMouseInfoPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMouseInfoPeer.java @@ -30,6 +30,7 @@ import java.awt.Window; import java.awt.GraphicsEnvironment; import java.awt.GraphicsDevice; import java.awt.peer.MouseInfoPeer; +import sun.awt.X11GraphicsDevice; import sun.awt.AWTAccessor; @@ -64,6 +65,12 @@ public class XMouseInfoPeer implements MouseInfoPeer { if (pointerFound) { point.x = Native.getInt(XlibWrapper.larg3); point.y = Native.getInt(XlibWrapper.larg4); + GraphicsDevice device = gds[i]; + if (device instanceof X11GraphicsDevice) { + int scale = ((X11GraphicsDevice) device).getScaleFactor(); + point.x = XlibUtil.scaleDown(point.x, scale); + point.y = XlibUtil.scaleDown(point.y, scale); + } return i; } } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XPopupMenuPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XPopupMenuPeer.java index c510836a2fa..b976a2d71b3 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XPopupMenuPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XPopupMenuPeer.java @@ -215,7 +215,7 @@ public class XPopupMenuPeer extends XMenuWindow implements PopupMenuPeer { */ protected Rectangle getWindowBounds(Point origin, Dimension windowSize) { Rectangle globalBounds = new Rectangle(origin.x, origin.y, 0, 0); - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension screenSize = graphicsConfig.getBounds().getSize(); Rectangle res; res = fitWindowRight(globalBounds, windowSize, screenSize); if (res != null) { diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java index 156abd9ce68..6d8473cb47c 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XRobotPeer.java @@ -64,7 +64,7 @@ class XRobotPeer implements RobotPeer { @Override public void mouseMove(int x, int y) { - mouseMoveImpl(xgc, x, y); + mouseMoveImpl(xgc, xgc.scaleUp(x), xgc.scaleUp(y)); } @Override @@ -95,7 +95,8 @@ class XRobotPeer implements RobotPeer { @Override public int getRGBPixel(int x, int y) { int pixelArray[] = new int[1]; - getRGBPixelsImpl(xgc, x, y, 1, 1, pixelArray, isGtkSupported); + getRGBPixelsImpl(xgc, x, y, 1, 1, xgc.getScale(), pixelArray, + isGtkSupported); return pixelArray[0]; } @@ -103,7 +104,7 @@ class XRobotPeer implements RobotPeer { public int [] getRGBPixels(Rectangle bounds) { int pixelArray[] = new int[bounds.width*bounds.height]; getRGBPixelsImpl(xgc, bounds.x, bounds.y, bounds.width, bounds.height, - pixelArray, isGtkSupported); + xgc.getScale(), pixelArray, isGtkSupported); return pixelArray; } @@ -118,5 +119,6 @@ class XRobotPeer implements RobotPeer { private static synchronized native void keyReleaseImpl(int keycode); private static synchronized native void getRGBPixelsImpl(X11GraphicsConfig xgc, - int x, int y, int width, int height, int pixelArray[], boolean isGtkSupported); + int x, int y, int width, int height, int scale, + int pixelArray[], boolean isGtkSupported); } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java index 6b97e48a297..3852193bd4a 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java @@ -57,6 +57,7 @@ import sun.print.PrintJob2D; import sun.security.action.GetPropertyAction; import sun.security.action.GetBooleanAction; import sun.util.logging.PlatformLogger; +import static sun.awt.X11.XlibUtil.scaleDown; public final class XToolkit extends UNIXToolkit implements Runnable { private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XToolkit"); @@ -422,7 +423,7 @@ public final class XToolkit extends UNIXToolkit implements Runnable { } } - private void processGlobalMotionEvent(XEvent e) { + private void processGlobalMotionEvent(XEvent e, XBaseWindow win) { // Only our windows guaranteely generate MotionNotify, so we // should track enter/leave, to catch the moment when to // switch to XQueryPointer @@ -431,9 +432,11 @@ public final class XToolkit extends UNIXToolkit implements Runnable { awtLock(); try { if (lastCursorPos == null) { - lastCursorPos = new Point(ev.get_x_root(), ev.get_y_root()); + lastCursorPos = new Point(win.scaleDown(ev.get_x_root()), + win.scaleDown(ev.get_y_root())); } else { - lastCursorPos.setLocation(ev.get_x_root(), ev.get_y_root()); + lastCursorPos.setLocation(win.scaleDown(ev.get_x_root()), + win.scaleDown(ev.get_y_root())); } } finally { awtUnlock(); @@ -452,9 +455,11 @@ public final class XToolkit extends UNIXToolkit implements Runnable { awtLock(); try { if (lastCursorPos == null) { - lastCursorPos = new Point(ev.get_x_root(), ev.get_y_root()); + lastCursorPos = new Point(win.scaleDown(ev.get_x_root()), + win.scaleDown(ev.get_y_root())); } else { - lastCursorPos.setLocation(ev.get_x_root(), ev.get_y_root()); + lastCursorPos.setLocation(win.scaleDown(ev.get_x_root()), + win.scaleDown(ev.get_y_root())); } } finally { awtUnlock(); @@ -492,10 +497,11 @@ public final class XToolkit extends UNIXToolkit implements Runnable { private void dispatchEvent(XEvent ev) { final XAnyEvent xany = ev.get_xany(); - if (windowToXWindow(xany.get_window()) != null && - (ev.get_type() == XConstants.MotionNotify || ev.get_type() == XConstants.EnterNotify || ev.get_type() == XConstants.LeaveNotify)) - { - processGlobalMotionEvent(ev); + XBaseWindow baseWindow = windowToXWindow(xany.get_window()); + if (baseWindow != null && (ev.get_type() == XConstants.MotionNotify + || ev.get_type() == XConstants.EnterNotify + || ev.get_type() == XConstants.LeaveNotify)) { + processGlobalMotionEvent(ev, baseWindow); } if( ev.get_type() == XConstants.MappingNotify ) { @@ -670,8 +676,8 @@ public final class XToolkit extends UNIXToolkit implements Runnable { XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), pattr.pData); - screenWidth = pattr.get_width(); - screenHeight = pattr.get_height(); + screenWidth = config.scaleDown(pattr.get_width()); + screenHeight = config.scaleDown(pattr.get_height()); } finally { pattr.dispose(); } @@ -701,7 +707,7 @@ public final class XToolkit extends UNIXToolkit implements Runnable { return getDefaultScreenHeight(); } - private static Rectangle getWorkArea(long root) + private static Rectangle getWorkArea(long root, int scale) { XAtom XA_NET_WORKAREA = XAtom.get("_NET_WORKAREA"); @@ -717,7 +723,10 @@ public final class XToolkit extends UNIXToolkit implements Runnable { int rootWidth = (int)Native.getLong(native_ptr, 2); int rootHeight = (int)Native.getLong(native_ptr, 3); - return new Rectangle(rootX, rootY, rootWidth, rootHeight); + return new Rectangle(scaleDown(rootX, scale), + scaleDown(rootY, scale), + scaleDown(rootWidth, scale), + scaleDown(rootHeight, scale)); } } finally @@ -750,15 +759,16 @@ public final class XToolkit extends UNIXToolkit implements Runnable { try { X11GraphicsConfig x11gc = (X11GraphicsConfig)gc; - X11GraphicsDevice x11gd = (X11GraphicsDevice)x11gc.getDevice(); + X11GraphicsDevice x11gd = x11gc.getDevice(); long root = XlibUtil.getRootWindow(x11gd.getScreen()); - Rectangle rootBounds = XlibUtil.getWindowGeometry(root); + int scale = x11gc.getScale(); + Rectangle rootBounds = XlibUtil.getWindowGeometry(root, scale); X11GraphicsEnvironment x11ge = (X11GraphicsEnvironment) GraphicsEnvironment.getLocalGraphicsEnvironment(); if (!x11ge.runningXinerama()) { - Rectangle workArea = XToolkit.getWorkArea(root); + Rectangle workArea = XToolkit.getWorkArea(root, scale); if (workArea != null) { return new Insets(workArea.y, @@ -768,7 +778,7 @@ public final class XToolkit extends UNIXToolkit implements Runnable { } } - return getScreenInsetsManually(root, rootBounds, gc.getBounds()); + return getScreenInsetsManually(root, rootBounds, gc.getBounds(), scale); } finally { @@ -783,7 +793,8 @@ public final class XToolkit extends UNIXToolkit implements Runnable { * * This method should be called under XToolkit.awtLock() */ - private Insets getScreenInsetsManually(long root, Rectangle rootBounds, Rectangle screenBounds) + private Insets getScreenInsetsManually(long root, Rectangle rootBounds, + Rectangle screenBounds, int scale) { /* * During the manual calculation of screen insets we iterate @@ -831,20 +842,23 @@ public final class XToolkit extends UNIXToolkit implements Runnable { if (strutPresent) { // second, verify that window is located on the proper screen - Rectangle windowBounds = XlibUtil.getWindowGeometry(window); + Rectangle windowBounds = XlibUtil.getWindowGeometry(window, + scale); if (windowLevel > 1) { - windowBounds = XlibUtil.translateCoordinates(window, root, windowBounds); + windowBounds = XlibUtil.translateCoordinates(window, root, + windowBounds, + scale); } // if _NET_WM_STRUT_PARTIAL is present, we should use its values to detect // if the struts area intersects with screenBounds, however some window // managers don't set this hint correctly, so we just get intersection with windowBounds if (windowBounds != null && windowBounds.intersects(screenBounds)) { - int left = (int)Native.getLong(native_ptr, 0); - int right = (int)Native.getLong(native_ptr, 1); - int top = (int)Native.getLong(native_ptr, 2); - int bottom = (int)Native.getLong(native_ptr, 3); + int left = scaleDown((int)Native.getLong(native_ptr, 0), scale); + int right = scaleDown((int)Native.getLong(native_ptr, 1), scale); + int top = scaleDown((int)Native.getLong(native_ptr, 2), scale); + int bottom = scaleDown((int)Native.getLong(native_ptr, 3), scale); /* * struts could be relative to root window bounds, so @@ -2487,7 +2501,8 @@ public final class XToolkit extends UNIXToolkit implements Runnable { oops_updated = false; long event_number = getEventNumber(); // Generate OOPS ConfigureNotify event - XlibWrapper.XMoveWindow(getDisplay(), win.getWindow(), ++oops_position, 0); + XlibWrapper.XMoveWindow(getDisplay(), win.getWindow(), + win.scaleUp(++oops_position), 0); // Change win position each time to avoid system optimization if (oops_position > 50) { oops_position = 0; diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWM.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWM.java index 61d2cbc380d..464c0dbde71 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWM.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWM.java @@ -1024,8 +1024,12 @@ final class XWM shellBounds.translate(-window.currentInsets.left, -window.currentInsets.top); window.updateSizeHints(window.getDimensions()); requestWMExtents(window.getWindow()); - XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(), - shellBounds.x, shellBounds.y, shellBounds.width, shellBounds.height); + XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), + window.getShell(), + window.scaleUp(shellBounds.x), + window.scaleUp(shellBounds.y), + window.scaleUp(shellBounds.width), + window.scaleUp(shellBounds.height)); /* REMINDER: will need to revisit when setExtendedStateBounds is added */ //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced. //We need to update frame's minimum size, not to reset it @@ -1058,8 +1062,12 @@ final class XWM window.updateSizeHints(newDimensions); requestWMExtents(window.getWindow()); XToolkit.XSync(); - XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(), - shellBounds.x, shellBounds.y, shellBounds.width, shellBounds.height); + XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), + window.getShell(), + window.scaleUp(shellBounds.x), + window.scaleUp(shellBounds.y), + window.scaleUp(shellBounds.width), + window.scaleUp(shellBounds.height)); } if (!justChangeSize) { /* update decorations */ setShellDecor(window); @@ -1701,6 +1709,12 @@ final class XWM pattr.dispose(); } } + + correctWM.top = win.scaleUp(correctWM.top); + correctWM.bottom = win.scaleUp(correctWM.bottom); + correctWM.left = win.scaleUp(correctWM.left); + correctWM.right = win.scaleUp(correctWM.right); + if (storedInsets.get(win.getClass()) == null) { storedInsets.put(win.getClass(), correctWM); } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWarningWindow.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWarningWindow.java index e1fa63e2604..81f7e84839a 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWarningWindow.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWarningWindow.java @@ -258,10 +258,10 @@ class XWarningWindow extends XWindow { super.handleExposeEvent(xev); XExposeEvent xe = xev.get_xexpose(); - final int x = xe.get_x(); - final int y = xe.get_y(); - final int width = xe.get_width(); - final int height = xe.get_height(); + final int x = scaleDown(xe.get_x()); + final int y = scaleDown(xe.get_y()); + final int width = scaleDown(xe.get_width()); + final int height = scaleDown(xe.get_height()); SunToolkit.executeOnEventHandlerThread(target, new Runnable() { public void run() { diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java index 42a03359f1f..b431c14d9d1 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java @@ -548,10 +548,11 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { if (isEventDisabled(xev)) { return; } - int x = xe.get_x(); - int y = xe.get_y(); - int w = xe.get_width(); - int h = xe.get_height(); + + int x = scaleDown(xe.get_x()); + int y = scaleDown(xe.get_y()); + int w = scaleDown(xe.get_width()); + int h = scaleDown(xe.get_height()); Component target = getEventSource(); ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); @@ -676,10 +677,11 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { when = xbe.get_time(); long jWhen = XToolkit.nowMillisUTC_offset(when); - int x = xbe.get_x(); - int y = xbe.get_y(); + int x = scaleDown(xbe.get_x()); + int y = scaleDown(xbe.get_y()); if (xev.get_xany().get_window() != window) { - Point localXY = toLocal(xbe.get_x_root(), xbe.get_y_root()); + Point localXY = toLocal(scaleDown(xbe.get_x_root()), + scaleDown(xbe.get_y_root())); x = localXY.x; y = localXY.y; } @@ -730,8 +732,8 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { MouseEvent me = new MouseEvent(getEventSource(), type == XConstants.ButtonPress ? MouseEvent.MOUSE_PRESSED : MouseEvent.MOUSE_RELEASED, jWhen,modifiers, x, y, - xbe.get_x_root(), - xbe.get_y_root(), + scaleDown(xbe.get_x_root()), + scaleDown(xbe.get_y_root()), clickCount,popupTrigger,button); postEventToEventQueue(me); @@ -744,8 +746,8 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { jWhen, modifiers, x, y, - xbe.get_x_root(), - xbe.get_y_root(), + scaleDown(xbe.get_x_root()), + scaleDown(xbe.get_y_root()), clickCount, false, button)); } @@ -757,8 +759,8 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { MouseWheelEvent mwe = new MouseWheelEvent(getEventSource(),MouseEvent.MOUSE_WHEEL, jWhen, modifiers, x, y, - xbe.get_x_root(), - xbe.get_y_root(), + scaleDown(xbe.get_x_root()), + scaleDown(xbe.get_y_root()), 1,false,MouseWheelEvent.WHEEL_UNIT_SCROLL, 3,button==4 ? -1 : 1); postEventToEventQueue(mwe); @@ -805,8 +807,8 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { /* Fix for 6176814 . Add multiclick checking. */ - int x = xme.get_x(); - int y = xme.get_y(); + int x = scaleDown(xme.get_x()); + int y = scaleDown(xme.get_y()); XWindow lastWindow = (lastWindowRef != null) ? (lastWindowRef.get()):(null); if (!(lastWindow == this && @@ -828,7 +830,8 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { Component source = getEventSource(); if (xme.get_window() != window) { - Point localXY = toLocal(xme.get_x_root(), xme.get_y_root()); + Point localXY = toLocal(scaleDown(xme.get_x_root()), + scaleDown(xme.get_y_root())); x = localXY.x; y = localXY.y; } @@ -837,7 +840,9 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { */ if ((isDragging && clickCount == 0) || !isDragging) { MouseEvent mme = new MouseEvent(source, mouseEventType, jWhen, - modifiers, x, y, xme.get_x_root(), xme.get_y_root(), + modifiers, x, y, + scaleDown(xme.get_x_root()), + scaleDown(xme.get_y_root()), clickCount, popupTrigger, MouseEvent.NOBUTTON); postEventToEventQueue(mme); } @@ -949,10 +954,11 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { int modifiers = getModifiers(xce.get_state(),0,0); int clickCount = 0; boolean popupTrigger = false; - int x = xce.get_x(); - int y = xce.get_y(); + int x = scaleDown(xce.get_x()); + int y = scaleDown(xce.get_y()); if (xce.get_window() != window) { - Point localXY = toLocal(xce.get_x_root(), xce.get_y_root()); + Point localXY = toLocal(scaleDown(xce.get_x_root()), + scaleDown(xce.get_y_root())); x = localXY.x; y = localXY.y; } @@ -960,18 +966,27 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { // This code tracks boundary crossing and ensures MOUSE_ENTER/EXIT // are posted in alternate pairs if (compWithMouse != null) { - MouseEvent me = new MouseEvent(compWithMouse, - MouseEvent.MOUSE_EXITED, jWhen, modifiers, xce.get_x(), - xce.get_y(), xce.get_x_root(), xce.get_y_root(), clickCount, popupTrigger, - MouseEvent.NOBUTTON); + MouseEvent me = new MouseEvent(compWithMouse, MouseEvent.MOUSE_EXITED, + jWhen, modifiers, + scaleDown(xce.get_x()), + scaleDown(xce.get_y()), + scaleDown(xce.get_x_root()), + scaleDown(xce.get_y_root()), + clickCount, popupTrigger, + MouseEvent.NOBUTTON); postEventToEventQueue(me); eventLog.finest("Clearing last window ref"); lastWindowRef = null; } if (xce.get_type() == XConstants.EnterNotify) { MouseEvent me = new MouseEvent(getEventSource(), MouseEvent.MOUSE_ENTERED, - jWhen, modifiers, xce.get_x(), xce.get_y(), xce.get_x_root(), xce.get_y_root(), clickCount, - popupTrigger, MouseEvent.NOBUTTON); + jWhen, modifiers, + scaleDown(xce.get_x()), + scaleDown(xce.get_y()), + scaleDown(xce.get_x_root()), + scaleDown(xce.get_y_root()), + clickCount, popupTrigger, + MouseEvent.NOBUTTON); postEventToEventQueue(me); } } @@ -1531,4 +1546,18 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { } } + @Override + protected int getScale() { + return graphicsConfig.getScale(); + } + + @Override + protected int scaleUp(int x) { + return graphicsConfig.scaleUp(x); + } + + @Override + protected int scaleDown(int x) { + return graphicsConfig.scaleDown(x); + } } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java index fd6464b41d3..77fb29d3a97 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java @@ -29,6 +29,7 @@ import java.awt.*; import java.awt.event.ComponentEvent; import java.awt.event.FocusEvent; import java.awt.event.WindowEvent; +import java.awt.geom.AffineTransform; import java.awt.peer.ComponentPeer; import java.awt.peer.WindowPeer; @@ -750,10 +751,10 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, private Point queryXLocation() { - return XlibUtil.translateCoordinates( - getContentWindow(), - XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()), - new Point(0, 0)); + return XlibUtil.translateCoordinates(getContentWindow(), XlibWrapper + .RootWindow(XToolkit.getDisplay(), + getScreenNumber()), + new Point(0, 0), getScale()); } protected Point getNewLocation(XConfigureEvent xe, int leftInset, int topInset) { @@ -764,7 +765,8 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, Point newLocation = targetBounds.getLocation(); if (xe.get_send_event() || runningWM == XWM.NO_WM || XWM.isNonReparentingWM()) { // Location, Client size + insets - newLocation = new Point(xe.get_x() - leftInset, xe.get_y() - topInset); + newLocation = new Point(scaleDown(xe.get_x()) - leftInset, + scaleDown(xe.get_y()) - topInset); } else { // ICCCM 4.1.5 states that a real ConfigureNotify will be sent when // a window is resized but the client can not tell if the window was @@ -807,12 +809,12 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, * See getNewLocation() for the details. */ Point newLocation = getNewLocation(xe, 0, 0); - xe.set_x(newLocation.x); - xe.set_y(newLocation.y); - checkIfOnNewScreen(new Rectangle(xe.get_x(), - xe.get_y(), - xe.get_width(), - xe.get_height())); + xe.set_x(scaleUp(newLocation.x)); + xe.set_y(scaleUp(newLocation.y)); + checkIfOnNewScreen(new Rectangle(newLocation.x, + newLocation.y, + scaleDown(xe.get_width()), + scaleDown(xe.get_height()))); // Don't call super until we've handled a screen change. Otherwise // there could be a race condition in which a ComponentListener could @@ -2115,7 +2117,9 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, XCrossingEvent xce = xev.get_xcrossing(); if (grabLog.isLoggable(PlatformLogger.Level.FINE)) { grabLog.fine("{0}, when grabbed {1}, contains {2}", - xce, isGrabbed(), containsGlobal(xce.get_x_root(), xce.get_y_root())); + xce, isGrabbed(), + containsGlobal(scaleDown(xce.get_x_root()), + scaleDown(xce.get_y_root()))); } if (isGrabbed()) { // When window is grabbed, all events are dispatched to @@ -2141,7 +2145,9 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, XMotionEvent xme = xev.get_xmotion(); if (grabLog.isLoggable(PlatformLogger.Level.FINER)) { grabLog.finer("{0}, when grabbed {1}, contains {2}", - xme, isGrabbed(), containsGlobal(xme.get_x_root(), xme.get_y_root())); + xme, isGrabbed(), + containsGlobal(scaleDown(xme.get_x_root()), + scaleDown(xme.get_y_root()))); } if (isGrabbed()) { boolean dragging = false; @@ -2166,9 +2172,10 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, // So, I do not want to implement complicated logic for better retargeting. target = pressTarget.isVisible() ? pressTarget : this; xme.set_window(target.getWindow()); - Point localCoord = target.toLocal(xme.get_x_root(), xme.get_y_root()); - xme.set_x(localCoord.x); - xme.set_y(localCoord.y); + Point localCoord = target.toLocal(scaleDown(xme.get_x_root()), + scaleDown(xme.get_y_root())); + xme.set_x(scaleUp(localCoord.x)); + xme.set_y(scaleUp(localCoord.y)); } if (grabLog.isLoggable(PlatformLogger.Level.FINER)) { grabLog.finer(" - Grab event target {0}", target); @@ -2182,7 +2189,9 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, // note that we need to pass dragging events to the grabber (6390326) // see comment above for more inforamtion. - if (!containsGlobal(xme.get_x_root(), xme.get_y_root()) && !dragging) { + if (!containsGlobal(scaleDown(xme.get_x_root()), + scaleDown(xme.get_y_root())) + && !dragging) { // Outside of Java return; } @@ -2195,7 +2204,6 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, public void handleButtonPressRelease(XEvent xev) { XButtonEvent xbe = xev.get_xbutton(); - /* * Ignore the buttons above 20 due to the bit limit for * InputEvent.BUTTON_DOWN_MASK. @@ -2206,7 +2214,11 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, } if (grabLog.isLoggable(PlatformLogger.Level.FINE)) { grabLog.fine("{0}, when grabbed {1}, contains {2} ({3}, {4}, {5}x{6})", - xbe, isGrabbed(), containsGlobal(xbe.get_x_root(), xbe.get_y_root()), getAbsoluteX(), getAbsoluteY(), getWidth(), getHeight()); + xbe, isGrabbed(), + containsGlobal(scaleDown(xbe.get_x_root()), + scaleDown(xbe.get_y_root())), + getAbsoluteX(), getAbsoluteY(), + getWidth(), getHeight()); } if (isGrabbed()) { // When window is grabbed, all events are dispatched to @@ -2232,9 +2244,10 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, // see 6390326 for more information. target = pressTarget.isVisible() ? pressTarget : this; xbe.set_window(target.getWindow()); - Point localCoord = target.toLocal(xbe.get_x_root(), xbe.get_y_root()); - xbe.set_x(localCoord.x); - xbe.set_y(localCoord.y); + Point localCoord = target.toLocal(scaleDown(xbe.get_x_root()), + scaleDown(xbe.get_y_root())); + xbe.set_x(scaleUp(localCoord.x)); + xbe.set_y(scaleUp(localCoord.y)); pressTarget = this; } if (target != null && target != getContentXWindow() && target != this) { @@ -2246,7 +2259,10 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, // Target is either us or our content window - // check that event is inside. 'Us' in case of // shell will mean that this will also filter out press on title - if ((target == this || target == getContentXWindow()) && !containsGlobal(xbe.get_x_root(), xbe.get_y_root())) { + if ((target == this || target == getContentXWindow()) + && !containsGlobal(scaleDown(xbe.get_x_root()), + scaleDown(xbe.get_y_root()))) + { // Outside this toplevel hierarchy // According to the specification of UngrabEvent, post it // when press occurs outside of the window and not on its owned windows diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XlibUtil.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XlibUtil.java index f06af9856ae..27d6eef57d7 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XlibUtil.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XlibUtil.java @@ -102,7 +102,7 @@ public class XlibUtil /** * Returns the bounds of the given window, in absolute coordinates */ - static Rectangle getWindowGeometry(long window) + static Rectangle getWindowGeometry(long window, int scale) { XToolkit.awtLock(); try @@ -126,7 +126,9 @@ public class XlibUtil long width = Native.getUInt(XlibWrapper.larg4); long height = Native.getUInt(XlibWrapper.larg5); - return new Rectangle(x, y, (int)width, (int)height); + return new Rectangle(scaleDown(x, scale), scaleDown(y, scale), + scaleDown((int) width, scale), + scaleDown((int) height, scale)); } finally { @@ -138,7 +140,7 @@ public class XlibUtil * Translates the given point from one window to another. Returns * null if the translation is failed */ - static Point translateCoordinates(long src, long dst, Point p) + static Point translateCoordinates(long src, long dst, Point p, int scale) { Point translated = null; @@ -146,7 +148,7 @@ public class XlibUtil try { XTranslateCoordinates xtc = - new XTranslateCoordinates(src, dst, p.x, p.y); + new XTranslateCoordinates(src, dst, p.x * scale, p.y * scale); try { int status = xtc.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance()); @@ -154,7 +156,8 @@ public class XlibUtil ((XErrorHandlerUtil.saved_error == null) || (XErrorHandlerUtil.saved_error.get_error_code() == XConstants.Success))) { - translated = new Point(xtc.get_dest_x(), xtc.get_dest_y()); + translated = new Point(scaleDown(xtc.get_dest_x(), scale), + scaleDown(xtc.get_dest_y(), scale)); } } finally @@ -174,9 +177,12 @@ public class XlibUtil * Translates the given rectangle from one window to another. * Returns null if the translation is failed */ - static Rectangle translateCoordinates(long src, long dst, Rectangle r) + static Rectangle translateCoordinates(long src, long dst, Rectangle r, + int scale) { - Point translatedLoc = translateCoordinates(src, dst, r.getLocation()); + Point translatedLoc = translateCoordinates(src, dst, r.getLocation(), + scale); + if (translatedLoc == null) { return null; @@ -406,4 +412,8 @@ public class XlibUtil return 1 << (7 + button); } } + + static int scaleDown(int x, int scale) { + return x / scale; + } } diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java index 9ac71d82993..1b3c4fa2e23 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java @@ -133,7 +133,7 @@ public class X11GraphicsConfig extends GraphicsConfiguration /** * Return the graphics device associated with this configuration. */ - public GraphicsDevice getDevice() { + public X11GraphicsDevice getDevice() { return screen; } @@ -256,7 +256,20 @@ public class X11GraphicsConfig extends GraphicsConfiguration * For image buffers, this Transform will be the Identity transform. */ public AffineTransform getDefaultTransform() { - return new AffineTransform(); + double scale = getScale(); + return AffineTransform.getScaleInstance(scale, scale); + } + + public int getScale() { + return getDevice().getScaleFactor(); + } + + public int scaleUp(int x) { + return x * getScale(); + } + + public int scaleDown(int x) { + return x / getScale(); } /** @@ -308,7 +321,14 @@ public class X11GraphicsConfig extends GraphicsConfiguration } public Rectangle getBounds() { - return pGetBounds(screen.getScreen()); + Rectangle rect = pGetBounds(screen.getScreen()); + if (getScale() != 1) { + rect.x = scaleDown(rect.x); + rect.y = scaleDown(rect.y); + rect.width = scaleDown(rect.width); + rect.height = scaleDown(rect.height); + } + return rect; } private native Rectangle pGetBounds(int screenNum); diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java index 56b4252f761..9f35f172014 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java @@ -43,6 +43,7 @@ import sun.java2d.xr.XRGraphicsConfig; import sun.java2d.loops.SurfaceType; import sun.awt.util.ThreadGroupUtils; +import sun.java2d.SunGraphicsEnvironment; import sun.misc.ManagedLocalsThread; /** @@ -63,9 +64,11 @@ public final class X11GraphicsDevice extends GraphicsDevice private SunDisplayChanger topLevels = new SunDisplayChanger(); private DisplayMode origDisplayMode; private boolean shutdownHookRegistered; + private final int scale; public X11GraphicsDevice(int screennum) { this.screen = screennum; + this.scale = initScaleFactor(); } /* @@ -279,6 +282,7 @@ public final class X11GraphicsDevice extends GraphicsDevice int width, int height, int displayMode); private static native void resetNativeData(int screen); + private static native int getNativeScaleFactor(int screen); /** * Returns true only if: @@ -509,6 +513,27 @@ public final class X11GraphicsDevice extends GraphicsDevice topLevels.add(client); } + public int getScaleFactor() { + return scale; + } + + private int initScaleFactor() { + + if (SunGraphicsEnvironment.isUIScaleEnabled()) { + + double debugScale = SunGraphicsEnvironment.getDebugScale(); + + if (debugScale >= 1) { + return (int) debugScale; + } + + int nativeScale = getNativeScaleFactor(screen); + return nativeScale >= 1 ? nativeScale : 1; + } + + return 1; + } + /** * Remove a DisplayChangeListener from this X11GraphicsDevice. */ diff --git a/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java b/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java index dcfd6325b35..aabdda0db1e 100644 --- a/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java +++ b/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceData.java @@ -244,7 +244,8 @@ public abstract class XRSurfaceData extends XSurfaceData { int width, int height, ColorModel cm, Image image, long drawable, - int transparency) { + int transparency, + boolean isTexture) { int depth; // If we have a 32 bit color model for the window it needs // alpha to support translucency of the window so we need @@ -267,7 +268,7 @@ public abstract class XRSurfaceData extends XSurfaceData { return new XRPixmapSurfaceData (gc, width, height, image, getSurfaceType(gc, transparency), cm, drawable, transparency, - XRUtils.getPictureFormatForTransparency(transparency), depth); + XRUtils.getPictureFormatForTransparency(transparency), depth, isTexture); } protected XRSurfaceData(X11ComponentPeer peer, XRGraphicsConfig gc, @@ -542,11 +543,16 @@ public abstract class XRSurfaceData extends XSurfaceData { } public static class XRWindowSurfaceData extends XRSurfaceData { + + protected final int scale; + public XRWindowSurfaceData(X11ComponentPeer peer, XRGraphicsConfig gc, SurfaceType sType) { super(peer, gc, sType, peer.getColorModel(), peer.getColorModel().getPixelSize(), Transparency.OPAQUE); + this.scale = gc.getScale(); + if (isXRDrawableValid()) { // If we have a 32 bit color model for the window it needs // alpha to support translucency of the window so we need @@ -571,6 +577,8 @@ public abstract class XRSurfaceData extends XSurfaceData { public Rectangle getBounds() { Rectangle r = peer.getBounds(); r.x = r.y = 0; + r.width *= scale; + r.height *= scale; return r; } @@ -596,6 +604,16 @@ public abstract class XRSurfaceData extends XSurfaceData { super.invalidate(); } + + @Override + public double getDefaultScaleX() { + return scale; + } + + @Override + public double getDefaultScaleY() { + return scale; + } } public static class XRInternalSurfaceData extends XRSurfaceData { @@ -627,18 +645,20 @@ public abstract class XRSurfaceData extends XSurfaceData { int width; int height; int transparency; + private final int scale; public XRPixmapSurfaceData(XRGraphicsConfig gc, int width, int height, Image image, SurfaceType sType, ColorModel cm, long drawable, int transparency, int pictFormat, - int depth) { + int depth, boolean isTexture) { super(null, gc, sType, cm, depth, transparency); - this.width = width; - this.height = height; + this.scale = isTexture ? 1 : gc.getDevice().getScaleFactor(); + this.width = width * scale; + this.height = height * scale; offscreenImage = image; this.transparency = transparency; - initSurface(depth, width, height, drawable, pictFormat); + initSurface(depth, this.width, this.height, drawable, pictFormat); initXRender(pictFormat); makePipes(); @@ -696,6 +716,16 @@ public abstract class XRSurfaceData extends XSurfaceData { public Object getDestination() { return offscreenImage; } + + @Override + public double getDefaultScaleX() { + return scale; + } + + @Override + public double getDefaultScaleY() { + return scale; + } } public long getGC() { diff --git a/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceDataProxy.java b/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceDataProxy.java index 091d26ee83b..ddc621a3f5e 100644 --- a/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceDataProxy.java +++ b/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSurfaceDataProxy.java @@ -59,8 +59,9 @@ public class XRSurfaceDataProxy extends SurfaceDataProxy implements Transparency public SurfaceData validateSurfaceData(SurfaceData srcData, SurfaceData cachedData, int w, int h) { if (cachedData == null) { - cachedData = XRSurfaceData.createData(xrgc, w, h, xrgc - .getColorModel(), null, 0, getTransparency()); + cachedData = XRSurfaceData.createData(xrgc, w, h, + xrgc.getColorModel(), null, 0, + getTransparency(), true); } return cachedData; } diff --git a/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRVolatileSurfaceManager.java b/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRVolatileSurfaceManager.java index 8c99f25b305..12a3034cf20 100644 --- a/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRVolatileSurfaceManager.java +++ b/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRVolatileSurfaceManager.java @@ -59,10 +59,10 @@ public class XRVolatileSurfaceManager extends VolatileSurfaceManager { drawable = ((Long)context).longValue(); } sData = XRSurfaceData.createData(gc, - vImg.getWidth(), - vImg.getHeight(), - cm, vImg, drawable, - vImg.getTransparency()); + vImg.getWidth(), + vImg.getHeight(), + cm, vImg, drawable, + vImg.getTransparency(), false); } catch (NullPointerException ex) { sData = null; } catch (OutOfMemoryError er) { diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c index a1c9fc27c44..6c9c2b49f01 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c @@ -2082,3 +2082,38 @@ Java_sun_awt_X11GraphicsDevice_exitFullScreenExclusive /** * End DisplayMode/FullScreen support */ + +int getScale(const char *name) { + char *uiScale = getenv(name); + if (uiScale != NULL) { + double scale = strtod(uiScale, NULL); + if (errno == ERANGE || scale < 1) { + return -1; + } + return (int) scale; + } + return -1; +} + +/* + * Class: sun_awt_X11GraphicsDevice + * Method: getNativeScaleFactor + * Signature: (I)I + */ +JNIEXPORT jint JNICALL +Java_sun_awt_X11GraphicsDevice_getNativeScaleFactor + (JNIEnv *env, jobject this, jint screen) { + + // for debug purposes + static int scale = -2.0; + + if (scale == -2) { + scale = getScale("J2D_UISCALE"); + } + + if (scale >= 1) { + return scale; + } + + return getScale("GDK_SCALE"); +} diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c index eed0a4e40df..c9172a6e5f6 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_Robot.c @@ -210,6 +210,7 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env, jint jy, jint jwidth, jint jheight, + jint scale, jintArray pixelArray, jboolean isGtkSupported) { XImage *image; @@ -231,13 +232,18 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env, AWT_LOCK(); + jint sx = jx * scale; + jint sy = jy * scale; + jint swidth = jwidth * scale; + jint sheight = jheight * scale; + rootWindow = XRootWindow(awt_display, adata->awt_visInfo.screen); if (!XGetWindowAttributes(awt_display, rootWindow, &attr) - || jx + jwidth <= attr.x - || attr.x + attr.width <= jx - || jy + jheight <= attr.y - || attr.y + attr.height <= jy) { + || sx + swidth <= attr.x + || attr.x + attr.width <= sx + || sy + sheight <= attr.y + || attr.y + attr.height <= sy) { AWT_UNLOCK(); return; // Does not intersect with root window @@ -246,14 +252,14 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env, gboolean gtk_failed = TRUE; jint _x, _y; - jint x = MAX(jx, attr.x); - jint y = MAX(jy, attr.y); - jint width = MIN(jx + jwidth, attr.x + attr.width) - x; - jint height = MIN(jy + jheight, attr.y + attr.height) - y; + jint x = MAX(sx, attr.x); + jint y = MAX(sy, attr.y); + jint width = MIN(sx + swidth, attr.x + attr.width) - x; + jint height = MIN(sy + sheight, attr.y + attr.height) - y; - int dx = attr.x > jx ? attr.x - jx : 0; - int dy = attr.y > jy ? attr.y - jy : 0; + int dx = attr.x > sx ? attr.x - sx : 0; + int dy = attr.y > sy ? attr.y - sy : 0; int index; @@ -264,6 +270,19 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env, pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(NULL, root, NULL, x, y, 0, 0, width, height); + if (pixbuf && scale != 1) { + GdkPixbuf *scaledPixbuf; + x /= scale; + y /= scale; + width /= scale; + height /= scale; + dx /= scale; + dy /= scale; + scaledPixbuf = (*fp_gdk_pixbuf_scale_simple)(pixbuf, width, height, + GDK_INTERP_BILINEAR); + (*fp_g_object_unref)(pixbuf); + pixbuf = scaledPixbuf; + } if (pixbuf) { int nchan = (*fp_gdk_pixbuf_get_n_channels)(pixbuf); @@ -312,7 +331,7 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env, } if (gtk_failed) { - image = getWindowImage(awt_display, rootWindow, x, y, width, height); + image = getWindowImage(awt_display, rootWindow, sx, sy, swidth, sheight); ary = (*env)->GetPrimitiveArrayCritical(env, pixelArray, NULL); @@ -322,10 +341,16 @@ Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env, return; } + dx /= scale; + dy /= scale; + width /= scale; + height /= scale; + /* convert to Java ARGB pixels */ for (_y = 0; _y < height; _y++) { for (_x = 0; _x < width; _x++) { - jint pixel = (jint) XGetPixel(image, _x, _y); /* Note ignore upper + jint pixel = (jint) XGetPixel(image, _x * scale, _y * scale); + /* Note ignore upper * 32-bits on 64-bit * OSes. */ diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c index 6ef926e749a..3fa9151fb40 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c @@ -648,6 +648,8 @@ gboolean gtk2_load(JNIEnv *env) fp_gdk_pixmap_new = dl_symbol("gdk_pixmap_new"); fp_gdk_pixbuf_get_from_drawable = dl_symbol("gdk_pixbuf_get_from_drawable"); + fp_gdk_pixbuf_scale_simple = + dl_symbol("gdk_pixbuf_scale_simple"); fp_gdk_gc_new = dl_symbol("gdk_gc_new"); fp_gdk_rgb_gc_set_foreground = dl_symbol("gdk_rgb_gc_set_foreground"); diff --git a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h index 06cf8bd5261..10f32dc3e36 100644 --- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h +++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h @@ -270,6 +270,13 @@ typedef enum G_PARAM_PRIVATE = 1 << 5 } GParamFlags; +typedef enum { + GDK_INTERP_NEAREST, + GDK_INTERP_TILES, + GDK_INTERP_BILINEAR, + GDK_INTERP_HYPER +} GdkInterpType; + /* We define all structure pointers to be void* */ typedef void GError; typedef void GMainContext; @@ -787,6 +794,8 @@ GdkColorspace (*fp_gdk_pixbuf_get_colorspace)(const GdkPixbuf *pixbuf); GdkPixbuf *(*fp_gdk_pixbuf_get_from_drawable)(GdkPixbuf *dest, GdkDrawable *src, GdkColormap *cmap, int src_x, int src_y, int dest_x, int dest_y, int width, int height); +GdkPixbuf *(*fp_gdk_pixbuf_scale_simple)(GdkPixbuf *src, + int dest_width, int dest_heigh, GdkInterpType interp_type); void (*fp_gtk_widget_destroy)(GtkWidget *widget); diff --git a/jdk/test/java/awt/hidpi/properties/HiDPIPropertiesLinuxTest.java b/jdk/test/java/awt/hidpi/properties/HiDPIPropertiesLinuxTest.java new file mode 100644 index 00000000000..aba2dc1f87c --- /dev/null +++ b/jdk/test/java/awt/hidpi/properties/HiDPIPropertiesLinuxTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import javax.swing.UIManager; + +/* @test + * @bug 8137571 + * @summary Linux HiDPI Graphics support + * @author Alexander Scherbatiy + * @requires (os.family == "linux") + * @run main/othervm -Dsun.java2d.uiScale.enabled=false + * -Dsun.java2d.uiScale=2 + * HiDPIPropertiesLinuxTest UISCALE_DISABLED + * HiDPIPropertiesTest UISCALE_DISABLED + * @run main/othervm -Dsun.java2d.uiScale.enabled=true + * -Dsun.java2d.uiScale=3 + * HiDPIPropertiesLinuxTest UISCALE_3 + * @run main/othervm -Dsun.java2d.uiScale=4 + * HiDPIPropertiesLinuxTest UISCALE_4 + */ +public class HiDPIPropertiesLinuxTest { + + public static void main(String[] args) throws Exception { + + try { + UIManager.setLookAndFeel( + "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); + } catch (Exception e) { + return; + } + + String testCase = args[0]; + switch (testCase) { + case "UISCALE_DISABLED": + testScale(1.0, 1.0); + break; + case "UISCALE_3": + testScale(3.0, 3.0); + break; + case "UISCALE_4": + testScale(4.0, 4.0); + break; + default: + throw new RuntimeException("Unknown test case: " + testCase); + } + } + + private static void testScale(double scaleX, double scaleY) { + + Dialog dialog = new Dialog((Frame) null, true) { + + @Override + public void paint(Graphics g) { + super.paint(g); + AffineTransform tx = ((Graphics2D) g).getTransform(); + dispose(); + if (scaleX != tx.getScaleX() || scaleY != tx.getScaleY()) { + throw new RuntimeException(String.format("Wrong scale:" + + "[%f, %f] instead of [%f, %f].", + tx.getScaleX(), tx.getScaleY(), scaleX, scaleY)); + } + } + }; + dialog.setSize(200, 300); + dialog.setVisible(true); + } +} From 00b0a8c46bca160e720ce84e73b019f5bb1a6bbb Mon Sep 17 00:00:00 2001 From: Rajeev Chamyal Date: Fri, 13 Nov 2015 18:46:16 +0400 Subject: [PATCH 098/260] 8079253: Test javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java fails Reviewed-by: serb, alexsch --- .../swing/SwingUtilities/TestBadBreak/TestBadBreak.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jdk/test/javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java b/jdk/test/javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java index 59806a33a0a..a4d1e0fb781 100644 --- a/jdk/test/javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java +++ b/jdk/test/javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java @@ -36,10 +36,10 @@ import static java.awt.image.BufferedImage.TYPE_INT_ARGB; /** * @test - * @bug 8015085 + * @bug 8015085 8079253 * @summary Shortening via " ... " is broken for Strings containing a combining * diaeresis. - * @author Sergey Bylokhov + * @run main TestBadBreak */ public class TestBadBreak { @@ -79,6 +79,7 @@ public class TestBadBreak { g2d.dispose(); } }; + label.setOpaque(true); frame.getContentPane().add(label); frame.setBounds(200, 200, 200, 90); } From 57ee6fa3abb6ce2159ac1c85438aa503969e493d Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Fri, 13 Nov 2015 16:50:39 -0500 Subject: [PATCH 099/260] 8027429: Add diagnostic command VM.info to get hs_err print-out Refactored hs_err reporting code so that it can be used for VM.info safely Co-authored-by: David Buck Reviewed-by: dholmes, hseigel --- .../share/vm/services/diagnosticCommand.cpp | 5 + .../share/vm/services/diagnosticCommand.hpp | 17 ++ hotspot/src/share/vm/utilities/vmError.cpp | 198 +++++++++++++++--- hotspot/src/share/vm/utilities/vmError.hpp | 6 +- 4 files changed, 196 insertions(+), 30 deletions(-) diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index 1d9ddf4de4e..d3ae517d795 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -56,6 +56,7 @@ void DCmdRegistrant::register_dcmds(){ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); @@ -323,6 +324,10 @@ int VMUptimeDCmd::num_arguments() { } } +void VMInfoDCmd::execute(DCmdSource source, TRAPS) { + VMError::print_vm_info(_output); +} + void SystemGCDCmd::execute(DCmdSource source, TRAPS) { if (!DisableExplicitGC) { Universe::heap()->collect(GCCause::_dcmd_gc_run); diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp index d71bff40bd4..3b0505a7347 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.hpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp @@ -213,6 +213,23 @@ public: virtual void execute(DCmdSource source, TRAPS); }; +class VMInfoDCmd : public DCmd { +public: + VMInfoDCmd(outputStream* output, bool heap) : DCmd(output, heap) { } + static const char* name() { return "VM.info"; } + static const char* description() { + return "Print information about JVM environment and status."; + } + static const char* impact() { return "Low"; } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments() { return 0; } + virtual void execute(DCmdSource source, TRAPS); +}; + class SystemGCDCmd : public DCmd { public: SystemGCDCmd(outputStream* output, bool heap) : DCmd(output, heap) { } diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index 45cc47152f8..6af19370b7c 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -201,7 +201,7 @@ void VMError::print_stack_trace(outputStream* st, JavaThread* jt, #endif // ZERO } -void VMError::print_oom_reasons(outputStream* st) { +static void print_oom_reasons(outputStream* st) { st->print_cr("# Possible reasons:"); st->print_cr("# The system is out of physical RAM or swap space"); st->print_cr("# In 32 bit mode, the process size limit was hit"); @@ -217,7 +217,7 @@ void VMError::print_oom_reasons(outputStream* st) { st->print_cr("# This output file may be truncated or incomplete."); } -const char* VMError::gc_mode() { +static const char* gc_mode() { if (UseG1GC) return "g1 gc"; if (UseParallelGC) return "parallel gc"; if (UseConcMarkSweepGC) return "concurrent mark sweep gc"; @@ -225,6 +225,33 @@ const char* VMError::gc_mode() { return "ERROR in GC mode"; } +static void report_vm_version(outputStream* st, char* buf, int buflen) { + // VM version + st->print_cr("#"); + JDK_Version::current().to_string(buf, buflen); + const char* runtime_name = JDK_Version::runtime_name() != NULL ? + JDK_Version::runtime_name() : ""; + const char* runtime_version = JDK_Version::runtime_version() != NULL ? + JDK_Version::runtime_version() : ""; + st->print_cr("# JRE version: %s (%s) (build %s)", runtime_name, buf, runtime_version); + // This is the long version with some default settings added + st->print_cr("# Java VM: %s (%s, %s%s%s%s%s, %s, %s)", + Abstract_VM_Version::vm_name(), + Abstract_VM_Version::vm_release(), + Abstract_VM_Version::vm_info_string(), + TieredCompilation ? ", tiered" : "", +#if INCLUDE_JVMCI + EnableJVMCI ? ", jvmci" : "", + UseJVMCICompiler ? ", jvmci compiler" : "", +#else + "", "", +#endif + UseCompressedOops ? ", compressed oops" : "", + gc_mode(), + Abstract_VM_Version::vm_platform_string() + ); +} + // This is the main function to report a fatal error. Only one thread can // call this function, so we don't need to worry about MT-safety. But it's // possible that the error handler itself may crash or die on an internal @@ -401,30 +428,7 @@ void VMError::report(outputStream* st, bool _verbose) { STEP(90, "(printing Java version string)") - // VM version - st->print_cr("#"); - JDK_Version::current().to_string(buf, sizeof(buf)); - const char* runtime_name = JDK_Version::runtime_name() != NULL ? - JDK_Version::runtime_name() : ""; - const char* runtime_version = JDK_Version::runtime_version() != NULL ? - JDK_Version::runtime_version() : ""; - st->print_cr("# JRE version: %s (%s) (build %s)", runtime_name, buf, runtime_version); - // This is the long version with some default settings added - st->print_cr("# Java VM: %s (%s, %s%s%s%s%s, %s, %s)", - Abstract_VM_Version::vm_name(), - Abstract_VM_Version::vm_release(), - Abstract_VM_Version::vm_info_string(), - TieredCompilation ? ", tiered" : "", -#if INCLUDE_JVMCI - EnableJVMCI ? ", jvmci" : "", - UseJVMCICompiler ? ", jvmci compiler" : "", -#else - "", "", -#endif - UseCompressedOops ? ", compressed oops" : "", - gc_mode(), - Abstract_VM_Version::vm_platform_string() - ); + report_vm_version(st, buf, sizeof(buf)); STEP(100, "(printing problematic frame)") @@ -715,7 +719,6 @@ void VMError::report(outputStream* st, bool _verbose) { if (_verbose && Universe::is_fully_initialized()) { Universe::heap()->print_on_error(st); st->cr(); - st->print_cr("Polling page: " INTPTR_FORMAT, p2i(os::get_polling_page())); st->cr(); } @@ -826,6 +829,147 @@ void VMError::report(outputStream* st, bool _verbose) { # undef END } +// Report for the vm_info_cmd. This prints out the information above omitting +// crash and thread specific information. If output is added above, it should be added +// here also, if it is safe to call during a running process. +void VMError::print_vm_info(outputStream* st) { + + char buf[O_BUFLEN]; + report_vm_version(st, buf, sizeof(buf)); + + // STEP("(printing summary)") + + st->cr(); + st->print_cr("--------------- S U M M A R Y ------------"); + st->cr(); + + // STEP("(printing VM option summary)") + + // VM options + Arguments::print_summary_on(st); + st->cr(); + + // STEP("(printing summary machine and OS info)") + + os::print_summary_info(st, buf, sizeof(buf)); + + // STEP("(printing date and time)") + + os::print_date_and_time(st, buf, sizeof(buf)); + + // Skip: STEP("(printing thread)") + + // STEP("(printing process)") + + st->cr(); + st->print_cr("--------------- P R O C E S S ---------------"); + st->cr(); + + // STEP("(printing number of OutOfMemoryError and StackOverflow exceptions)") + + if (Exceptions::has_exception_counts()) { + st->print_cr("OutOfMemory and StackOverflow Exception counts:"); + Exceptions::print_exception_counts_on_error(st); + st->cr(); + } + + // STEP("(printing compressed oops mode") + + if (UseCompressedOops) { + Universe::print_compressed_oops_mode(st); + if (UseCompressedClassPointers) { + Metaspace::print_compressed_class_space(st); + } + st->cr(); + } + + // STEP("(printing heap information)") + + if (Universe::is_fully_initialized()) { + Universe::heap()->print_on_error(st); + st->cr(); + st->print_cr("Polling page: " INTPTR_FORMAT, p2i(os::get_polling_page())); + st->cr(); + } + + // STEP("(printing code cache information)") + + if (Universe::is_fully_initialized()) { + // print code cache information before vm abort + CodeCache::print_summary(st); + st->cr(); + } + + // STEP("(printing ring buffers)") + + Events::print_all(st); + st->cr(); + + // STEP("(printing dynamic libraries)") + + // dynamic libraries, or memory map + os::print_dll_info(st); + st->cr(); + + // STEP("(printing VM options)") + + // VM options + Arguments::print_on(st); + st->cr(); + + // STEP("(printing warning if internal testing API used)") + + if (WhiteBox::used()) { + st->print_cr("Unsupported internal testing APIs have been used."); + st->cr(); + } + + // STEP("(printing all environment variables)") + + os::print_environment_variables(st, env_list); + st->cr(); + + // STEP("(printing signal handlers)") + + os::print_signal_handlers(st, buf, sizeof(buf)); + st->cr(); + + // STEP("(Native Memory Tracking)") + + MemTracker::error_report(st); + + // STEP("(printing system)") + + st->cr(); + st->print_cr("--------------- S Y S T E M ---------------"); + st->cr(); + + // STEP("(printing OS information)") + + os::print_os_info(st); + st->cr(); + + // STEP("(printing CPU info)") + + os::print_cpu_info(st, buf, sizeof(buf)); + st->cr(); + + // STEP("(printing memory info)") + + os::print_memory_info(st); + st->cr(); + + // STEP("(printing internal vm info)") + + st->print_cr("vm_info: %s", Abstract_VM_Version::internal_vm_info_string()); + st->cr(); + + // print a defined marker to show that error handling finished correctly. + // STEP("(printing end marker)") + + st->print_cr("END."); +} + volatile intptr_t VMError::first_error_tid = -1; // An error could happen before tty is initialized or after it has been diff --git a/hotspot/src/share/vm/utilities/vmError.hpp b/hotspot/src/share/vm/utilities/vmError.hpp index aa1d89ecea6..e7cce398fd3 100644 --- a/hotspot/src/share/vm/utilities/vmError.hpp +++ b/hotspot/src/share/vm/utilities/vmError.hpp @@ -88,9 +88,6 @@ class VMError : public AllStatic { static void print_stack_trace(outputStream* st, JavaThread* jt, char* buf, int buflen, bool verbose = false); - static const char* gc_mode(); - static void print_oom_reasons(outputStream* st); - static bool should_report_bug(unsigned int id) { return (id != OOM_MALLOC_ERROR) && (id != OOM_MMAP_ERROR); } @@ -110,6 +107,9 @@ public: // Record status of core/minidump static void record_coredump_status(const char* message, bool status); + // support for VM.info diagnostic command + static void print_vm_info(outputStream* st); + // main error reporting function static void report_and_die(int id, const char* message, const char* detail_fmt, va_list detail_args, Thread* thread, address pc, void* siginfo, void* context, From 2603ac8fdbca6376ed2a69b7aa7371da732e1ab0 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 16 Nov 2015 10:56:21 +0300 Subject: [PATCH 100/260] 8081491: The case print incomplete Reviewed-by: alexsch, rchamyal --- .../classes/javax/swing/TablePrintable.java | 29 ++- .../javax/swing/plaf/basic/BasicTableUI.java | 23 ++- .../print/PageFormat/ImageableAreaTest.java | 77 +++++++- .../javax/swing/JTable/JTableScrollTest.java | 182 ++++++++++++++++++ 4 files changed, 298 insertions(+), 13 deletions(-) create mode 100644 jdk/test/javax/swing/JTable/JTableScrollTest.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/TablePrintable.java b/jdk/src/java.desktop/share/classes/javax/swing/TablePrintable.java index 6b9053f4355..b47f8696662 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/TablePrintable.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/TablePrintable.java @@ -205,11 +205,9 @@ class TablePrintable implements Printable { */ public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { - // for easy access to these values final int imgWidth = (int)pageFormat.getImageableWidth(); final int imgHeight = (int)pageFormat.getImageableHeight(); - if (imgWidth <= 0) { throw new PrinterException("Width of printable area is too small."); } @@ -302,10 +300,12 @@ class TablePrintable implements Printable { // been divided by it int scaledWidth = (int)(imgWidth / sf); int scaledHeight = (int)((availableSpace - hclip.height) / sf); - // calculate the area of the table to be printed for this page findNextClip(scaledWidth, scaledHeight); + if (!((table.getBounds()).intersects(clip))) { + return NO_SUCH_PAGE; + } last++; } @@ -343,7 +343,6 @@ class TablePrintable implements Printable { tempRect.width = imgWidth; tempRect.height = availableSpace; g2d.clip(tempRect); - // if we have a scale factor, scale the graphics object to fit // the entire width if (sf != 1.0D) { @@ -389,7 +388,26 @@ class TablePrintable implements Printable { // draw a box around the table g2d.setColor(Color.BLACK); - g2d.drawRect(0, 0, clip.width, hclip.height + clip.height); + + // compute the visible portion of table and draw the rect around it + Rectangle visibleBounds = clip.intersection(table.getBounds()); + Point upperLeft = visibleBounds.getLocation(); + Point lowerRight = new Point(visibleBounds.x + visibleBounds.width, + visibleBounds.y + visibleBounds.height); + + int rMin = table.rowAtPoint(upperLeft); + int rMax = table.rowAtPoint(lowerRight); + if (rMin == -1) { + rMin = 0; + } + if (rMax == -1) { + rMax = table.getRowCount(); + } + int rowHeight = 0; + for(int visrow = rMin; visrow < rMax; visrow++) { + rowHeight += table.getRowHeight(visrow); + } + g2d.drawRect(0, 0, visibleBounds.width, hclip.height + rowHeight); // dispose the graphics copy g2d.dispose(); @@ -509,7 +527,6 @@ class TablePrintable implements Printable { if (++col >= colCount) { // reset col to 0 to indicate we're finished all columns col = 0; - break; } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTableUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTableUI.java index ef0c45463dd..73fd9a51340 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTableUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTableUI.java @@ -1812,9 +1812,11 @@ public class BasicTableUI extends TableUI boolean ltr = table.getComponentOrientation().isLeftToRight(); - Point upperLeft = clip.getLocation(); - Point lowerRight = new Point(clip.x + clip.width - 1, - clip.y + clip.height - 1); + // compute the visible part of table which needs to be painted + Rectangle visibleBounds = clip.intersection(bounds); + Point upperLeft = visibleBounds.getLocation(); + Point lowerRight = new Point(visibleBounds.x + visibleBounds.width - 1, + visibleBounds.y + visibleBounds.height - 1); int rMin = table.rowAtPoint(upperLeft); int rMax = table.rowAtPoint(lowerRight); @@ -1843,6 +1845,21 @@ public class BasicTableUI extends TableUI cMax = table.getColumnCount()-1; } + Container comp = SwingUtilities.getUnwrappedParent(table); + if (comp != null) { + comp = comp.getParent(); + } + + if (comp != null && !(comp instanceof JViewport) && !(comp instanceof JScrollPane)) { + // We did rMax-1 to paint the same number of rows that are drawn on console + // otherwise 1 extra row is printed per page than that are displayed + // when there is no scrollPane and we do printing of table + // but not when rmax is already pointing to index of last row + if (rMax != (table.getRowCount() - 1)) { + rMax = rMax - 1; + } + } + // Paint the grid. paintGrid(g, rMin, rMax, cMin, cMax); diff --git a/jdk/test/java/awt/print/PageFormat/ImageableAreaTest.java b/jdk/test/java/awt/print/PageFormat/ImageableAreaTest.java index f9e7b4bbea8..7bf37415e6e 100644 --- a/jdk/test/java/awt/print/PageFormat/ImageableAreaTest.java +++ b/jdk/test/java/awt/print/PageFormat/ImageableAreaTest.java @@ -45,7 +45,7 @@ import javax.swing.table.TableModel; /** * @test - * @bug 8044444 + * @bug 8044444 8081491 * @summary The output's 'Page-n' footer does not show completely * @author Alexandr Scherbatiy * @run main/manual ImageableAreaTest @@ -58,11 +58,13 @@ public class ImageableAreaTest { @Override public void run() { + createAndShowTestDialog( "1. Press the Print Table button\n" + " Java print dialog should appear.\n" + "2. Press the Print button on the Java Print dialog.\n" - + "2. Check that the page number is correctly printed.\n" + + "3. Check that the page number is correctly printed.\n" + + "4. Check only the visible part of the table is printed.\n" + "If so, press PASS, else press FAIL.", "Page number is not correctly printed!", ImageableAreaTest::printWithJavaPrintDialog); @@ -71,24 +73,47 @@ public class ImageableAreaTest { "1. Press the Print Table button\n" + " The table should be printed without the print dialog.\n" + "2. Check that the page number is correctly printed.\n" + + "3. Check only the visible part of the table is printed.\n" + "If so, press PASS, else press FAIL.", "Page number is not correctly printed!", ImageableAreaTest::printWithoutPrintDialog); + + createAndShowTestDialog( "1. Press the Print Table button\n" + " Java print dialog should appear.\n" + "2. Press the Print button on the Java Print dialog.\n" + "3. Check that the table has about half size of the printed page\n" + + "4. Check only the visible part of the table is printed.\n" + "If so, press PASS, else press FAIL.", "Custom imageable area is not correctly printed!", ImageableAreaTest::printWithCustomImageareaSize); + + createAndShowTestDialog( + "1. Press the Print Table button\n" + + " Java print dialog should appear.\n" + + "2. Press the Print button on the Java Print dialog.\n" + + "3. Check that the rows with different height is printed.\n" + + "4. Check only the visible part of the table is printed.\n" + + "If so, press PASS, else press FAIL.", + "Row with different height is not correctly printed!", + ImageableAreaTest::printDifferentRowHeight); + + createAndShowTestDialog( + "1. Press the Print Table button\n" + + " Java print dialog should appear.\n" + + "2. Press the Print button on the Java Print dialog.\n" + + "3. Check that the only 1 row is shown & printed.\n" + + "If so, press PASS, else press FAIL.", + "Only 1 Row is not correctly printed!", + ImageableAreaTest::printOneRowWithJavaPrintDialog); } }); } private static void printWithJavaPrintDialog() { - final JTable table = createAuthorTable(42); + final JTable table = createAuthorTable(50); Printable printable = table.getPrintable( JTable.PrintMode.NORMAL, new MessageFormat("Author Table"), @@ -110,7 +135,7 @@ public class ImageableAreaTest { private static void printWithoutPrintDialog() { - final JTable table = createAuthorTable(42); + final JTable table = createAuthorTable(50); PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet(); pras.add(new Copies(1)); @@ -132,6 +157,50 @@ public class ImageableAreaTest { } } + private static void printDifferentRowHeight() { + final JTable table = createAuthorTable(50); + table.setRowHeight(15, table.getRowHeight(15)+10); + Printable printable = table.getPrintable( + JTable.PrintMode.NORMAL, + new MessageFormat("Author Table"), + new MessageFormat("Page - {0}")); + + PrinterJob job = PrinterJob.getPrinterJob(); + job.setPrintable(printable); + + boolean printAccepted = job.printDialog(); + if (printAccepted) { + try { + job.print(); + closeFrame(); + } catch (PrinterException e) { + throw new RuntimeException(e); + } + } + + } + + private static void printOneRowWithJavaPrintDialog() { + final JTable table = createAuthorTable(1); + Printable printable = table.getPrintable( + JTable.PrintMode.NORMAL, + new MessageFormat("Author Table"), + new MessageFormat("Page - {0}")); + + PrinterJob job = PrinterJob.getPrinterJob(); + job.setPrintable(printable); + + boolean printAccepted = job.printDialog(); + if (printAccepted) { + try { + job.print(); + closeFrame(); + } catch (PrinterException e) { + throw new RuntimeException(e); + } + } + } + private static void printWithCustomImageareaSize() { final JTable table = createAuthorTable(18); PrintRequestAttributeSet printAttributes = new HashPrintRequestAttributeSet(); diff --git a/jdk/test/javax/swing/JTable/JTableScrollTest.java b/jdk/test/javax/swing/JTable/JTableScrollTest.java new file mode 100644 index 00000000000..5e0461cc9f9 --- /dev/null +++ b/jdk/test/javax/swing/JTable/JTableScrollTest.java @@ -0,0 +1,182 @@ +/* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.Color; +import java.awt.Dialog; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JFrame; +import javax.swing.JTable; +import javax.swing.JTextArea; +import javax.swing.JButton; +import javax.swing.table.TableModel; +import javax.swing.JScrollPane; +import javax.swing.table.AbstractTableModel; +import javax.swing.SwingUtilities; + +/** + * @test + * @bug 8081491 + * @summary Scrolling a JTable creates artifacts + * @run main/manual JTableScrollTest + */ +public class JTableScrollTest { + static JFrame frame = new JFrame(); + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + doTest(JTableScrollTest::createTable); + } + }); + } + + private static void createTable() { + // final + final String[] names = { + new String("first_name"), + new String("last_name"), + new String("favorite_color"), + new String("favorite_food") + }; + + // Create the dummy data (a few rows of names) + final Object[][] data = { + {"Mike", "Albers", "green", "strawberry"}, + {"Mark", "Andrews", "blue", "grapes"}, + {"Brian", "Beck", "black", "raspberry"}, + {"Lara", "Bunni", "red", "strawberry"}, + {"Roger", "Brinkley", "blue", "peach"}, + {"Brent", "Christian", "black", "broccoli"}, + {"Mark", "Davidson", "darkgreen", "asparagus"}, + {"Jeff", "Dinkins", "blue", "kiwi"}, + {"Ewan", "Dinkins", "yellow", "strawberry"}, + {"Amy", "Fowler", "violet", "raspberry"}, + {"Hania", "Gajewska", "purple", "raspberry"}, + {"David", "Geary", "blue", "watermelon"}, + {"Ryan", "Gosling", "pink", "donut"}, + {"Eric", "Hawkes", "blue", "pickle"}, + {"Shannon", "Hickey", "green", "grapes"}, + {"Earl", "Johnson", "green", "carrot"}, + {"Robi", "Khan", "green", "apple"}, + {"Robert", "Kim", "blue", "strawberry"}, + {"Janet", "Koenig", "turquoise", "peach"}, + {"Jeff", "Kesselman", "blue", "pineapple"}, + {"Onno", "Kluyt", "orange", "broccoli"}, + {"Peter", "Korn", "sunpurple", "sparegrass"}, + {"Rick", "Levenson", "black", "raspberry"}, + {"Brian", "Lichtenwalter", "blue", "pear"}, + {"Malini", "Minasandram", "beige", "corn"}, + {"Michael", "Martak", "green", "strawberry"}, + {"David", "Mendenhall", "forestgreen", "peach"}, + {"Phil", "Milne", "pink", "banana"}, + {"Lynn", "Monsanto", "cybergreen", "peach"}, + {"Hans", "Muller", "rustred", "pineapple"}, + {"Joshua", "Outwater", "blue", "pineapple"}, + {"Tim", "Prinzing", "blue", "pepper"}, + {"Raj", "Premkumar", "blue", "broccoli"}, + {"Howard", "Rosen", "green", "strawberry"}, + {"Ray", "Ryan", "black", "banana"}, + {"Georges", "Saab", "aqua", "cantaloupe"}, + {"Tom", "Santos", "blue", "pepper"}, + {"Rich", "Schiavi", "blue", "pepper"}, + {"Nancy", "Schorr", "green", "watermelon"}, + {"Keith", "Sprochi", "darkgreen", "watermelon"}, + {"Matt", "Tucker", "eblue", "broccoli"}, + {"Dmitri", "Trembovetski", "red", "tomato"}, + {"Scott", "Violet", "violet", "banana"}, + {"Kathy", "Walrath", "darkgreen", "pear"}, + }; + + // Create a model of the data. + TableModel dataModel = new AbstractTableModel() { + public int getColumnCount() { return names.length; } + public int getRowCount() { return data.length;} + public Object getValueAt(int row, int col) {return data[row][col];} + public String getColumnName(int column) {return names[column];} + public Class getColumnClass(int c) {return getValueAt(0, c).getClass();} + public boolean isCellEditable(int row, int col) {return col != 5;} + public void setValueAt(Object aValue, int row, int column) { data[row][column] = aValue; } + }; + + // Create the table + JTable tableView = new JTable(dataModel); + tableView.setBackground(Color.WHITE); + tableView.setForeground(Color.BLACK); + tableView.setSize(600, 800); + JScrollPane scrollpane = new JScrollPane(tableView); + frame.add(scrollpane); + frame.pack(); + frame.setVisible(true); + } + + private static void doTest(Runnable action) { + String description = + "JTable with rows will be displayed along with scrollbar.\n" + + "Scroll the table. Verify no arifacts are shown and rows.\n" + + " are correctly displayed."; + final JDialog dialog = new JDialog(); + dialog.setTitle("ScrollArtifactTest "); + JTextArea textArea = new JTextArea(description); + textArea.setEditable(false); + final JButton testButton = new JButton("Create Table"); + final JButton passButton = new JButton("PASS"); + passButton.setEnabled(false); + passButton.addActionListener((e) -> { + dialog.dispose(); + if (frame != null) { + frame.setVisible(false); + frame.dispose(); + } + }); + final JButton failButton = new JButton("FAIL"); + failButton.setEnabled(false); + failButton.addActionListener((e) -> { + dialog.dispose(); + if (frame != null) { + frame.setVisible(false); + frame.dispose(); + } + throw new RuntimeException("Scrollbar artifact shown"); + }); + testButton.addActionListener((e) -> { + testButton.setEnabled(false); + action.run(); + passButton.setEnabled(true); + failButton.setEnabled(true); + }); + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(textArea, BorderLayout.CENTER); + JPanel buttonPanel = new JPanel(new FlowLayout()); + buttonPanel.add(testButton); + buttonPanel.add(passButton); + buttonPanel.add(failButton); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + dialog.add(mainPanel); + dialog.pack(); + dialog.setVisible(true); + } + + +} From 694262c33baed0f71c527348d71074c46991a621 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Mon, 16 Nov 2015 10:18:18 +0100 Subject: [PATCH 101/260] 8042997: Make intrinsic some or all check index/range methods Objects.checkIndex() intrinsic Reviewed-by: psandoz, shade --- .../share/classes/java/util/Objects.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/Objects.java b/jdk/src/java.base/share/classes/java/util/Objects.java index 65089553b87..dbee22b2cef 100644 --- a/jdk/src/java.base/share/classes/java/util/Objects.java +++ b/jdk/src/java.base/share/classes/java/util/Objects.java @@ -27,6 +27,7 @@ package java.util; import java.util.function.BiFunction; import java.util.function.Supplier; +import jdk.internal.HotSpotIntrinsicCandidate; /** * This class consists of {@code static} utility methods for operating @@ -416,14 +417,14 @@ public final class Objects { * @throws IndexOutOfBoundsException if the {@code index} is out of bounds * and the exception mapping function is {@code null} * @since 9 - */ - /* - @HotSpotIntrinsicCandidate - This method will be made intrinsic in C2 to guide HotSpot to perform - unsigned comparisons of the index and length when it is known the length is - a non-negative value (such as that of an array length or from the upper - bound of a loop) + * + * @implNote + * This method is made intrinsic in optimizing compilers to guide + * them to perform unsigned comparisons of the index and length + * when it is known the length is a non-negative value (such as + * that of an array length or from the upper bound of a loop) */ + @HotSpotIntrinsicCandidate public static int checkIndex(int index, int length, BiFunction oobe) throws T, IndexOutOfBoundsException { From 7d7c9563972879de5cb6240bb6f1b8393dfe1a1d Mon Sep 17 00:00:00 2001 From: Rajeev Chamyal Date: Mon, 16 Nov 2015 15:03:17 +0400 Subject: [PATCH 102/260] 6288609: JInternalFrame.setDefaultCloseOperation() interferes with "close" behavior Reviewed-by: psadhukhan, alexsch --- .../classes/javax/swing/JInternalFrame.java | 5 - .../6288609/TestJInternalFrameDispose.java | 158 ++++++++++++++++++ 2 files changed, 158 insertions(+), 5 deletions(-) create mode 100644 jdk/test/javax/swing/JInternalFrame/6288609/TestJInternalFrameDispose.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JInternalFrame.java b/jdk/src/java.desktop/share/classes/javax/swing/JInternalFrame.java index 2297fdacdc0..6d82ffda5af 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JInternalFrame.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JInternalFrame.java @@ -1753,11 +1753,6 @@ public class JInternalFrame extends JComponent implements if (isVisible()) { setVisible(false); } - if (isSelected()) { - try { - setSelected(false); - } catch (PropertyVetoException pve) {} - } if (!isClosed) { firePropertyChange(IS_CLOSED_PROPERTY, Boolean.FALSE, Boolean.TRUE); isClosed = true; diff --git a/jdk/test/javax/swing/JInternalFrame/6288609/TestJInternalFrameDispose.java b/jdk/test/javax/swing/JInternalFrame/6288609/TestJInternalFrameDispose.java new file mode 100644 index 00000000000..8da7c1646c5 --- /dev/null +++ b/jdk/test/javax/swing/JInternalFrame/6288609/TestJInternalFrameDispose.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6288609 + * @summary JInternalFrame.setDefaultCloseOperation() interferes with "close" + behavior + * @library ../../regtesthelpers + * @build Util + * @run main TestJInternalFrameDispose + */ +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import javax.swing.JFrame; +import javax.swing.JDesktopPane; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JInternalFrame; +import javax.swing.SwingUtilities; +import javax.swing.event.InternalFrameAdapter; +import javax.swing.event.InternalFrameEvent; + +public class TestJInternalFrameDispose { + + private static JDesktopPane desktopPane; + private static JFrame frame = new JFrame("Test Frame"); + private static int count = 0; + private static JMenu menu; + private static JMenuBar menuBar; + private static JMenuItem menuItem; + private static Robot robot; + private static JInternalFrame internalFrame; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + createUI(); + } + }); + + robot.waitForIdle(); + executeTest(); + dispose(); + } + + private static void createUI() { + + desktopPane = new JDesktopPane(); + frame.getContentPane().add(desktopPane); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + menuBar = new JMenuBar(); + frame.setJMenuBar(menuBar); + + menu = new JMenu("File"); + menuBar.add(menu); + + menuItem = new JMenuItem("New Child"); + menuItem.addActionListener( + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + JInternalFrame f = new JInternalFrame("Child " + + (++count), true, true, true, true); + f.setDefaultCloseOperation( + JInternalFrame.DO_NOTHING_ON_CLOSE); + f.addInternalFrameListener(new InternalFrameAdapter() { + @Override + public void internalFrameClosing( + InternalFrameEvent e) { + e.getInternalFrame().dispose(); + } + }); + f.setSize(200, 300); + f.setLocation(count * 20, count * 20); + desktopPane.add(f); + f.setVisible(true); + } + }); + menu.add(menuItem); + + frame.setSize(400, 500); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void executeTest() throws Exception { + + Point point = Util.getCenterPoint(menu); + performMouseOperations(point); + point = Util.getCenterPoint(menuItem); + performMouseOperations(point); + point = Util.getCenterPoint(menu); + performMouseOperations(point); + point = Util.getCenterPoint(menuItem); + performMouseOperations(point); + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + internalFrame = desktopPane.getSelectedFrame(); + internalFrame.doDefaultCloseAction(); + internalFrame = desktopPane.getSelectedFrame(); + } + }); + + robot.delay(2000); + if (internalFrame == null) { + dispose(); + throw new RuntimeException("Test Failed"); + } + } + + private static void dispose() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + frame.dispose(); + } + }); + } + + private static void performMouseOperations(Point point) { + robot.mouseMove(point.x, point.y); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.delay(1000); + robot.waitForIdle(); + } +} From 350b04eab2f7db7dc3e3abf932df39356ae963a4 Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Mon, 16 Nov 2015 14:19:10 +0100 Subject: [PATCH 103/260] 8141551: C2 can not handle returns with inccompatible interface arrays Reviewed-by: kvn --- hotspot/src/share/vm/opto/cfgnode.cpp | 25 +- hotspot/src/share/vm/opto/parse1.cpp | 28 +- hotspot/src/share/vm/opto/type.cpp | 46 ++- hotspot/src/share/vm/opto/type.hpp | 5 + .../TestMeetIncompatibleInterfaceArrays.java | 353 ++++++++++++++++++ 5 files changed, 438 insertions(+), 19 deletions(-) create mode 100644 hotspot/test/compiler/types/TestMeetIncompatibleInterfaceArrays.java diff --git a/hotspot/src/share/vm/opto/cfgnode.cpp b/hotspot/src/share/vm/opto/cfgnode.cpp index 8cb6488a535..454a29636a6 100644 --- a/hotspot/src/share/vm/opto/cfgnode.cpp +++ b/hotspot/src/share/vm/opto/cfgnode.cpp @@ -984,7 +984,7 @@ const Type *PhiNode::Value( PhaseTransform *phase ) const { #ifdef ASSERT // The following logic has been moved into TypeOopPtr::filter. const Type* jt = t->join_speculative(_type); - if( jt->empty() ) { // Emptied out??? + if (jt->empty()) { // Emptied out??? // Check for evil case of 't' being a class and '_type' expecting an // interface. This can happen because the bytecodes do not contain @@ -995,14 +995,21 @@ const Type *PhiNode::Value( PhaseTransform *phase ) const { // be 'I' or 'j/l/O'. Thus we'll pick 'j/l/O'. If this then flows // into a Phi which "knows" it's an Interface type we'll have to // uplift the type. - if( !t->empty() && ttip && ttip->is_loaded() && ttip->klass()->is_interface() ) - { assert(ft == _type, ""); } // Uplift to interface - else if( !t->empty() && ttkp && ttkp->is_loaded() && ttkp->klass()->is_interface() ) - { assert(ft == _type, ""); } // Uplift to interface - // Otherwise it's something stupid like non-overlapping int ranges - // found on dying counted loops. - else - { assert(ft == Type::TOP, ""); } // Canonical empty value + if (!t->empty() && ttip && ttip->is_loaded() && ttip->klass()->is_interface()) { + assert(ft == _type, ""); // Uplift to interface + } else if (!t->empty() && ttkp && ttkp->is_loaded() && ttkp->klass()->is_interface()) { + assert(ft == _type, ""); // Uplift to interface + } else { + // We also have to handle 'evil cases' of interface- vs. class-arrays + Type::get_arrays_base_elements(jt, _type, NULL, &ttip); + if (!t->empty() && ttip != NULL && ttip->is_loaded() && ttip->klass()->is_interface()) { + assert(ft == _type, ""); // Uplift to array of interface + } else { + // Otherwise it's something stupid like non-overlapping int ranges + // found on dying counted loops. + assert(ft == Type::TOP, ""); // Canonical empty value + } + } } else { diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index b28eeafd9f5..f33cc2a2acc 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -988,13 +988,18 @@ void Parse::do_exits() { // In case of concurrent class loading, the type we set for the // ret_phi in build_exits() may have been too optimistic and the // ret_phi may be top now. -#ifdef ASSERT + // Otherwise, we've encountered an error and have to mark the method as + // not compilable. Just using an assertion instead would be dangerous + // as this could lead to an infinite compile loop in non-debug builds. { MutexLockerEx ml(Compile_lock, Mutex::_no_safepoint_check_flag); - assert(ret_type->isa_ptr() && C->env()->system_dictionary_modification_counter_changed(), "return value must be well defined"); + if (C->env()->system_dictionary_modification_counter_changed()) { + C->record_failure(C2Compiler::retry_class_loading_during_parsing()); + } else { + C->record_method_not_compilable("Can't determine return type."); + } } -#endif - C->record_failure(C2Compiler::retry_class_loading_during_parsing()); + return; } _exits.push_node(ret_type->basic_type(), ret_phi); } @@ -2144,15 +2149,24 @@ void Parse::return_current(Node* value) { // here. Node* phi = _exits.argument(0); const TypeInstPtr *tr = phi->bottom_type()->isa_instptr(); - if( tr && tr->klass()->is_loaded() && - tr->klass()->is_interface() ) { + if (tr && tr->klass()->is_loaded() && + tr->klass()->is_interface()) { const TypeInstPtr *tp = value->bottom_type()->isa_instptr(); if (tp && tp->klass()->is_loaded() && !tp->klass()->is_interface()) { // sharpen the type eagerly; this eases certain assert checking if (tp->higher_equal(TypeInstPtr::NOTNULL)) tr = tr->join_speculative(TypeInstPtr::NOTNULL)->is_instptr(); - value = _gvn.transform(new CheckCastPPNode(0,value,tr)); + value = _gvn.transform(new CheckCastPPNode(0, value, tr)); + } + } else { + // Also handle returns of oop-arrays to an arrays-of-interface return + const TypeInstPtr* phi_tip; + const TypeInstPtr* val_tip; + Type::get_arrays_base_elements(phi->bottom_type(), value->bottom_type(), &phi_tip, &val_tip); + if (phi_tip != NULL && phi_tip->is_loaded() && phi_tip->klass()->is_interface() && + val_tip != NULL && val_tip->is_loaded() && !val_tip->klass()->is_interface()) { + value = _gvn.transform(new CheckCastPPNode(0, value, phi->bottom_type())); } } phi->add_req(value); diff --git a/hotspot/src/share/vm/opto/type.cpp b/hotspot/src/share/vm/opto/type.cpp index 8cf30c4fdfa..ec4c898afb2 100644 --- a/hotspot/src/share/vm/opto/type.cpp +++ b/hotspot/src/share/vm/opto/type.cpp @@ -150,6 +150,33 @@ BasicType Type::array_element_basic_type() const { return bt; } +// For two instance arrays of same dimension, return the base element types. +// Otherwise or if the arrays have different dimensions, return NULL. +void Type::get_arrays_base_elements(const Type *a1, const Type *a2, + const TypeInstPtr **e1, const TypeInstPtr **e2) { + + if (e1) *e1 = NULL; + if (e2) *e2 = NULL; + const TypeAryPtr* a1tap = (a1 == NULL) ? NULL : a1->isa_aryptr(); + const TypeAryPtr* a2tap = (a2 == NULL) ? NULL : a2->isa_aryptr(); + + if (a1tap != NULL && a2tap != NULL) { + // Handle multidimensional arrays + const TypePtr* a1tp = a1tap->elem()->make_ptr(); + const TypePtr* a2tp = a2tap->elem()->make_ptr(); + while (a1tp && a1tp->isa_aryptr() && a2tp && a2tp->isa_aryptr()) { + a1tap = a1tp->is_aryptr(); + a2tap = a2tp->is_aryptr(); + a1tp = a1tap->elem()->make_ptr(); + a2tp = a2tap->elem()->make_ptr(); + } + if (a1tp && a1tp->isa_instptr() && a2tp && a2tp->isa_instptr()) { + if (e1) *e1 = a1tp->is_instptr(); + if (e2) *e2 = a2tp->is_instptr(); + } + } +} + //---------------------------get_typeflow_type--------------------------------- // Import a type produced by ciTypeFlow. const Type* Type::get_typeflow_type(ciType* type) { @@ -2029,7 +2056,11 @@ const TypePtr* TypePtr::with_inline_depth(int depth) const { bool TypeAry::interface_vs_oop(const Type *t) const { const TypeAry* t_ary = t->is_ary(); if (t_ary) { - return _elem->interface_vs_oop(t_ary->_elem); + const TypePtr* this_ptr = _elem->make_ptr(); // In case we have narrow_oops + const TypePtr* t_ptr = t_ary->_elem->make_ptr(); + if(this_ptr != NULL && t_ptr != NULL) { + return this_ptr->interface_vs_oop(t_ptr); + } } return false; } @@ -3134,8 +3165,17 @@ const Type *TypeOopPtr::filter_helper(const Type *kills, bool include_speculativ // be 'I' or 'j/l/O'. Thus we'll pick 'j/l/O'. If this then flows // into a Phi which "knows" it's an Interface type we'll have to // uplift the type. - if (!empty() && ktip != NULL && ktip->is_loaded() && ktip->klass()->is_interface()) - return kills; // Uplift to interface + if (!empty()) { + if (ktip != NULL && ktip->is_loaded() && ktip->klass()->is_interface()) { + return kills; // Uplift to interface + } + // Also check for evil cases of 'this' being a class array + // and 'kills' expecting an array of interfaces. + Type::get_arrays_base_elements(ft, kills, NULL, &ktip); + if (ktip != NULL && ktip->is_loaded() && ktip->klass()->is_interface()) { + return kills; // Uplift to array of interface + } + } return Type::TOP; // Canonical empty value } diff --git a/hotspot/src/share/vm/opto/type.hpp b/hotspot/src/share/vm/opto/type.hpp index 2a3e530d7db..6636af716b4 100644 --- a/hotspot/src/share/vm/opto/type.hpp +++ b/hotspot/src/share/vm/opto/type.hpp @@ -368,6 +368,11 @@ public: return _const_basic_type[type]; } + // For two instance arrays of same dimension, return the base element types. + // Otherwise or if the arrays have different dimensions, return NULL. + static void get_arrays_base_elements(const Type *a1, const Type *a2, + const TypeInstPtr **e1, const TypeInstPtr **e2); + // Mapping to the array element's basic type. BasicType array_element_basic_type() const; diff --git a/hotspot/test/compiler/types/TestMeetIncompatibleInterfaceArrays.java b/hotspot/test/compiler/types/TestMeetIncompatibleInterfaceArrays.java new file mode 100644 index 00000000000..f12972c5cd2 --- /dev/null +++ b/hotspot/test/compiler/types/TestMeetIncompatibleInterfaceArrays.java @@ -0,0 +1,353 @@ +/* + * Copyright 2015 SAP AG. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8141551 + * @summary C2 can not handle returns with inccompatible interface arrays + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/sun.misc + * @library /testlibrary /../../test/lib + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm + * -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * -Xbatch + * -XX:CompileThreshold=1 + * -XX:-TieredCompilation + * -XX:CICompilerCount=1 + * -XX:+PrintCompilation + * -XX:+PrintInlining + * -XX:CompileCommand=compileonly,MeetIncompatibleInterfaceArrays*.run + * -XX:CompileCommand=dontinline,TestMeetIncompatibleInterfaceArrays$Helper.createI2* + * -XX:CompileCommand=quiet + * TestMeetIncompatibleInterfaceArrays 0 + * @run main/othervm + * -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * -Xbatch + * -XX:CompileThreshold=1 + * -XX:-TieredCompilation + * -XX:CICompilerCount=1 + * -XX:+PrintCompilation + * -XX:+PrintInlining + * -XX:CompileCommand=compileonly,MeetIncompatibleInterfaceArrays*.run + * -XX:CompileCommand=inline,TestMeetIncompatibleInterfaceArrays$Helper.createI2* + * -XX:CompileCommand=quiet + * TestMeetIncompatibleInterfaceArrays 1 + * @run main/othervm + * -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * -Xbatch + * -XX:CompileThreshold=1 + * -XX:Tier0InvokeNotifyFreqLog=0 -XX:Tier2InvokeNotifyFreqLog=0 -XX:Tier3InvokeNotifyFreqLog=0 -XX:Tier23InlineeNotifyFreqLog=0 + * -XX:Tier3InvocationThreshold=2 -XX:Tier3MinInvocationThreshold=2 -XX:Tier3CompileThreshold=2 + * -XX:Tier4InvocationThreshold=1 -XX:Tier4MinInvocationThreshold=1 -XX:Tier4CompileThreshold=1 + * -XX:+TieredCompilation + * -XX:CICompilerCount=2 + * -XX:+PrintCompilation + * -XX:+PrintInlining + * -XX:CompileCommand=compileonly,MeetIncompatibleInterfaceArrays*.run + * -XX:CompileCommand=compileonly,TestMeetIncompatibleInterfaceArrays$Helper.createI2* + * -XX:CompileCommand=inline,TestMeetIncompatibleInterfaceArrays$Helper.createI2* + * -XX:CompileCommand=quiet + * TestMeetIncompatibleInterfaceArrays 2 + * + * @author volker.simonis@gmail.com + */ + +import java.io.FileOutputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import static jdk.internal.org.objectweb.asm.Opcodes.*; +import sun.hotspot.WhiteBox; + +public class TestMeetIncompatibleInterfaceArrays extends ClassLoader { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public static interface I1 { public String getName(); } + public static interface I2 { public String getName(); } + public static class I2C implements I2 { public String getName() { return "I2";} } + public static class I21C implements I2, I1 { public String getName() { return "I2 and I1";} } + + public static class Helper { + public static I2 createI2Array0() { + return new I2C(); + } + public static I2[] createI2Array1() { + return new I2C[] { new I2C() }; + } + public static I2[][] createI2Array2() { + return new I2C[][] { new I2C[] { new I2C() } }; + } + public static I2[][][] createI2Array3() { + return new I2C[][][] { new I2C[][] { new I2C[] { new I2C() } } }; + } + public static I2[][][][] createI2Array4() { + return new I2C[][][][] { new I2C[][][] { new I2C[][] { new I2C[] { new I2C() } } } }; + } + public static I2[][][][][] createI2Array5() { + return new I2C[][][][][] { new I2C[][][][] { new I2C[][][] { new I2C[][] { new I2C[] { new I2C() } } } } }; + } + public static I2 createI21Array0() { + return new I21C(); + } + public static I2[] createI21Array1() { + return new I21C[] { new I21C() }; + } + public static I2[][] createI21Array2() { + return new I21C[][] { new I21C[] { new I21C() } }; + } + public static I2[][][] createI21Array3() { + return new I21C[][][] { new I21C[][] { new I21C[] { new I21C() } } }; + } + public static I2[][][][] createI21Array4() { + return new I21C[][][][] { new I21C[][][] { new I21C[][] { new I21C[] { new I21C() } } } }; + } + public static I2[][][][][] createI21Array5() { + return new I21C[][][][][] { new I21C[][][][] { new I21C[][][] { new I21C[][] { new I21C[] { new I21C() } } } } }; + } + } + + // Location for the generated class files + public static final String PATH = System.getProperty("test.classes", ".") + java.io.File.separator; + + /* + * With 'good == false' this helper method creates the following classes + * (using the nested 'Helper' class and the nested interfaces 'I1' and 'I2'). + * For brevity I omit the enclosing class 'TestMeetIncompatibleInterfaceArrays' in the + * following examples: + * + * public class MeetIncompatibleInterfaceArrays0ASM { + * public static I1 run() { + * return Helper.createI2Array0(); // returns I2 + * } + * public static void test() { + * I1 i1 = run(); + * System.out.println(i1.getName()); + * } + * } + * public class MeetIncompatibleInterfaceArrays1ASM { + * public static I1[] run() { + * return Helper.createI2Array1(); // returns I2[] + * } + * public static void test() { + * I1[] i1 = run(); + * System.out.println(i1[0].getName()); + * } + * } + * ... + * // MeetIncompatibleInterfaceArrays4ASM is special because it creates + * // an illegal class which will be rejected by the verifier. + * public class MeetIncompatibleInterfaceArrays4ASM { + * public static I1[][][][] run() { + * return Helper.createI2Array3(); // returns I1[][][] which gives a verifier error because return expects I1[][][][] + * } + * public static void test() { + * I1[][][][][] i1 = run(); + * System.out.println(i1[0][0][0][0][0].getName()); + * } + * ... + * public class MeetIncompatibleInterfaceArrays5ASM { + * public static I1[][][][][] run() { + * return Helper.createI2Array5(); // returns I2[][][][][] + * } + * public static void test() { + * I1[][][][][] i1 = run(); + * System.out.println(i1[0][0][0][0][0].getName()); + * } + * } + * + * Notice that this is not legal Java code. We would have to use a cast in "run()" to make it legal: + * + * public static I1[] run() { + * return (I1[])Helper.createI2Array1(); // returns I2[] + * } + * + * But in pure bytecode, the "run()" methods are perfectly legal: + * + * public static I1[] run(); + * Code: + * 0: invokestatic #16 // Method Helper.createI2Array1:()[LI2; + * 3: areturn + * + * The "test()" method calls the "getName()" function from I1 on the objects returned by "run()". + * This will epectedly fail with an "IncompatibleClassChangeError" because the objects returned + * by "run()" (and by createI2Array()) are actually of type "I2C" and only implement "I2" but not "I1". + * + * + * With 'good == true' this helper method will create the following classes: + * + * public class MeetIncompatibleInterfaceArraysGood0ASM { + * public static I1 run() { + * return Helper.createI21Array0(); // returns I2 + * } + * public static void test() { + * I1 i1 = run(); + * System.out.println(i1.getName()); + * } + * } + * + * Calling "test()" on these objects will succeed and output "I2 and I1" because now the "run()" + * method calls "createI21Array()" which actually return an object (or an array of objects) of + * type "I21C" which implements both "I2" and "I1". + * + * Notice that at the bytecode level, the code for the "run()" and "test()" methods in + * "MeetIncompatibleInterfaceArraysASM" and "MeetIncompatibleInterfaceArraysGoodASM" look exactly + * the same. I.e. the verifier has no chance to verify if the I2 object returned by "createI1Array()" + * or "createI21Array()" implements "I1" or not. That's actually the reason why both versions of + * generated classes are legal from a verifier point of view. + * + */ + static void generateTestClass(int dim, boolean good) throws Exception { + String baseClassName = "MeetIncompatibleInterfaceArrays"; + if (good) + baseClassName += "Good"; + String createName = "createI2" + (good ? "1" : "") + "Array"; + String a = ""; + for (int i = 0; i < dim; i++) + a += "["; + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + cw.visit(V1_8, ACC_PUBLIC, baseClassName + dim + "ASM", null, "java/lang/Object", null); + MethodVisitor constr = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + constr.visitCode(); + constr.visitVarInsn(ALOAD, 0); + constr.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + constr.visitInsn(RETURN); + constr.visitMaxs(0, 0); + constr.visitEnd(); + MethodVisitor run = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "run", + "()" + a + "LTestMeetIncompatibleInterfaceArrays$I1;", null, null); + run.visitCode(); + if (dim == 4) { + run.visitMethodInsn(INVOKESTATIC, "TestMeetIncompatibleInterfaceArrays$Helper", createName + 3, + "()" + "[[[" + "LTestMeetIncompatibleInterfaceArrays$I2;", false); + } else { + run.visitMethodInsn(INVOKESTATIC, "TestMeetIncompatibleInterfaceArrays$Helper", createName + dim, + "()" + a + "LTestMeetIncompatibleInterfaceArrays$I2;", false); + } + run.visitInsn(ARETURN); + run.visitMaxs(0, 0); + run.visitEnd(); + MethodVisitor test = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "test", "()V", null, null); + test.visitCode(); + test.visitMethodInsn(INVOKESTATIC, baseClassName + dim + "ASM", "run", + "()" + a + "LTestMeetIncompatibleInterfaceArrays$I1;", false); + test.visitVarInsn(ASTORE, 0); + if (dim > 0) { + test.visitVarInsn(ALOAD, 0); + for (int i = 1; i <= dim; i++) { + test.visitInsn(ICONST_0); + test.visitInsn(AALOAD); + } + test.visitVarInsn(ASTORE, 1); + } + test.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + test.visitVarInsn(ALOAD, dim > 0 ? 1 : 0); + test.visitMethodInsn(INVOKEINTERFACE, "TestMeetIncompatibleInterfaceArrays$I1", "getName", + "()Ljava/lang/String;", true); + test.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V", false); + test.visitInsn(RETURN); + test.visitMaxs(0, 0); + test.visitEnd(); + + // Get the bytes of the class.. + byte[] b = cw.toByteArray(); + // ..and write them into a class file (for debugging) + FileOutputStream fos = new FileOutputStream(PATH + baseClassName + dim + "ASM.class"); + fos.write(b); + fos.close(); + + } + + public static String[][] tier = { { "interpreted", "C2 (tier 4) without inlining", "C2 (tier4) without inlining" }, + { "interpreted", "C2 (tier 4) with inlining", "C2 (tier4) with inlining" }, + { "interpreted", "C1 (tier 3) with inlining", "C2 (tier4) with inlining" } }; + + public static void main(String[] args) throws Exception { + final int pass = Integer.parseInt(args.length > 0 ? args[0] : "0"); + + // Load and initialize some classes required for compilation + Class.forName("TestMeetIncompatibleInterfaceArrays$I1"); + Class.forName("TestMeetIncompatibleInterfaceArrays$I2"); + Class.forName("TestMeetIncompatibleInterfaceArrays$Helper"); + + for (int g = 0; g < 2; g++) { + String baseClassName = "MeetIncompatibleInterfaceArrays"; + boolean good = (g == 0) ? false : true; + if (good) + baseClassName += "Good"; + for (int i = 0; i < 6; i++) { + System.out.println(); + System.out.println("Creating " + baseClassName + i + "ASM.class"); + System.out.println("========================================" + "=" + "========="); + // Create the "MeetIncompatibleInterfaceArraysASM" class + generateTestClass(i, good); + Class c = null; + try { + c = Class.forName(baseClassName + i + "ASM"); + } catch (VerifyError ve) { + if (i == 4) { + System.out.println("OK - must be (" + ve.getMessage() + ")."); + } else { + throw ve; + } + continue; + } + // Call MeetIncompatibleInterfaceArraysASM.test() + Method m = c.getMethod("test"); + Method r = c.getMethod("run"); + for (int j = 0; j < 3; j++) { + System.out.println((j + 1) + ". invokation of " + baseClassName + i + "ASM.test() [should be " + + tier[pass][j] + "]"); + try { + m.invoke(null); + } catch (InvocationTargetException ite) { + if (good) { + throw ite; + } else { + if (ite.getCause() instanceof IncompatibleClassChangeError) { + System.out.println(" OK - catched InvocationTargetException(" + + ite.getCause().getMessage() + ")."); + } else { + throw ite; + } + } + } + } + System.out.println("Method " + r + (WB.isMethodCompiled(r) ? " has" : " has not") + " been compiled."); + if (!WB.isMethodCompiled(r)) { + throw new Exception("Method " + r + " must be compiled!"); + } + } + } + } +} From 98bc34016228ea894c7f1d18176d9793aa9dfd89 Mon Sep 17 00:00:00 2001 From: Tatiana Pivovarova Date: Mon, 16 Nov 2015 19:21:35 +0300 Subject: [PATCH 104/260] 8138815: improve tests CompilerToVM::getStackTraceElement Reviewed-by: kvn --- .../compiler/jvmci/common/CTVMUtilities.java | 84 ++++++++++++++++ .../compilerToVM/GetLineNumberTableTest.java | 96 +++---------------- .../GetStackTraceElementTest.java | 62 +++++++++--- 3 files changed, 145 insertions(+), 97 deletions(-) diff --git a/hotspot/test/compiler/jvmci/common/CTVMUtilities.java b/hotspot/test/compiler/jvmci/common/CTVMUtilities.java index 2563b35e5a5..67a1aef7a19 100644 --- a/hotspot/test/compiler/jvmci/common/CTVMUtilities.java +++ b/hotspot/test/compiler/jvmci/common/CTVMUtilities.java @@ -23,10 +23,25 @@ package compiler.jvmci.common; +import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Executable; import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.tree.ClassNode; +import jdk.test.lib.Utils; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.hotspot.CompilerToVMHelper; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; @@ -71,4 +86,73 @@ public class CTVMUtilities { this.entryPoint = entryPoint; } } + public static Map getBciToLineNumber(Executable method) { + Map lineNumbers = new TreeMap<>(); + try { + ClassReader cr = new ClassReader(method.getDeclaringClass() + .getName()); + ClassNode cn = new ClassNode(); + cr.accept(cn, ClassReader.EXPAND_FRAMES); + + Map labels = new HashMap<>(); + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + ClassVisitor cv = new ClassVisitorForLabels(cw, labels, method); + cr.accept(cv, ClassReader.EXPAND_FRAMES); + labels.forEach((k, v) -> lineNumbers.put(k.getOffset(), v)); + } catch (IOException e) { + throw new Error("TEST BUG " + e, e); + } + boolean isEmptyMethod = Modifier.isAbstract(method.getModifiers()) + || Modifier.isNative(method.getModifiers()); + if (lineNumbers.isEmpty() && !isEmptyMethod) { + throw new Error(method + " doesn't contains the line numbers table " + +"(the method marked neither abstract nor native)"); + } + return lineNumbers; + } + + private static class ClassVisitorForLabels extends ClassVisitor { + private final Map lineNumbers; + private final String targetName; + private final String targetDesc; + + public ClassVisitorForLabels(ClassWriter cw, Map lines, + Executable target) { + super(Opcodes.ASM5, cw); + this.lineNumbers = lines; + + StringBuilder builder = new StringBuilder("("); + for (Parameter parameter : target.getParameters()) { + builder.append(Utils.toJVMTypeSignature(parameter.getType())); + } + builder.append(")"); + if (target instanceof Constructor) { + targetName = ""; + builder.append("V"); + } else { + targetName = target.getName(); + builder.append(Utils.toJVMTypeSignature( + ((Method) target).getReturnType())); + } + targetDesc = builder.toString(); + } + + @Override + public final MethodVisitor visitMethod(int access, String name, + String desc, String signature, + String[] exceptions) { + MethodVisitor mv = cv.visitMethod(access, name, desc, signature, + exceptions); + if (targetDesc.equals(desc) && targetName.equals(name)) { + return new MethodVisitor(Opcodes.ASM5, mv) { + @Override + public void visitLineNumber(int i, Label label) { + super.visitLineNumber(i, label); + lineNumbers.put(label, i); + } + }; + } + return mv; + } + } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java index c609d017cc8..9755b2a4564 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java @@ -40,25 +40,11 @@ import compiler.jvmci.common.CTVMUtilities; import compiler.jvmci.common.testcases.TestCase; import jdk.vm.ci.hotspot.CompilerToVMHelper; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Label; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.Opcodes; -import jdk.internal.org.objectweb.asm.tree.ClassNode; import jdk.test.lib.Asserts; -import jdk.test.lib.Utils; -import java.io.IOException; -import java.lang.reflect.Constructor; import java.lang.reflect.Executable; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; import java.util.Arrays; -import java.util.HashMap; import java.util.Map; -import java.util.TreeMap; public class GetLineNumberTableTest { public static void main(String[] args) { @@ -80,79 +66,19 @@ public class GetLineNumberTableTest { } public static long[] getExpectedLineNumbers(Executable aMethod) { - try { - ClassReader cr = new ClassReader(aMethod.getDeclaringClass() - .getName()); - ClassNode cn = new ClassNode(); - cr.accept(cn, ClassReader.EXPAND_FRAMES); - - Map lineNumbers = new HashMap<>(); - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - ClassVisitor cv = new ClassVisitorForLabels(cw, lineNumbers, - aMethod); - cr.accept(cv, ClassReader.EXPAND_FRAMES); - - long[] result = null; - if (!lineNumbers.isEmpty()) { - Map labels = new TreeMap<>(); - lineNumbers.forEach((k, v) -> labels.put(k.getOffset(), v)); - - result = new long[2 * labels.size()]; - int i = 0; - for (Integer key : labels.keySet()) { - result[i++] = key.longValue(); - result[i++] = labels.get(key).longValue(); - } + Map bciToLine = CTVMUtilities + .getBciToLineNumber(aMethod); + long[] result = null; + if (!bciToLine.isEmpty()) { + result = new long[2 * bciToLine.size()]; + int i = 0; + for (Integer key : bciToLine.keySet()) { + result[i++] = key.longValue(); + result[i++] = bciToLine.get(key).longValue(); } - // compilerToVM::getLineNumberTable returns null in case empty table - return result; - } catch (IOException e) { - throw new Error("TEST BUG " + e, e); } + // compilerToVM::getLineNumberTable returns null in case empty table + return result; } - private static class ClassVisitorForLabels extends ClassVisitor { - private final Map lineNumbers; - private final String targetName; - private final String targetDesc; - - public ClassVisitorForLabels(ClassWriter cw, Map lines, - Executable target) { - super(Opcodes.ASM5, cw); - this.lineNumbers = lines; - - StringBuilder builder = new StringBuilder("("); - for (Parameter parameter : target.getParameters()) { - builder.append(Utils.toJVMTypeSignature(parameter.getType())); - } - builder.append(")"); - if (target instanceof Constructor) { - targetName = ""; - builder.append("V"); - } else { - targetName = target.getName(); - builder.append(Utils.toJVMTypeSignature( - ((Method) target).getReturnType())); - } - targetDesc = builder.toString(); - } - - @Override - public final MethodVisitor visitMethod(int access, String name, - String desc, String signature, - String[] exceptions) { - MethodVisitor mv = cv.visitMethod(access, name, desc, signature, - exceptions); - if (targetDesc.equals(desc) && targetName.equals(name)) { - return new MethodVisitor(Opcodes.ASM5, mv) { - @Override - public void visitLineNumber(int i, Label label) { - super.visitLineNumber(i, label); - lineNumbers.put(label, i); - } - }; - } - return mv; - } - } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java index 3bbb5b29a72..821616b1b8c 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java @@ -41,6 +41,8 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; + +import compiler.jvmci.common.testcases.TestCase; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; import jdk.vm.ci.hotspot.CompilerToVMHelper; import jdk.test.lib.Asserts; @@ -56,22 +58,49 @@ public class GetStackTraceElementTest { HotSpotResolvedJavaMethod method = CTVMUtilities .getResolvedMethod(aMethod); String className = aMethod.getDeclaringClass().getName(); + String methodName = aMethod.getName().equals(className) + ? "" + : aMethod.getName(); + String fileName = getFileName(className); + Map bciWithLineNumber = CTVMUtilities + .getBciToLineNumber(aMethod); + boolean isNative = Modifier.isNative(aMethod.getModifiers()); + int lineNumber = -1; + for (int bci : bcis) { + StackTraceElement ste = CompilerToVMHelper + .getStackTraceElement(method, bci); + Asserts.assertNotNull(ste, aMethod + " : got null StackTraceElement" + + " at bci " + bci); + Asserts.assertEQ(className, ste.getClassName(), aMethod + + " : unexpected class name"); + Asserts.assertEQ(fileName, ste.getFileName(), aMethod + + " : unexpected filename"); + Asserts.assertEQ(methodName, ste.getMethodName(), aMethod + + " : unexpected method name"); + Asserts.assertEQ(isNative, ste.isNativeMethod(), aMethod + + " : unexpected 'isNative' value"); + if (bciWithLineNumber.size() > 0) { + if (bciWithLineNumber.containsKey(bci)) { + lineNumber = bciWithLineNumber.get(bci); + } + Asserts.assertEQ(lineNumber, ste.getLineNumber(), aMethod + + " : unexpected line number"); + } else { + // native and abstract function + Asserts.assertLT(0, ste.getLineNumber(), + aMethod + " : unexpected line number for abstract " + + "or native method"); + } + } + + } + + private static String getFileName(String className) { int lastDot = className.lastIndexOf('.'); int firstDol = className.contains("$") ? className.indexOf('$') : className.length(); - String fileName = className.substring(lastDot + 1, firstDol) + ".java"; - for (int bci : bcis) { - StackTraceElement ste = CompilerToVMHelper - .getStackTraceElement(method, bci); - Asserts.assertNotNull(ste); - Asserts.assertEQ(ste.getClassName(), className); - Asserts.assertEQ(ste.getFileName(), fileName); - Asserts.assertEQ(ste.getMethodName(), aMethod.getName()); - Asserts.assertEQ(ste.isNativeMethod(), Modifier - .isNative(aMethod.getModifiers())); - } - + return className.substring(lastDot + 1, firstDol) + ".java"; } private static Map createTestCases() { @@ -86,6 +115,13 @@ public class GetStackTraceElementTest { aMethod = aClass.getDeclaredMethod("dummyEmptyFunction"); bci = new int[] {0}; testCases.put(aMethod, bci); + + aMethod = aClass.getDeclaredMethod("nativeFunction"); + bci = new int[] {0}; + testCases.put(aMethod, bci); + + TestCase.getAllExecutables() + .forEach(c -> testCases.put(c, new int[] {0})); } catch (NoSuchMethodException e) { throw new Error("TEST BUG : test method not found", e); } @@ -102,5 +138,7 @@ public class GetStackTraceElementTest { } public void dummyEmptyFunction() {} + + public native void nativeFunction(); } } From 7badb3edfb46e0cac71acc8a063adaf9244db931 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 16 Nov 2015 14:11:36 -0500 Subject: [PATCH 105/260] 8143013: Remove unused DirtyCardQueue::iterate_closure_all_threads Remove unused function. Reviewed-by: tbenson, tschatzl, mgerdin --- hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp | 14 -------------- hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp | 8 -------- 2 files changed, 22 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp index 15947fddf76..7eb460394a3 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp @@ -119,20 +119,6 @@ void DirtyCardQueueSet::handle_zero_index_for_thread(JavaThread* t) { t->dirty_card_queue().handle_zero_index(); } -void DirtyCardQueueSet::iterate_closure_all_threads(CardTableEntryClosure* cl, - bool consume, - uint worker_i) { - assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); - for (JavaThread* t = Threads::first(); t; t = t->next()) { - bool b = t->dirty_card_queue().apply_closure(cl, consume); - guarantee(b, "Should not be interrupted."); - } - bool b = shared_dirty_card_queue()->apply_closure(cl, - consume, - worker_i); - guarantee(b, "Should not be interrupted."); -} - bool DirtyCardQueueSet::mut_process_buffer(void** buf) { // Used to determine if we had already claimed a par_id diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp index 86fc438b71e..965c83b1d67 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp @@ -112,14 +112,6 @@ public: static void handle_zero_index_for_thread(JavaThread* t); - // Apply the given closure to all entries in all currently-active buffers. - // This should only be applied at a safepoint. (Currently must not be called - // in parallel; this should change in the future.) If "consume" is true, - // processed entries are discarded. - void iterate_closure_all_threads(CardTableEntryClosure* cl, - bool consume = true, - uint worker_i = 0); - // If there exists some completed buffer, pop it, then apply the // specified closure to all its elements, nulling out those elements // processed. If all elements are processed, returns "true". If no From 56745a7f9f97b8aec7182b7c84cadb464f5cd4c3 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 16 Nov 2015 14:47:21 -0500 Subject: [PATCH 106/260] 8141024: [Solaris] Obsolete UseAltSigs Reviewed-by: dcubed, ddmitriev --- hotspot/src/os/solaris/vm/jvm_solaris.h | 4 ---- hotspot/src/os/solaris/vm/os_solaris.cpp | 19 +++++++------------ hotspot/src/share/vm/runtime/arguments.cpp | 11 ++++------- hotspot/src/share/vm/runtime/globals.hpp | 4 ---- 4 files changed, 11 insertions(+), 27 deletions(-) diff --git a/hotspot/src/os/solaris/vm/jvm_solaris.h b/hotspot/src/os/solaris/vm/jvm_solaris.h index 5e4c41e7680..e961d36035b 100644 --- a/hotspot/src/os/solaris/vm/jvm_solaris.h +++ b/hotspot/src/os/solaris/vm/jvm_solaris.h @@ -91,10 +91,6 @@ #define SHUTDOWN1_SIGNAL SIGHUP /* Shutdown Hooks support. */ #define SHUTDOWN2_SIGNAL SIGINT #define SHUTDOWN3_SIGNAL SIGTERM -/* alternative signals used with -XX:+UseAltSigs (or for backward - compatibility with 1.2, -Xusealtsigs) flag. Chosen to be - unlikely to conflict with applications embedding the vm */ -#define ALT_ASYNC_SIGNAL (SIGRTMIN + SIGRTMAX)/2 /* alternate async signal */ /* With 1.4.1 libjsig added versioning: used in os_solaris.cpp and jsig.c */ #define JSIG_VERSION_1_4_1 0x30140100 diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 36ee014bed3..de90c5ca4f8 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -997,9 +997,8 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, } // defined for >= Solaris 10. This allows builds on earlier versions -// of Solaris to take advantage of the newly reserved Solaris JVM signals -// With SIGJVM1, SIGJVM2, ASYNC_SIGNAL is SIGJVM2 and -XX:+UseAltSigs does -// nothing since these should have no conflict. Previously INTERRUPT_SIGNAL +// of Solaris to take advantage of the newly reserved Solaris JVM signals. +// With SIGJVM1, SIGJVM2, ASYNC_SIGNAL is SIGJVM2. Previously INTERRUPT_SIGNAL // was SIGJVM1. // #if !defined(SIGJVM1) @@ -1053,13 +1052,9 @@ void os::Solaris::signal_sets_init() { sigaddset(&unblocked_sigs, SIGBUS); sigaddset(&unblocked_sigs, SIGFPE); - if (isJVM1available) { - os::Solaris::set_SIGasync(SIGJVM2); - } else if (UseAltSigs) { - os::Solaris::set_SIGasync(ALT_ASYNC_SIGNAL); - } else { - os::Solaris::set_SIGasync(ASYNC_SIGNAL); - } + // Always true on Solaris 10+ + guarantee(isJVM1available(), "SIGJVM1/2 missing!"); + os::Solaris::set_SIGasync(SIGJVM2); sigaddset(&unblocked_sigs, os::Solaris::SIGasync()); @@ -3922,7 +3917,7 @@ void os::Solaris::set_signal_handler(int sig, bool set_installed, // save the old handler in jvm save_preinstalled_handler(sig, oldAct); } else { - vm_exit_during_initialization("Signal chaining not allowed for VM interrupt signal, try -XX:+UseAltSigs."); + vm_exit_during_initialization("Signal chaining not allowed for VM interrupt signal."); } // libjsig also interposes the sigaction() call below and saves the // old sigaction on it own. @@ -3991,7 +3986,7 @@ void os::run_periodic_checks() { DO_SIGNAL_CHECK(BREAK_SIGNAL); } - // See comments above for using JVM1/JVM2 and UseAltSigs + // See comments above for using JVM1/JVM2 DO_SIGNAL_CHECK(os::Solaris::SIGasync()); } diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 0efd30b08f8..ca98eb8e7f0 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -366,6 +366,7 @@ static SpecialFlag const special_jvm_flags[] = { { "StarvationMonitorInterval", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "PreInflateSpin", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "JNIDetachReleasesMonitors", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, + { "UseAltSigs", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, #ifdef TEST_VERIFY_SPECIAL_JVM_FLAGS { "dep > obs", JDK_Version::jdk(9), JDK_Version::jdk(8), JDK_Version::undefined() }, @@ -2949,11 +2950,12 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, round_to((int)long_ThreadStackSize, K) / K) != Flag::SUCCESS) { return JNI_EINVAL; } - // -Xoss, -Xsqnopause, -Xoptimize, -Xboundthreads + // -Xoss, -Xsqnopause, -Xoptimize, -Xboundthreads, -Xusealtsigs } else if (match_option(option, "-Xoss", &tail) || match_option(option, "-Xsqnopause") || match_option(option, "-Xoptimize") || - match_option(option, "-Xboundthreads")) { + match_option(option, "-Xboundthreads") || + match_option(option, "-Xusealtsigs")) { // All these options are deprecated in JDK 9 and will be removed in a future release char version[256]; JDK_Version::jdk(9).to_string(version, sizeof(version)); @@ -3036,11 +3038,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, if (FLAG_SET_CMDLINE(bool, ReduceSignalUsage, true) != Flag::SUCCESS) { return JNI_EINVAL; } - } else if (match_option(option, "-Xusealtsigs")) { - // change default internal VM signals used - lower case for back compat - if (FLAG_SET_CMDLINE(bool, UseAltSigs, true) != Flag::SUCCESS) { - return JNI_EINVAL; - } // -Xprof } else if (match_option(option, "-Xprof")) { #if INCLUDE_FPROF diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 49153c0c62d..fb61f555307 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1334,10 +1334,6 @@ public: "Use signal-chaining to invoke signal handlers installed " \ "by the application (Solaris & Linux only)") \ \ - product(bool, UseAltSigs, false, \ - "Use alternate signals instead of SIGUSR1 & SIGUSR2 for VM " \ - "internal signals (Solaris only)") \ - \ product(bool, AllowJNIEnvProxy, false, \ "Allow JNIEnv proxies for jdbx") \ \ From 3904de571b293dca3ce291def23190b95105b97f Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 16 Nov 2015 18:50:55 -0500 Subject: [PATCH 107/260] 8139300: Internal Error (vm/utilities/debug.cpp:399), # Error: ShouldNotReachHere() Reviewed-by: simonis, dcubed --- hotspot/src/share/vm/utilities/debug.cpp | 4 +++- hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp index fa1c625d334..241aa6f139e 100644 --- a/hotspot/src/share/vm/utilities/debug.cpp +++ b/hotspot/src/share/vm/utilities/debug.cpp @@ -331,7 +331,9 @@ static void crash_with_sigfpe() { volatile int x = 0; volatile int y = 1/x; #ifndef _WIN32 - raise(SIGFPE); + // OSX implements raise(sig) incorrectly so we need to + // explicitly target the current thread + pthread_kill(pthread_self(), SIGFPE); #endif } // end: crash_with_sigfpe diff --git a/hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java b/hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java index 9c60d2d0c89..37fac08130c 100644 --- a/hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java +++ b/hotspot/test/runtime/ErrorHandling/SecondaryErrorTest.java @@ -28,7 +28,6 @@ * @summary Synchronous signals during error reporting may terminate or hang VM process * @library /testlibrary * @author Thomas Stuefe (SAP) - * @requires os.family != "mac" * @modules java.base/sun.misc * java.management */ From 8b00726f061fbfc65ea0a02bef1e2b41f53e6707 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 16 Nov 2015 16:07:46 -0800 Subject: [PATCH 108/260] 7162125: [macosx] A font has different behaviour for ligatures depending on its creation mod Reviewed-by: srl, jgodinez --- .../sun/font/CCompositeGlyphMapper.java | 155 +++++++++++++++++ .../macosx/classes/sun/font/CFont.java | 60 ++++++- .../macosx/classes/sun/font/CStrike.java | 2 +- .../macosx/native/libawt_lwawt/font/AWTFont.h | 3 + .../macosx/native/libawt_lwawt/font/AWTFont.m | 159 ++++++++++++++++++ .../share/classes/sun/font/CompositeFont.java | 19 +++ .../sun/font/CompositeGlyphMapper.java | 2 +- .../share/classes/sun/font/Font2D.java | 9 +- .../classes/sun/font/FontSubstitution.java | 38 +++++ .../share/classes/sun/font/GlyphLayout.java | 3 + .../classes/sun/font/StandardGlyphVector.java | 10 +- .../classes/sun/font/SunLayoutEngine.java | 5 +- .../share/classes/sun/font/TrueTypeFont.java | 6 +- .../awt/font/TextLayout/OSXLigatureTest.java | 82 +++++++++ 14 files changed, 540 insertions(+), 13 deletions(-) create mode 100644 jdk/src/java.desktop/macosx/classes/sun/font/CCompositeGlyphMapper.java create mode 100644 jdk/src/java.desktop/share/classes/sun/font/FontSubstitution.java create mode 100644 jdk/test/java/awt/font/TextLayout/OSXLigatureTest.java diff --git a/jdk/src/java.desktop/macosx/classes/sun/font/CCompositeGlyphMapper.java b/jdk/src/java.desktop/macosx/classes/sun/font/CCompositeGlyphMapper.java new file mode 100644 index 00000000000..bf03ab9dfdf --- /dev/null +++ b/jdk/src/java.desktop/macosx/classes/sun/font/CCompositeGlyphMapper.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.font; + +public final class CCompositeGlyphMapper extends CompositeGlyphMapper { + + private CompositeFont font; + private CharToGlyphMapper slotMappers[]; + + public CCompositeGlyphMapper(CompositeFont compFont) { + super(compFont); + font = compFont; + slotMappers = new CharToGlyphMapper[font.numSlots]; + missingGlyph = 0; + } + + private CharToGlyphMapper getSlotMapper(int slot) { + CharToGlyphMapper mapper = slotMappers[slot]; + if (mapper == null) { + mapper = font.getSlotFont(slot).getMapper(); + slotMappers[slot] = mapper; + } + return mapper; + } + + public boolean canDisplay(char ch) { + int glyph = charToGlyph(ch); + return glyph != missingGlyph; + } + + private int convertToGlyph(int unicode) { + for (int slot = 0; slot < font.numSlots; slot++) { + CharToGlyphMapper mapper = getSlotMapper(slot); + int glyphCode = mapper.charToGlyph(unicode); + // The CFont Mappers will return a negative code + // for fonts that will fill the glyph from fallbacks + // - cascading font in OSX-speak. But we need to be + // know here that only the codes > 0 are really present. + if (glyphCode > 0) { + glyphCode = compositeGlyphCode(slot, glyphCode); + return glyphCode; + } + } + return missingGlyph; + } + + public int getNumGlyphs() { + int numGlyphs = 0; + for (int slot=0; slot<1 /*font.numSlots*/; slot++) { + CharToGlyphMapper mapper = slotMappers[slot]; + if (mapper == null) { + mapper = font.getSlotFont(slot).getMapper(); + slotMappers[slot] = mapper; + } + numGlyphs += mapper.getNumGlyphs(); + } + return numGlyphs; + } + + public int charToGlyph(int unicode) { + return convertToGlyph(unicode); + } + + public int charToGlyph(char unicode) { + return convertToGlyph(unicode); + } + + public boolean charsToGlyphsNS(int count, char[] unicodes, int[] glyphs) { + + for (int i=0; i= HI_SURROGATE_START && + code <= HI_SURROGATE_END && i < count - 1) { + char low = unicodes[i + 1]; + + if (low >= LO_SURROGATE_START && + low <= LO_SURROGATE_END) { + code = (code - HI_SURROGATE_START) * + 0x400 + low - LO_SURROGATE_START + 0x10000; + glyphs[i + 1] = INVISIBLE_GLYPH_ID; + } + } + + glyphs[i] = convertToGlyph(code); + + if (code < FontUtilities.MIN_LAYOUT_CHARCODE) { + continue; + } + else if (FontUtilities.isComplexCharCode(code)) { + return true; + } + else if (code >= 0x10000) { + i += 1; // Empty glyph slot after surrogate + continue; + } + } + + return false; + } + + public void charsToGlyphs(int count, char[] unicodes, int[] glyphs) { + for (int i=0; i= HI_SURROGATE_START && + code <= HI_SURROGATE_END && i < count - 1) { + char low = unicodes[i + 1]; + + if (low >= LO_SURROGATE_START && + low <= LO_SURROGATE_END) { + code = (code - HI_SURROGATE_START) * + 0x400 + low - LO_SURROGATE_START + 0x10000; + + glyphs[i] = convertToGlyph(code); + i += 1; // Empty glyph slot after surrogate + glyphs[i] = INVISIBLE_GLYPH_ID; + continue; + } + } + + glyphs[i] = convertToGlyph(code); + } + } + + public void charsToGlyphs(int count, int[] unicodes, int[] glyphs) { + for (int i=0; i listOfString); + + private CompositeFont createCompositeFont() { + ArrayList listOfString = new ArrayList(); + getCascadeList(nativeFontPtr, listOfString); + + FontManager fm = FontManagerFactory.getInstance(); + int numFonts = 1 + listOfString.size(); + PhysicalFont[] fonts = new PhysicalFont[numFonts]; + fonts[0] = this; + int idx = 1; + for (String s : listOfString) { + if (s.equals(".AppleSymbolsFB")) { + // Don't know why we get the weird name above .. replace. + s = "AppleSymbols"; + } + Font2D f2d = fm.findFont2D(s, Font.PLAIN, FontManager.NO_FALLBACK); + if (f2d == null || f2d == this) { + continue; + } + fonts[idx++] = (PhysicalFont)f2d; + } + if (idx < fonts.length) { + PhysicalFont[] orig = fonts; + fonts = new PhysicalFont[idx]; + System.arraycopy(orig, 0, fonts, 0, idx); + } + CompositeFont compFont = new CompositeFont(fonts); + compFont.mapper = new CCompositeGlyphMapper(compFont); + return compFont; + } + + private CompositeFont compFont; + + public CompositeFont getCompositeFont2D() { + if (compFont == null) { + compFont = createCompositeFont(); + } + return compFont; + } + protected synchronized void finalize() { if (nativeFontPtr != 0) { disposeNativeFont(nativeFontPtr); diff --git a/jdk/src/java.desktop/macosx/classes/sun/font/CStrike.java b/jdk/src/java.desktop/macosx/classes/sun/font/CStrike.java index 5296f5c87f0..c50533a5947 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/font/CStrike.java +++ b/jdk/src/java.desktop/macosx/classes/sun/font/CStrike.java @@ -31,7 +31,7 @@ import java.util.*; import sun.awt.SunHints; -public final class CStrike extends FontStrike { +public final class CStrike extends PhysicalStrike { // Creates the native strike private static native long createNativeStrikePtr(long nativeFontPtr, diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.h b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.h index 026809952dc..a86f5c3859d 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.h +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.h @@ -26,6 +26,8 @@ #import #import +#import "fontscalerdefs.h" + #define MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE 256 @interface AWTFont : NSObject { @@ -33,6 +35,7 @@ NSFont *fFont; CGFontRef fNativeCGFont; BOOL fIsFakeItalic; + TTLayoutTableCache* layoutTableCache; } + (AWTFont *) awtFontForName:(NSString *)name diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m index a82afc26888..548fd5015d6 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m @@ -42,10 +42,33 @@ if (self) { fFont = [font retain]; fNativeCGFont = CTFontCopyGraphicsFont((CTFontRef)font, NULL); + layoutTableCache = NULL; } return self; } +static TTLayoutTableCache* newCFontLayoutTableCache() { + TTLayoutTableCache* ltc = calloc(1, sizeof(TTLayoutTableCache)); + if (ltc) { + int i; + for(i=0;ientries[i].len = -1; + } + } + return ltc; +} + +static void freeCFontLayoutTableCache(TTLayoutTableCache* ltc) { + if (ltc) { + int i; + for(i=0;ientries[i].ptr) free (ltc->entries[i].ptr); + } + if (ltc->kernPairs) free(ltc->kernPairs); + free(ltc); + } +} + - (void) dealloc { [fFont release]; fFont = nil; @@ -53,6 +76,10 @@ if (fNativeCGFont) { CGFontRelease(fNativeCGFont); fNativeCGFont = NULL; + if (layoutTableCache != NULL) { + freeCFontLayoutTableCache(layoutTableCache); + layoutTableCache = NULL; + } } [super dealloc]; @@ -63,6 +90,10 @@ CGFontRelease(fNativeCGFont); fNativeCGFont = NULL; } + if (layoutTableCache != NULL) { + freeCFontLayoutTableCache(layoutTableCache); + layoutTableCache = NULL; + } [super finalize]; } @@ -343,6 +374,95 @@ JNF_COCOA_EXIT(env); #pragma mark --- sun.font.CFont JNI --- +/* + * Class: sun_font_CFont + * Method: getPlatformFontPtrNative + * Signature: (JI)[B + */ +JNIEXPORT jlong JNICALL +Java_sun_font_CFont_getCGFontPtrNative + (JNIEnv *env, jclass clazz, + jlong awtFontPtr) +{ + AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr); + return (jlong)(awtFont->fNativeCGFont); +} + +/* + * Class: sun_font_CFont + * Method: getLayoutTableCacheNative + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL +Java_sun_font_CFont_getLayoutTableCacheNative + (JNIEnv *env, jclass clazz, + jlong awtFontPtr) +{ + AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr); + if (awtFont->layoutTableCache == NULL) { + awtFont->layoutTableCache = newCFontLayoutTableCache(); + } + return (jlong)(awtFont->layoutTableCache); +} + +/* + * Class: sun_font_CFont + * Method: getTableBytesNative + * Signature: (JI)[B + */ +JNIEXPORT jbyteArray JNICALL +Java_sun_font_CFont_getTableBytesNative + (JNIEnv *env, jclass clazz, + jlong awtFontPtr, jint jtag) +{ + jbyteArray jbytes = NULL; +JNF_COCOA_ENTER(env); + + CTFontTableTag tag = (CTFontTableTag)jtag; + int i, found = 0; + AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr); + NSFont* nsFont = awtFont->fFont; + CTFontRef ctfont = (CTFontRef)nsFont; + CFArrayRef tagsArray = + CTFontCopyAvailableTables(ctfont, kCTFontTableOptionNoOptions); + CFIndex numTags = CFArrayGetCount(tagsArray); + for (i=0; iNewByteArray(env, (jsize)tableLength); + if (jbytes == NULL) { + return NULL; + } + (*env)->SetByteArrayRegion(env, jbytes, 0, + (jsize)tableLength, + (jbyte*)tableBytes); + CFRelease(table); + +JNF_COCOA_EXIT(env); + + return jbytes; +} + /* * Class: sun_font_CFont * Method: initNativeFont @@ -460,3 +580,42 @@ Java_sun_awt_FontDescriptor_initIDs { } #endif + +/* + * Class: sun_awt_FontDescriptor + * Method: initIDs + * Signature: ()V + */ +JNIEXPORT void JNICALL +Java_sun_font_CFont_getCascadeList + (JNIEnv *env, jclass cls, jlong awtFontPtr, jobject arrayListOfString) +{ + jclass alc = (*env)->FindClass(env, "java/util/ArrayList"); + if (alc == NULL) return; + jmethodID addMID = (*env)->GetMethodID(env, alc, "add", "(Ljava/lang/Object;)Z"); + if (addMID == NULL) return; + + CFIndex i; + AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr); + NSFont* nsFont = awtFont->fFont; + CTFontRef font = (CTFontRef)nsFont; + CFStringRef base = CTFontCopyFullName(font); + CFArrayRef codes = CFLocaleCopyISOLanguageCodes(); + +#ifdef DEBUG + NSLog(@"BaseFont is : %@", (NSString*)base); +#endif + CFArrayRef fds = CTFontCopyDefaultCascadeListForLanguages(font, codes); + CFIndex cnt = CFArrayGetCount(fds); + for (i=0; iCallBooleanMethod(env, arrayListOfString, addMID, jFontName); + (*env)->DeleteLocalRef(env, jFontName); + } +} diff --git a/jdk/src/java.desktop/share/classes/sun/font/CompositeFont.java b/jdk/src/java.desktop/share/classes/sun/font/CompositeFont.java index 7b19bb362cb..177570b9638 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/CompositeFont.java +++ b/jdk/src/java.desktop/share/classes/sun/font/CompositeFont.java @@ -149,6 +149,25 @@ public final class CompositeFont extends Font2D { } } + /* + * Build a composite from a set of individual slot fonts. + */ + CompositeFont(PhysicalFont[] slotFonts) { + + isStdComposite = false; + handle = new Font2DHandle(this); + fullName = slotFonts[0].fullName; + familyName = slotFonts[0].familyName; + style = slotFonts[0].style; + + numMetricsSlots = 1; /* Only the physical Font */ + numSlots = slotFonts.length; + + components = new PhysicalFont[numSlots]; + System.arraycopy(slotFonts, 0, components, 0, numSlots); + deferredInitialisation = new boolean[numSlots]; // all false. + } + /* This method is currently intended to be called only from * FontManager.getCompositeFontUIResource(Font) * It creates a new CompositeFont with the contents of the Physical diff --git a/jdk/src/java.desktop/share/classes/sun/font/CompositeGlyphMapper.java b/jdk/src/java.desktop/share/classes/sun/font/CompositeGlyphMapper.java index d875da33991..81a90f5021d 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/CompositeGlyphMapper.java +++ b/jdk/src/java.desktop/share/classes/sun/font/CompositeGlyphMapper.java @@ -42,7 +42,7 @@ package sun.font; * this appears to cause problems. */ -public final class CompositeGlyphMapper extends CharToGlyphMapper { +public class CompositeGlyphMapper extends CharToGlyphMapper { public static final int SLOTMASK = 0xff000000; public static final int GLYPHMASK = 0x00ffffff; diff --git a/jdk/src/java.desktop/share/classes/sun/font/Font2D.java b/jdk/src/java.desktop/share/classes/sun/font/Font2D.java index e1c7c912e3d..7e7edc3e8cc 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/Font2D.java +++ b/jdk/src/java.desktop/share/classes/sun/font/Font2D.java @@ -461,10 +461,17 @@ public abstract class Font2D { * to check the font class before attempting to run, rather than needing * to promote this method up from TrueTypeFont */ - byte[] getTableBytes(int tag) { + protected byte[] getTableBytes(int tag) { return null; } + /* implemented for fonts backed by an sfnt that has + * OpenType or AAT layout tables. + */ + protected long getLayoutTableCache() { + return 0L; + } + /* for layout code */ protected long getUnitsPerEm() { return 2048; diff --git a/jdk/src/java.desktop/share/classes/sun/font/FontSubstitution.java b/jdk/src/java.desktop/share/classes/sun/font/FontSubstitution.java new file mode 100644 index 00000000000..47dfc6f6c5e --- /dev/null +++ b/jdk/src/java.desktop/share/classes/sun/font/FontSubstitution.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.font; + + + +/** + * Interface that indicates a Font2D that is not a Composite but has the + * property that it internally behaves like one, substituting glyphs + * from another font at render time. + * In this case the Font must provide a way to behave like a regular + * composite when that behaviour is not wanted. + */ +public interface FontSubstitution { + public CompositeFont getCompositeFont2D(); +} diff --git a/jdk/src/java.desktop/share/classes/sun/font/GlyphLayout.java b/jdk/src/java.desktop/share/classes/sun/font/GlyphLayout.java index 0129d225730..143795e7b6a 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/GlyphLayout.java +++ b/jdk/src/java.desktop/share/classes/sun/font/GlyphLayout.java @@ -408,6 +408,9 @@ public final class GlyphLayout { int lang = -1; // default for now Font2D font2D = FontUtilities.getFont2D(font); + if (font2D instanceof FontSubstitution) { + font2D = ((FontSubstitution)font2D).getCompositeFont2D(); + } _textRecord.init(text, offset, lim, min, max); int start = offset; diff --git a/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java b/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java index d48c99a6781..06abf9de163 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java +++ b/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java @@ -1124,6 +1124,9 @@ public class StandardGlyphVector extends GlyphVector { private void initFontData() { font2D = FontUtilities.getFont2D(font); + if (font2D instanceof FontSubstitution) { + font2D = ((FontSubstitution)font2D).getCompositeFont2D(); + } float s = font.getSize2D(); if (font.isTransformed()) { ftx = font.getTransform(); @@ -1742,7 +1745,12 @@ public class StandardGlyphVector extends GlyphVector { aa, fm); // Get the strike via the handle. Shouldn't matter // if we've invalidated the font but its an extra precaution. - FontStrike strike = sgv.font2D.handle.font2D.getStrike(desc); // !!! getStrike(desc, false) + // do we want the CompFont from CFont here ? + Font2D f2d = sgv.font2D; + if (f2d instanceof FontSubstitution) { + f2d = ((FontSubstitution)f2d).getCompositeFont2D(); + } + FontStrike strike = f2d.handle.font2D.getStrike(desc); // !!! getStrike(desc, false) return new GlyphStrike(sgv, strike, dx, dy); } diff --git a/jdk/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java b/jdk/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java index 47f0022a443..a62b1e5fe21 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java +++ b/jdk/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java @@ -155,10 +155,7 @@ public final class SunLayoutEngine implements LayoutEngine, LayoutEngineFactory Point2D.Float pt, GVData data) { Font2D font = key.font(); FontStrike strike = font.getStrike(desc); - long layoutTables = 0; - if (font instanceof TrueTypeFont) { - layoutTables = ((TrueTypeFont) font).getLayoutTableCache(); - } + long layoutTables = font.getLayoutTableCache(); nativeLayout(font, strike, mat, gmask, baseIndex, tr.text, tr.start, tr.limit, tr.min, tr.max, key.script(), key.lang(), typo_flags, pt, data, diff --git a/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java b/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java index 0e8647cc734..f3bb84529da 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java +++ b/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java @@ -874,8 +874,8 @@ public class TrueTypeFont extends FileFont { } } - /* NB: is it better to move declaration to Font2D? */ - long getLayoutTableCache() { + @Override + protected long getLayoutTableCache() { try { return getScaler().getLayoutTableCache(); } catch(FontScalerException fe) { @@ -884,7 +884,7 @@ public class TrueTypeFont extends FileFont { } @Override - byte[] getTableBytes(int tag) { + protected byte[] getTableBytes(int tag) { ByteBuffer buffer = getTableBuffer(tag); if (buffer == null) { return null; diff --git a/jdk/test/java/awt/font/TextLayout/OSXLigatureTest.java b/jdk/test/java/awt/font/TextLayout/OSXLigatureTest.java new file mode 100644 index 00000000000..b1d2d797dae --- /dev/null +++ b/jdk/test/java/awt/font/TextLayout/OSXLigatureTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7162125 + * @summary Test ligatures form on OS X. + */ + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.awt.font.TextAttribute; +import java.util.HashMap; +import java.util.Map; + +public class OSXLigatureTest { + + public static void main(String[] args) { + if (!System.getProperty("os.name").startsWith("Mac")) { + return; + } + String ligStr = "ffi"; + int w = 50, h = 50; + + BufferedImage bi1 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + Graphics2D bi1Graphics = bi1.createGraphics(); + bi1Graphics.setColor(Color.white); + bi1Graphics.fillRect(0, 0, w, h); + bi1Graphics.setColor(Color.black); + Font noLigFont = new Font("Gill Sans", Font.PLAIN, 30); + bi1Graphics.setFont(noLigFont); + bi1Graphics.drawString(ligStr, 10, 40); + + BufferedImage bi2 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + Graphics2D bi2Graphics = bi2.createGraphics(); + bi2Graphics.setColor(Color.white); + bi2Graphics.fillRect(0, 0, w, h); + bi2Graphics.setColor(Color.black); + Map attributes = new HashMap<>(); + attributes.put(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON); + Font ligFont = noLigFont.deriveFont(attributes); + bi2Graphics.setFont(ligFont); + bi2Graphics.drawString(ligStr, 10, 40); + + boolean same = true; + for (int x = 0; x < w; x++) { + for (int y = 0; y < h; y++) { + int c1 = bi1.getRGB(x, y); + int c2 = bi2.getRGB(x, y); + same &= (c1 == c2); + } + if (!same) { + break; + } + } + if (same) { + throw new RuntimeException("Images do not differ - no ligature"); + } + } +} From 2946748843d9bdbf65c673f3a21b779ab3eac74c Mon Sep 17 00:00:00 2001 From: Rajeev Chamyal Date: Tue, 17 Nov 2015 13:14:26 +0400 Subject: [PATCH 109/260] 8030099: Memory usage of java process increases after pressing start button in test window Reviewed-by: prr, serb --- .../sun/awt/shell/Win32ShellFolder2.java | 7 +- .../sun/awt/shell/ShellFolderMemoryLeak.java | 226 ++++++++++++++++++ 2 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 jdk/test/sun/awt/shell/ShellFolderMemoryLeak.java diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java b/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java index 9539b981709..8e32e39acc8 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java @@ -141,6 +141,9 @@ final class Win32ShellFolder2 extends ShellFolder { public static final int SHGDN_FORADDRESSBAR = 0x4000; public static final int SHGDN_FORPARSING = 0x8000; + /** The referent to be registered with the Disposer. */ + private Object disposerReferent = new Object(); + // Values for system call LoadIcon() public enum SystemIcon { IDI_APPLICATION(32512), @@ -297,7 +300,7 @@ final class Win32ShellFolder2 extends ShellFolder { } }, InterruptedException.class); - sun.java2d.Disposer.addRecord(this, disposer); + sun.java2d.Disposer.addObjectRecord(disposerReferent, disposer); } @@ -309,7 +312,7 @@ final class Win32ShellFolder2 extends ShellFolder { this.isLib = isLib; this.disposer.pIShellFolder = pIShellFolder; this.disposer.relativePIDL = relativePIDL; - sun.java2d.Disposer.addRecord(this, disposer); + sun.java2d.Disposer.addObjectRecord(disposerReferent, disposer); } diff --git a/jdk/test/sun/awt/shell/ShellFolderMemoryLeak.java b/jdk/test/sun/awt/shell/ShellFolderMemoryLeak.java new file mode 100644 index 00000000000..68a18e0e42c --- /dev/null +++ b/jdk/test/sun/awt/shell/ShellFolderMemoryLeak.java @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8030099 + * @summary Memory usage of java process increases + after calling Win32ShellFolder:listFiles + multiple times on some directory with + large number of files/folders + * @modules java.desktop/sun.awt + * @requires (os.family == "windows") + * @run main/timeout=1000 ShellFolderMemoryLeak + */ +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.logging.Level; +import java.util.logging.Logger; +import sun.awt.shell.ShellFolder; + +public class ShellFolderMemoryLeak { + + private final static String tempDir = System.getProperty("java.io.tmpdir"); + private static Process process; + public static void main(String[] args) throws Exception { + if (args.length == 0) { + boolean testResultParallel + = createChildProcessWithParallelCollector(); + String result = ""; + if (!testResultParallel) { + result = "Test failed with Parallel collector"; + } + boolean testResultDefault + = createChildProcessWithDefaultCollector(); + if (!testResultDefault && !testResultParallel) { + result += " and with default collector both."; + } else if (!testResultDefault) { + result = "Test failed with default collector"; + } + if (!"".equals(result)) { + throw new RuntimeException(result); + } + } else { + testListFile(args[args.length - 1]); + } + } + + public static boolean createChildProcessWithDefaultCollector() + throws Exception { + String testDirectory = "TestDirectory1"; + testDirectory = tempDir + testDirectory +File.separator; + createTestData(testDirectory); + return runProcess("", testDirectory); + } + + public static boolean createChildProcessWithParallelCollector() + throws Exception { + String testDirectory = "TestDirectory2"; + testDirectory = tempDir + testDirectory +File.separator; + createTestData(testDirectory); + return runProcess(" -XX:+UseParallelGC", testDirectory); + } + + public static boolean runProcess(String arg1, String arg2) throws Exception { + String javaPath = System.getProperty("java.home"); + String classPathDir = System.getProperty("java.class.path"); + + //creating java process which run same class with different Xmx value + String command = javaPath + File.separator + "bin" + File.separator + + "java -Xmx256M" + arg1 + " -cp " + + classPathDir + + " ShellFolderMemoryLeak " + arg2; + process = Runtime.getRuntime().exec(command); + BufferedReader input = null; + InputStream errorStream = null; + String line = null; + try { + int exitVal = process.waitFor(); + input = new BufferedReader(new InputStreamReader( + process.getInputStream())); + while ((line = input.readLine()) != null) { + } + errorStream = process.getErrorStream(); + if (checkExceptions(errorStream) || exitVal != 0) { + return false; + } + } catch (IllegalThreadStateException e) { + throw new RuntimeException(e); + } finally { + if (input != null) { + input.close(); + } + if (errorStream != null) { + errorStream.close(); + } + process.destroy(); + } + return true; + } + + public static boolean checkExceptions(InputStream in) throws IOException { + String tempString; + int count = in.available(); + boolean exception = false; + while (count > 0) { + byte[] b = new byte[count]; + in.read(b); + tempString = new String(b); + if (!exception) { + exception = tempString.contains("RunTimeException"); + } + count = in.available(); + } + return exception; + } + + private static void createTestData(String testDirectory) { + String folder = "folder_"; + File testFolder = new File(testDirectory); + if (testFolder.exists()) { + clearTestData(testDirectory); + } else { + if (testFolder.mkdir()) { + for (int inx = 0; inx < 100; inx++) { + new File(testFolder + File.separator + folder + inx).mkdir(); + } + } else { + throw new RuntimeException("Failed to create testDirectory"); + } + } + } + + public static void deleteDirectory(File file) + throws IOException { + + if (file.isDirectory()) { + if (file.list().length == 0) { + file.delete(); + } else { + String files[] = file.list(); + for (String temp : files) { + File fileDelete = new File(file, temp); + deleteDirectory(fileDelete); + } + if (file.list().length == 0) { + file.delete(); + } + } + } + } + + private static void testListFile(String testDirectory) { + try { + int mb = 1024 * 1024; + ShellFolder folder = ShellFolder.getShellFolder( + new File(testDirectory)); + Runtime instance = Runtime.getRuntime(); + + //Memory used before calling listFiles + long startmem = instance.totalMemory() - instance.freeMemory(); + long start = System.currentTimeMillis(); + long endmem = 0; + + //Calling listFiles for 5 minutes with sleep of 10 ms. + while ((System.currentTimeMillis() - start) < 300000) { + try { + folder.listFiles(); + Thread.sleep(10); + endmem = instance.totalMemory() - instance.freeMemory(); + } catch (InterruptedException ex) { + Logger.getLogger(ShellFolderMemoryLeak.class.getName()) + .log(Level.SEVERE, "InterruptedException", ex); + } + } + + //Total increase in memory after 5 minutes + long result = (endmem - startmem) / mb; + + if (result > 100) { + clearTestData(testDirectory); + throw new RuntimeException("Test Failed"); + } + clearTestData(testDirectory); + } catch (FileNotFoundException ex) { + if(process != null && process.isAlive()) { + process.destroy(); + } + Logger.getLogger(ShellFolderMemoryLeak.class.getName()) + .log(Level.SEVERE, "File Not Found Exception", ex); + } + } + + private static void clearTestData(String testDirectory) { + File testFolder = new File(testDirectory); + try { + deleteDirectory(testFolder); + } catch (IOException ex) { + Logger.getLogger(ShellFolderMemoryLeak.class.getName()) + .log(Level.SEVERE, "Unable to delete files", ex); + } + } +} \ No newline at end of file From 56adbd02ec40ed5109b857383b6b6f0f453e5c08 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Tue, 17 Nov 2015 11:20:27 +0100 Subject: [PATCH 110/260] 8141280: G1ResManAllocator doesn't work with _survivor_is_full/_old_is_full Reviewed-by: jmasa, kbarrett, tschatzl --- hotspot/src/share/vm/gc/g1/g1Allocator.cpp | 42 +++++++++++----------- hotspot/src/share/vm/gc/g1/g1Allocator.hpp | 24 ++++++++----- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp index 9a63b618d8b..8bd8b376c72 100644 --- a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp +++ b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp @@ -33,6 +33,8 @@ G1DefaultAllocator::G1DefaultAllocator(G1CollectedHeap* heap) : G1Allocator(heap), + _survivor_is_full(false), + _old_is_full(false), _retained_old_gc_alloc_region(NULL), _survivor_gc_alloc_region(heap->alloc_buffer_stats(InCSetState::Young)), _old_gc_alloc_region(heap->alloc_buffer_stats(InCSetState::Old)) { @@ -87,7 +89,8 @@ void G1Allocator::reuse_retained_old_region(EvacuationInfo& evacuation_info, void G1DefaultAllocator::init_gc_alloc_regions(EvacuationInfo& evacuation_info) { assert_at_safepoint(true /* should_be_vm_thread */); - G1Allocator::init_gc_alloc_regions(evacuation_info); + _survivor_is_full = false; + _old_is_full = false; _survivor_gc_alloc_region.init(); _old_gc_alloc_region.init(); @@ -118,6 +121,22 @@ void G1DefaultAllocator::abandon_gc_alloc_regions() { _retained_old_gc_alloc_region = NULL; } +bool G1DefaultAllocator::survivor_is_full(AllocationContext_t context) const { + return _survivor_is_full; +} + +bool G1DefaultAllocator::old_is_full(AllocationContext_t context) const { + return _old_is_full; +} + +void G1DefaultAllocator::set_survivor_full(AllocationContext_t context) { + _survivor_is_full = true; +} + +void G1DefaultAllocator::set_old_full(AllocationContext_t context) { + _old_is_full = true; +} + G1PLAB::G1PLAB(size_t gclab_word_size) : PLAB(gclab_word_size), _retired(true) { } @@ -165,22 +184,6 @@ HeapWord* G1Allocator::par_allocate_during_gc(InCSetState dest, } } -bool G1Allocator::survivor_is_full(AllocationContext_t context) const { - return _survivor_is_full; -} - -bool G1Allocator::old_is_full(AllocationContext_t context) const { - return _old_is_full; -} - -void G1Allocator::set_survivor_full(AllocationContext_t context) { - _survivor_is_full = true; -} - -void G1Allocator::set_old_full(AllocationContext_t context) { - _old_is_full = true; -} - HeapWord* G1Allocator::survivor_attempt_allocation(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size, @@ -232,11 +235,6 @@ HeapWord* G1Allocator::old_attempt_allocation(size_t min_word_size, return result; } -void G1Allocator::init_gc_alloc_regions(EvacuationInfo& evacuation_info) { - _survivor_is_full = false; - _old_is_full = false; -} - G1PLABAllocator::G1PLABAllocator(G1Allocator* allocator) : _g1h(G1CollectedHeap::heap()), _allocator(allocator), diff --git a/hotspot/src/share/vm/gc/g1/g1Allocator.hpp b/hotspot/src/share/vm/gc/g1/g1Allocator.hpp index f58b248bd4e..e2db5c8dd0c 100644 --- a/hotspot/src/share/vm/gc/g1/g1Allocator.hpp +++ b/hotspot/src/share/vm/gc/g1/g1Allocator.hpp @@ -38,19 +38,16 @@ class EvacuationInfo; // Also keeps track of retained regions across GCs. class G1Allocator : public CHeapObj { friend class VMStructs; -private: - bool _survivor_is_full; - bool _old_is_full; protected: G1CollectedHeap* _g1h; virtual MutatorAllocRegion* mutator_alloc_region(AllocationContext_t context) = 0; - virtual bool survivor_is_full(AllocationContext_t context) const; - virtual bool old_is_full(AllocationContext_t context) const; + virtual bool survivor_is_full(AllocationContext_t context) const = 0; + virtual bool old_is_full(AllocationContext_t context) const = 0; - virtual void set_survivor_full(AllocationContext_t context); - virtual void set_old_full(AllocationContext_t context); + virtual void set_survivor_full(AllocationContext_t context) = 0; + virtual void set_old_full(AllocationContext_t context) = 0; // Accessors to the allocation regions. virtual SurvivorGCAllocRegion* survivor_gc_alloc_region(AllocationContext_t context) = 0; @@ -67,7 +64,7 @@ protected: size_t* actual_word_size, AllocationContext_t context); public: - G1Allocator(G1CollectedHeap* heap) : _g1h(heap), _survivor_is_full(false), _old_is_full(false) { } + G1Allocator(G1CollectedHeap* heap) : _g1h(heap) { } virtual ~G1Allocator() { } static G1Allocator* create_allocator(G1CollectedHeap* g1h); @@ -79,7 +76,7 @@ public: virtual void init_mutator_alloc_region() = 0; virtual void release_mutator_alloc_region() = 0; - virtual void init_gc_alloc_regions(EvacuationInfo& evacuation_info); + virtual void init_gc_alloc_regions(EvacuationInfo& evacuation_info) = 0; virtual void release_gc_alloc_regions(EvacuationInfo& evacuation_info) = 0; virtual void abandon_gc_alloc_regions() = 0; @@ -119,6 +116,9 @@ public: // and old generation allocation region. // Can retain the (single) old generation allocation region across GCs. class G1DefaultAllocator : public G1Allocator { +private: + bool _survivor_is_full; + bool _old_is_full; protected: // Alloc region used to satisfy mutator allocation requests. MutatorAllocRegion _mutator_alloc_region; @@ -135,6 +135,12 @@ protected: public: G1DefaultAllocator(G1CollectedHeap* heap); + virtual bool survivor_is_full(AllocationContext_t context) const; + virtual bool old_is_full(AllocationContext_t context) const ; + + virtual void set_survivor_full(AllocationContext_t context); + virtual void set_old_full(AllocationContext_t context); + virtual void init_mutator_alloc_region(); virtual void release_mutator_alloc_region(); From 2e94af3f3d7010e89852721d1fda7a226e8ffb6c Mon Sep 17 00:00:00 2001 From: Avik Niyogi Date: Tue, 17 Nov 2015 19:09:37 +0400 Subject: [PATCH 111/260] 7124218: Space should select cell in the JTable Reviewed-by: rchamyal, alexsch --- .../JTable/7124218/SelectEditTableCell.java | 201 ++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 jdk/test/javax/swing/JTable/7124218/SelectEditTableCell.java diff --git a/jdk/test/javax/swing/JTable/7124218/SelectEditTableCell.java b/jdk/test/javax/swing/JTable/7124218/SelectEditTableCell.java new file mode 100644 index 00000000000..6191ddf04f8 --- /dev/null +++ b/jdk/test/javax/swing/JTable/7124218/SelectEditTableCell.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 7124218 + * @summary verifies different behaviour of SPACE and ENTER in JTable + * @library ../../regtesthelpers + * @build Util + * @run main SelectEditTableCell + */ +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import javax.swing.DefaultListSelectionModel; +import javax.swing.JFrame; +import javax.swing.JTable; +import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +public class SelectEditTableCell { + + private static JFrame frame; + private static JTable table; + private static Robot robot; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.delay(2000); + UIManager.LookAndFeelInfo[] lookAndFeelArray + = UIManager.getInstalledLookAndFeels(); + for (UIManager.LookAndFeelInfo lookAndFeelItem : lookAndFeelArray) { + executeCase(lookAndFeelItem.getClassName()); + } + + } + + private static void executeCase(String lookAndFeelString) throws Exception { + if (tryLookAndFeel(lookAndFeelString)) { + createUI(lookAndFeelString); + robot.delay(2000); + runTestCase(); + robot.delay(2000); + cleanUp(); + robot.delay(2000); + } + + } + + private static void createUI(final String lookAndFeelString) + throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + String[][] data = {{"Foo"}}; + String[] cols = {"One"}; + table = new JTable(data, cols); + table.setSelectionMode( + DefaultListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + frame = new JFrame(lookAndFeelString); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.getContentPane().add(table); + frame.pack(); + frame.setSize(500, frame.getSize().height); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.toFront(); + } + }); + } + + private static void runTestCase() throws Exception { + Point centerPoint; + centerPoint = Util.getCenterPoint(table); + LookAndFeel lookAndFeel = UIManager.getLookAndFeel(); + robot.mouseMove(centerPoint.x, centerPoint.y); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + table.clearSelection(); + if (table.isEditing() || table.isCellSelected(0, 0)) { + // assumption is bad, bail + frame.dispose(); + throw new AssertionError("Failed assumption: assumed no" + + "editing and no selection."); + } + } + }); + robot.waitForIdle(); + int fetchKeyCode; + keyTap(fetchKeyCode = isMac(lookAndFeel) + ? KeyEvent.VK_ENTER : KeyEvent.VK_SPACE); + final int keyCode = fetchKeyCode; + robot.waitForIdle(); + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + if (!table.isCellSelected(0, 0)) { + frame.dispose(); + throw new RuntimeException(((keyCode == KeyEvent.VK_ENTER) + ? "Enter" : "Space") + + " should select cell"); + } + } + }); + robot.waitForIdle(); + keyTap(KeyEvent.VK_SPACE); + robot.waitForIdle(); + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + if (!table.isEditing()) { + frame.dispose(); + throw new RuntimeException("Space should start editing"); + } + table.getCellEditor().cancelCellEditing(); + table.clearSelection(); + if (table.isEditing() || table.isCellSelected(0, 0)) { + // assumption is bad, bail + frame.dispose(); + throw new AssertionError("Failed assumption: assumed no " + + "editing and no selection."); + } + } + }); + robot.waitForIdle(); + // hitting a letter key will start editing + keyTap(KeyEvent.VK_A); + keyTap(KeyEvent.VK_SPACE); + keyTap(KeyEvent.VK_A); + robot.waitForIdle(); + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + if (table.isCellSelected(0, 0)) { + frame.dispose(); + throw new RuntimeException("Space should not select when " + + "already editing."); + } + } + }); + } + + private static void cleanUp() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame.dispose(); + } + }); + } + + private static boolean isMac(LookAndFeel lookAndFeel) { + + return lookAndFeel.toString().toLowerCase().contains("mac"); + } + + private static void keyTap(int keyCode) { + robot.keyPress(keyCode); + robot.keyRelease(keyCode); + } + + private static boolean tryLookAndFeel(String lookAndFeelString) + throws Exception { + try { + UIManager.setLookAndFeel( + lookAndFeelString); + + } catch (UnsupportedLookAndFeelException + | ClassNotFoundException + | InstantiationException + | IllegalAccessException e) { + return false; + } + return true; + } +} From 1e176777dbe507ea94e838d858733a7cfaaade7f Mon Sep 17 00:00:00 2001 From: Avik Niyogi Date: Tue, 17 Nov 2015 19:29:04 +0400 Subject: [PATCH 112/260] 8132770: Test javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java fails in MacOSX Reviewed-by: rchamyal, alexsch --- .../FocusTraversal/FocusTraversal.java | 170 +++++++++++++----- 1 file changed, 125 insertions(+), 45 deletions(-) diff --git a/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java b/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java index 53e975447d4..34a7cfe0206 100644 --- a/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java +++ b/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java @@ -22,43 +22,82 @@ */ /* @test - @bug 8129940 - @summary JRadioButton does not honor non-standard FocusTraversalKeys - @author Semyon Sadetsky - */ - -import javax.swing.*; -import java.awt.*; + @bug 8129940 8132770 + @summary JRadioButton should run custom FocusTraversalKeys for all LaFs + @run main FocusTraversal + */ +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.KeyboardFocusManager; +import java.awt.Robot; import java.awt.event.KeyEvent; import java.util.HashSet; import java.util.Set; +import javax.swing.ButtonGroup; +import javax.swing.FocusManager; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JTextField; +import javax.swing.KeyStroke; +import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; public class FocusTraversal { private static JFrame frame; private static JRadioButton a; + private static JRadioButton b; + private static JRadioButton c; private static JRadioButton d; private static JTextField next; private static JTextField prev; + private static Robot robot; public static void main(String[] args) throws Exception { + + robot = new Robot(); + robot.delay(2000); + UIManager.LookAndFeelInfo[] lookAndFeelArray + = UIManager.getInstalledLookAndFeels(); + for (UIManager.LookAndFeelInfo lookAndFeelItem : lookAndFeelArray) { + executeCase(lookAndFeelItem.getClassName()); + } + } + + private static void executeCase(String lookAndFeelString) + throws Exception { + if (tryLookAndFeel(lookAndFeelString)) { + createUI(lookAndFeelString); + robot.delay(2000); + runTestCase(); + robot.delay(2000); + cleanUp(); + robot.delay(2000); + } + } + + private static void createUI(final String lookAndFeelString) + throws Exception { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { - frame = new JFrame("FocusTraversalTest"); - frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frame.setUndecorated(true); - Set keystrokes = new HashSet(); keystrokes.add(KeyStroke.getKeyStroke("TAB")); keystrokes.add(KeyStroke.getKeyStroke("ENTER")); + frame = new JFrame("FocusTraversalTest " + lookAndFeelString); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setUndecorated(true); frame.setFocusTraversalKeys( KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, keystrokes); a = new JRadioButton("a"); - JRadioButton b = new JRadioButton("b"); - JRadioButton c = new JRadioButton("c"); + b = new JRadioButton("b"); + c = new JRadioButton("c"); d = new JRadioButton("d"); ButtonGroup radioButtonGroup = new ButtonGroup(); @@ -84,61 +123,102 @@ public class FocusTraversal { frame.add(root); frame.pack(); + frame.setLocationRelativeTo(null); frame.setVisible(true); + frame.toFront(); } }); + } + private static void runTestCase() throws Exception { + LookAndFeel lookAndFeel = UIManager.getLookAndFeel(); + focusOn(a); + if (isExcludedLookAndFeel(lookAndFeel)) { + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); + isFocusOwner(b, "forward"); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.waitForIdle(); + isFocusOwner(a, "backward"); + + } else { + + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); + isFocusOwner(next, "forward"); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.waitForIdle(); + isFocusOwner(d, "backward"); + } + + } + + private static boolean isExcludedLookAndFeel(LookAndFeel lookAndFeel) { + + return lookAndFeel.toString().toLowerCase().contains("aqua") + || lookAndFeel.toString().toLowerCase().contains("nimbus") + || lookAndFeel.toString().toLowerCase().contains("gtk"); + } + + private static void focusOn(Component component) + throws Exception { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { - a.requestFocus(); + component.requestFocusInWindow(); } }); + } - Robot robot = new Robot(); - robot.waitForIdle(); - - robot.setAutoDelay(200); - - robot.keyPress(KeyEvent.VK_ENTER); - robot.keyRelease(KeyEvent.VK_ENTER); - robot.waitForIdle(); - + private static void isFocusOwner(Component queriedFocusOwner, + String direction) + throws Exception { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { - Component focusOwner = - FocusManager.getCurrentManager().getFocusOwner(); - if (focusOwner != next) { + Component actualFocusOwner + = FocusManager.getCurrentManager().getFocusOwner(); + if (actualFocusOwner != queriedFocusOwner) { + frame.dispose(); throw new RuntimeException( - "Focus component is wrong after forward key " + focusOwner); + "Focus component is wrong after " + direction + + " direction "); + } } }); + } - robot.keyPress(KeyEvent.VK_SHIFT); - robot.keyPress(KeyEvent.VK_TAB); - robot.keyRelease(KeyEvent.VK_TAB); - robot.keyRelease(KeyEvent.VK_SHIFT); - robot.waitForIdle(); + private static boolean tryLookAndFeel(String lookAndFeelString) + throws Exception { + + try { + UIManager.setLookAndFeel( + lookAndFeelString); + + } catch (UnsupportedLookAndFeelException + | ClassNotFoundException + | InstantiationException + | IllegalAccessException e) { + return false; + } + return true; + } + + private static void cleanUp() throws Exception { SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - Component focusOwner = - FocusManager.getCurrentManager().getFocusOwner(); - if (focusOwner != d) { - throw new RuntimeException( - "Focus component is wrong after backward key " + focusOwner); - } - } - }); - SwingUtilities.invokeLater(new Runnable() { @Override public void run() { frame.dispose(); } }); - System.out.println("ok"); - } } From 73b1044258a2bb0ac6a89c5dd10254ed7599c274 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 17 Nov 2015 19:15:48 +0300 Subject: [PATCH 113/260] 8039412: Stack overflow on Linux using DialogTypeSelection.NATIVE Reviewed-by: prr, rchamyal --- .../classes/sun/print/RasterPrinterJob.java | 14 ++++- .../PrinterJob/PageDlgStackOverflowTest.java | 53 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 jdk/test/java/awt/print/PrinterJob/PageDlgStackOverflowTest.java diff --git a/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java index b3225679369..e5024b20764 100644 --- a/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java +++ b/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java @@ -740,7 +740,19 @@ public abstract class RasterPrinterJob extends PrinterJob { } updatePageAttributes(service, page); - PageFormat newPage = pageDialog(attributes); + PageFormat newPage = null; + DialogTypeSelection dts = + (DialogTypeSelection)attributes.get(DialogTypeSelection.class); + if (dts == DialogTypeSelection.NATIVE) { + // Remove DialogTypeSelection.NATIVE to prevent infinite loop in + // RasterPrinterJob. + attributes.remove(DialogTypeSelection.class); + newPage = pageDialog(attributes); + // restore attribute + attributes.add(DialogTypeSelection.NATIVE); + } else { + newPage = pageDialog(attributes); + } if (newPage == null) { return page; diff --git a/jdk/test/java/awt/print/PrinterJob/PageDlgStackOverflowTest.java b/jdk/test/java/awt/print/PrinterJob/PageDlgStackOverflowTest.java new file mode 100644 index 00000000000..ffe695d6f48 --- /dev/null +++ b/jdk/test/java/awt/print/PrinterJob/PageDlgStackOverflowTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.awt.print.PrinterJob; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.DialogTypeSelection; + +/** + * @test + * @bug 8039412 + * @run main/manual PageDlgStackOverflowTest + * @summary Calling pageDialog() after printDialog with + * DialogTypeSelection.NATIVE should not result in StackOverflowError + */ +public class PageDlgStackOverflowTest { + + public static void main(String args[]) { + PrinterJob job = PrinterJob.getPrinterJob(); + if (job == null) { + return; + } + PrintRequestAttributeSet pSet = + new HashPrintRequestAttributeSet(); + pSet.add(DialogTypeSelection.NATIVE); + job.printDialog(pSet); + try { + job.pageDialog(pSet); + } catch (StackOverflowError e) { + throw new RuntimeException("StackOverflowError is thrown"); + } + } +} + From 18cd974bce1c4802a8b1841a0a609145a3f728b3 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 18 Nov 2015 00:20:15 +0300 Subject: [PATCH 114/260] 8067059: PrinterJob.pageDialog() with DialogSelectionType.NATIVE returns a PageFormat when cancelled Reviewed-by: jgodinez, prr --- .../classes/sun/print/RasterPrinterJob.java | 11 +++- .../java/awt/print/PrinterJob/PageDlgApp.java | 65 +++++++++++++++++++ 2 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 jdk/test/java/awt/print/PrinterJob/PageDlgApp.java diff --git a/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java index e5024b20764..585e6e495b8 100644 --- a/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java +++ b/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java @@ -778,8 +778,15 @@ public abstract class RasterPrinterJob extends PrinterJob { // Check for native, note that default dialog is COMMON. if (dlg == DialogTypeSelection.NATIVE) { PrintService pservice = getPrintService(); - PageFormat page = pageDialog(attributeToPageFormat(pservice, - attributes)); + PageFormat pageFrmAttrib = attributeToPageFormat(pservice, + attributes); + PageFormat page = pageDialog(pageFrmAttrib); + + // If user cancels the dialog, pageDialog() will return the original + // page object and as per spec, we should return null in that case. + if (page == pageFrmAttrib) { + return null; + } updateAttributesWithPageFormat(pservice, page, attributes); return page; } diff --git a/jdk/test/java/awt/print/PrinterJob/PageDlgApp.java b/jdk/test/java/awt/print/PrinterJob/PageDlgApp.java new file mode 100644 index 00000000000..e07e8ffd6cf --- /dev/null +++ b/jdk/test/java/awt/print/PrinterJob/PageDlgApp.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.awt.Component; +import java.awt.print.PrinterJob; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.DialogTypeSelection; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +/** + * @test + * @bug 8067059 + * @run main/manual PageDlgApp + * @summary Test if cancelling dialog returns null when + * PrinterJob.pageDialog() with DialogSelectionType.NATIVE is called + */ +public class PageDlgApp { + + public static void main(String[] args) throws Exception { + + String[] instructions = + { + "Visual inspection of the dialog is needed. ", + "It should be a Printer Job Setup Dialog", + "Do nothing except Cancel", + "You must NOT press OK", + }; + SwingUtilities.invokeAndWait(() -> { + JOptionPane.showMessageDialog( + (Component) null, + instructions, + "information", JOptionPane.INFORMATION_MESSAGE); + }); + PrinterJob pj = PrinterJob.getPrinterJob(); + PrintRequestAttributeSet pSet = new HashPrintRequestAttributeSet(); + pSet.add(DialogTypeSelection.NATIVE); + if ((pj.pageDialog(pSet)) != null) { + throw + new RuntimeException("PrinterJob.pageDialog(PrintRequestAttributeSet)" + + " does not return null when dialog is cancelled"); + } + } +} + From e8c5bc2024e510cb1746498c322ce9267967a5e6 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 17 Nov 2015 16:40:52 -0500 Subject: [PATCH 115/260] 8143014: Access PtrQueue member offsets through derived classes Moved accessors to derived classes and updated callers. Reviewed-by: tschatzl, jmasa, twisti --- .../cpu/aarch64/vm/c1_Runtime1_aarch64.cpp | 10 +++--- .../cpu/aarch64/vm/macroAssembler_aarch64.cpp | 14 ++++----- hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp | 20 ++++++------ hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp | 8 ++--- .../src/cpu/sparc/vm/c1_Runtime1_sparc.cpp | 12 +++---- .../src/cpu/sparc/vm/macroAssembler_sparc.cpp | 24 +++++++------- hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp | 8 ++--- hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp | 14 ++++----- .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 19 +++++++----- hotspot/src/share/vm/c1/c1_LIRGenerator.cpp | 6 ++-- hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp | 12 +++++++ hotspot/src/share/vm/gc/g1/ptrQueue.hpp | 14 +++++++-- hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp | 17 ++++++++++ hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp | 31 ++++++++++++++++++- hotspot/src/share/vm/opto/compile.cpp | 2 +- hotspot/src/share/vm/opto/escape.cpp | 4 +-- hotspot/src/share/vm/opto/graphKit.cpp | 16 +++++----- hotspot/src/share/vm/opto/macro.cpp | 2 +- hotspot/src/share/vm/runtime/vmStructs.cpp | 12 +++---- 19 files changed, 157 insertions(+), 88 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp index a68da825e62..77498c35972 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp @@ -1169,12 +1169,12 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { const Register tmp = rscratch1; Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active())); + SATBMarkQueue::byte_offset_of_active())); Address queue_index(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_index())); + SATBMarkQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_buf())); + SATBMarkQueue::byte_offset_of_buf())); Label done; Label runtime; @@ -1219,9 +1219,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { const Register thread = rthread; Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_index())); + DirtyCardQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf())); + DirtyCardQueue::byte_offset_of_buf())); const Register card_addr = rscratch2; ExternalAddress cardtable((address) ct->byte_map_base); diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index a827da7a5be..8a59f261512 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -3487,18 +3487,18 @@ void MacroAssembler::g1_write_barrier_pre(Register obj, assert_different_registers(obj, pre_val, tmp); Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active())); + SATBMarkQueue::byte_offset_of_active())); Address index(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_index())); + SATBMarkQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_buf())); + SATBMarkQueue::byte_offset_of_buf())); // Is marking active? - if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { ldrw(tmp, in_progress); } else { - assert(in_bytes(PtrQueue::byte_width_of_active()) == 1, "Assumption"); + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); ldrb(tmp, in_progress); } cbzw(tmp, done); @@ -3566,9 +3566,9 @@ void MacroAssembler::g1_write_barrier_post(Register store_addr, assert(thread == rthread, "must be"); Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_index())); + DirtyCardQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf())); + DirtyCardQueue::byte_offset_of_buf())); BarrierSet* bs = Universe::heap()->barrier_set(); CardTableModRefBS* ct = (CardTableModRefBS*)bs; diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index 3310f37f57a..38cf28d094a 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -2633,11 +2633,11 @@ void MacroAssembler::g1_write_barrier_pre(Register Robj, RegisterOrConstant offs Label runtime, filtered; // Is marking active? - if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { - lwz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_active()), R16_thread); + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + lwz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), R16_thread); } else { - guarantee(in_bytes(PtrQueue::byte_width_of_active()) == 1, "Assumption"); - lbz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_active()), R16_thread); + guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + lbz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), R16_thread); } cmpdi(CCR0, Rtmp1, 0); beq(CCR0, filtered); @@ -2672,13 +2672,13 @@ void MacroAssembler::g1_write_barrier_pre(Register Robj, RegisterOrConstant offs // (The index field is typed as size_t.) const Register Rbuffer = Rtmp1, Rindex = Rtmp2; - ld(Rindex, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_index()), R16_thread); + ld(Rindex, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()), R16_thread); cmpdi(CCR0, Rindex, 0); beq(CCR0, runtime); // If index == 0, goto runtime. - ld(Rbuffer, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_buf()), R16_thread); + ld(Rbuffer, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf()), R16_thread); addi(Rindex, Rindex, -wordSize); // Decrement index. - std(Rindex, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_index()), R16_thread); + std(Rindex, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()), R16_thread); // Record the previous value. stdx(Rpre_val, Rbuffer, Rindex); @@ -2757,13 +2757,13 @@ void MacroAssembler::g1_write_barrier_post(Register Rstore_addr, Register Rnew_v const Register Rqueue_index = Rtmp2, Rqueue_buf = Rtmp3; - ld(Rqueue_index, in_bytes(JavaThread::dirty_card_queue_offset() + PtrQueue::byte_offset_of_index()), R16_thread); + ld(Rqueue_index, in_bytes(JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_index()), R16_thread); cmpdi(CCR0, Rqueue_index, 0); beq(CCR0, runtime); // index == 0 then jump to runtime - ld(Rqueue_buf, in_bytes(JavaThread::dirty_card_queue_offset() + PtrQueue::byte_offset_of_buf()), R16_thread); + ld(Rqueue_buf, in_bytes(JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_buf()), R16_thread); addi(Rqueue_index, Rqueue_index, -wordSize); // decrement index - std(Rqueue_index, in_bytes(JavaThread::dirty_card_queue_offset() + PtrQueue::byte_offset_of_index()), R16_thread); + std(Rqueue_index, in_bytes(JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_index()), R16_thread); stdx(Rcard_addr, Rqueue_buf, Rqueue_index); // store card b(filtered); diff --git a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp index 1f0d252229d..1dbb5c04f29 100644 --- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp @@ -630,11 +630,11 @@ class StubGenerator: public StubCodeGenerator { Label filtered; // Is marking active? - if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { - __ lwz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_active()), R16_thread); + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ lwz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), R16_thread); } else { - guarantee(in_bytes(PtrQueue::byte_width_of_active()) == 1, "Assumption"); - __ lbz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_active()), R16_thread); + guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ lbz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), R16_thread); } __ cmpdi(CCR0, Rtmp1, 0); __ beq(CCR0, filtered); diff --git a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp index 766b00a6bd8..45bfab26f45 100644 --- a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp @@ -857,13 +857,13 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { bool with_frame = false; // I don't know if we can do with-frame. int satb_q_index_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_index()); + SATBMarkQueue::byte_offset_of_index()); int satb_q_buf_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_buf()); + SATBMarkQueue::byte_offset_of_buf()); __ bind(restart); - // Load the index into the SATB buffer. PtrQueue::_index is a + // 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); @@ -961,14 +961,14 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { int dirty_card_q_index_byte_offset = in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_index()); + DirtyCardQueue::byte_offset_of_index()); int dirty_card_q_buf_byte_offset = in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf()); + DirtyCardQueue::byte_offset_of_buf()); __ bind(restart); - // Get the index into the update buffer. PtrQueue::_index is + // 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); diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp index a6d5cd68e47..9f5d807b390 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp @@ -3632,19 +3632,19 @@ static void generate_satb_log_enqueue(bool with_frame) { int satb_q_index_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_index()); + SATBMarkQueue::byte_offset_of_index()); int satb_q_buf_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_buf()); + SATBMarkQueue::byte_offset_of_buf()); - assert(in_bytes(PtrQueue::byte_width_of_index()) == sizeof(intptr_t) && - in_bytes(PtrQueue::byte_width_of_buf()) == sizeof(intptr_t), + assert(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t) && + in_bytes(SATBMarkQueue::byte_width_of_buf()) == sizeof(intptr_t), "check sizes in assembly below"); __ bind(restart); - // Load the index into the SATB buffer. PtrQueue::_index is a size_t + // 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, L0); @@ -3736,17 +3736,17 @@ void MacroAssembler::g1_write_barrier_pre(Register obj, } // Is marking active? - if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { ld(G2, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active()), + SATBMarkQueue::byte_offset_of_active()), tmp); } else { - guarantee(in_bytes(PtrQueue::byte_width_of_active()) == 1, + guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); ldsb(G2, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active()), + SATBMarkQueue::byte_offset_of_active()), tmp); } @@ -3847,13 +3847,13 @@ static void generate_dirty_card_log_enqueue(jbyte* byte_map_base) { int dirty_card_q_index_byte_offset = in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_index()); + DirtyCardQueue::byte_offset_of_index()); int dirty_card_q_buf_byte_offset = in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf()); + DirtyCardQueue::byte_offset_of_buf()); __ bind(restart); - // Load the index into the update buffer. PtrQueue::_index is + // Load 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, L0); diff --git a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp index 02c0bed270d..c977465cfc5 100644 --- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp @@ -1622,9 +1622,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { NOT_LP64(__ get_thread(thread);) Address queue_index(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_index())); + SATBMarkQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_buf())); + SATBMarkQueue::byte_offset_of_buf())); Label done; Label runtime; @@ -1698,9 +1698,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread); Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_index())); + DirtyCardQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf())); + DirtyCardQueue::byte_offset_of_buf())); __ push(rax); __ push(rcx); diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 100ea5962c6..37d117e6b23 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -4248,18 +4248,18 @@ void MacroAssembler::g1_write_barrier_pre(Register obj, } Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active())); + SATBMarkQueue::byte_offset_of_active())); Address index(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_index())); + SATBMarkQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_buf())); + SATBMarkQueue::byte_offset_of_buf())); // Is marking active? - if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { cmpl(in_progress, 0); } else { - assert(in_bytes(PtrQueue::byte_width_of_active()) == 1, "Assumption"); + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); cmpb(in_progress, 0); } jcc(Assembler::equal, done); @@ -4346,9 +4346,9 @@ void MacroAssembler::g1_write_barrier_post(Register store_addr, #endif // _LP64 Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_index())); + DirtyCardQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf())); + DirtyCardQueue::byte_offset_of_buf())); CardTableModRefBS* ct = barrier_set_cast(Universe::heap()->barrier_set()); diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 7b924e25ed9..e6e051131de 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -1193,9 +1193,12 @@ public class HotSpotVMConfig { @HotSpotVMConstant(name = "frame::interpreter_frame_sender_sp_offset", archs = {"amd64"}) @Stable public int frameInterpreterFrameSenderSpOffset; @HotSpotVMConstant(name = "frame::interpreter_frame_last_sp_offset", archs = {"amd64"}) @Stable public int frameInterpreterFrameLastSpOffset; - @HotSpotVMField(name = "PtrQueue::_active", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueActiveOffset; - @HotSpotVMField(name = "PtrQueue::_buf", type = "void**", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueBufferOffset; - @HotSpotVMField(name = "PtrQueue::_index", type = "size_t", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueIndexOffset; + @HotSpotVMConstant(name = "dirtyCardQueueBufferOffset") @Stable private int dirtyCardQueueBufferOffset; + @HotSpotVMConstant(name = "dirtyCardQueueIndexOffset") @Stable private int dirtyCardQueueIndexOffset; + + @HotSpotVMConstant(name = "satbMarkQueueBufferOffset") @Stable private int satbMarkQueueBufferOffset; + @HotSpotVMConstant(name = "satbMarkQueueIndexOffset") @Stable private int satbMarkQueueIndexOffset; + @HotSpotVMConstant(name = "satbMarkQueueActiveOffset") @Stable private int satbMarkQueueActiveOffset; @HotSpotVMField(name = "OSThread::_interrupted", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int osThreadInterruptedOffset; @@ -1396,23 +1399,23 @@ public class HotSpotVMConfig { // G1 Collector Related Values. public int g1CardQueueIndexOffset() { - return javaThreadDirtyCardQueueOffset + ptrQueueIndexOffset; + return javaThreadDirtyCardQueueOffset + dirtyCardQueueIndexOffset; } public int g1CardQueueBufferOffset() { - return javaThreadDirtyCardQueueOffset + ptrQueueBufferOffset; + return javaThreadDirtyCardQueueOffset + dirtyCardQueueBufferOffset; } public int g1SATBQueueMarkingOffset() { - return javaThreadSatbMarkQueueOffset + ptrQueueActiveOffset; + return javaThreadSatbMarkQueueOffset + satbMarkQueueActiveOffset; } public int g1SATBQueueIndexOffset() { - return javaThreadSatbMarkQueueOffset + ptrQueueIndexOffset; + return javaThreadSatbMarkQueueOffset + satbMarkQueueIndexOffset; } public int g1SATBQueueBufferOffset() { - return javaThreadSatbMarkQueueOffset + ptrQueueBufferOffset; + return javaThreadSatbMarkQueueOffset + satbMarkQueueBufferOffset; } @HotSpotVMField(name = "java_lang_Class::_klass_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int klassOffset; diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index a45d221f740..627c48f4a05 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -1464,10 +1464,10 @@ void LIRGenerator::G1SATBCardTableModRef_pre_barrier(LIR_Opr addr_opr, LIR_Opr p bool do_load, bool patch, CodeEmitInfo* info) { // First we test whether marking is in progress. BasicType flag_type; - if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { flag_type = T_INT; } else { - guarantee(in_bytes(PtrQueue::byte_width_of_active()) == 1, + 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. @@ -1477,7 +1477,7 @@ void LIRGenerator::G1SATBCardTableModRef_pre_barrier(LIR_Opr addr_opr, LIR_Opr p LIR_Address* mark_active_flag_addr = new LIR_Address(thrd, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active()), + SATBMarkQueue::byte_offset_of_active()), flag_type); // Read the marking-in-progress flag. LIR_Opr flag_val = new_register(T_INT); diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp index 965c83b1d67..f3f9bb18a07 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp @@ -72,6 +72,18 @@ public: void **get_buf() { return _buf;} size_t get_index() { return _index;} void reinitialize() { _buf = 0; _sz = 0; _index = 0;} + + // Compiler support. + static ByteSize byte_offset_of_index() { + return PtrQueue::byte_offset_of_index(); + } + using PtrQueue::byte_width_of_index; + + static ByteSize byte_offset_of_buf() { + return PtrQueue::byte_offset_of_buf(); + } + using PtrQueue::byte_width_of_buf; + }; diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp index 39f1c931e74..707d591c0c0 100644 --- a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp @@ -140,19 +140,27 @@ public: } // To support compiler. + +protected: + template static ByteSize byte_offset_of_index() { - return byte_offset_of(PtrQueue, _index); + return byte_offset_of(Derived, _index); } + static ByteSize byte_width_of_index() { return in_ByteSize(sizeof(size_t)); } + template static ByteSize byte_offset_of_buf() { - return byte_offset_of(PtrQueue, _buf); + return byte_offset_of(Derived, _buf); } + static ByteSize byte_width_of_buf() { return in_ByteSize(sizeof(void*)); } + template static ByteSize byte_offset_of_active() { - return byte_offset_of(PtrQueue, _active); + return byte_offset_of(Derived, _active); } + static ByteSize byte_width_of_active() { return in_ByteSize(sizeof(bool)); } }; diff --git a/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp b/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp index 0ca3b45c2ff..e3591f4f7df 100644 --- a/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp @@ -68,6 +68,23 @@ public: void print(const char* name); static void print(const char* name, void** buf, size_t index, size_t sz); #endif // PRODUCT + + // Compiler support. + static ByteSize byte_offset_of_index() { + return PtrQueue::byte_offset_of_index(); + } + using PtrQueue::byte_width_of_index; + + static ByteSize byte_offset_of_buf() { + return PtrQueue::byte_offset_of_buf(); + } + using PtrQueue::byte_width_of_buf; + + static ByteSize byte_offset_of_active() { + return PtrQueue::byte_offset_of_active(); + } + using PtrQueue::byte_width_of_active; + }; class SATBMarkQueueSet: public PtrQueueSet { diff --git a/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp b/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp index 97daf08e66d..1fad2b64637 100644 --- a/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp +++ b/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp @@ -28,6 +28,7 @@ #include "gc/g1/g1CollectedHeap.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/g1/heapRegionManager.hpp" +#include "utilities/macros.hpp" #define VM_STRUCTS_G1(nonstatic_field, static_field) \ \ @@ -62,6 +63,34 @@ \ nonstatic_field(HeapRegionSetCount, _length, uint) \ nonstatic_field(HeapRegionSetCount, _capacity, size_t) \ + \ + nonstatic_field(PtrQueue, _active, bool) \ + nonstatic_field(PtrQueue, _buf, void**) \ + nonstatic_field(PtrQueue, _index, size_t) \ + + +#define VM_INT_CONSTANTS_G1(declare_constant, declare_constant_with_value) \ + \ + JVMCI_ONLY( \ + declare_constant_with_value( \ + "dirtyCardQueueBufferOffset", \ + in_bytes(DirtyCardQueue::byte_offset_of_buf())) \ + declare_constant_with_value( \ + "dirtyCardQueueIndexOffset", \ + in_bytes(DirtyCardQueue::byte_offset_of_index())) \ + ) /* JVMCI_ONLY */ \ + \ + JVMCI_ONLY( \ + declare_constant_with_value( \ + "satbMarkQueueBufferOffset", \ + in_bytes(SATBMarkQueue::byte_offset_of_buf())) \ + declare_constant_with_value( \ + "satbMarkQueueIndexOffset", \ + in_bytes(SATBMarkQueue::byte_offset_of_index())) \ + declare_constant_with_value( \ + "satbMarkQueueActiveOffset", \ + in_bytes(SATBMarkQueue::byte_offset_of_active())) \ + ) /* JVMCI_ONLY */ \ #define VM_TYPES_G1(declare_type, declare_toplevel_type) \ @@ -76,10 +105,10 @@ declare_toplevel_type(HeapRegionSetBase) \ declare_toplevel_type(HeapRegionSetCount) \ declare_toplevel_type(G1MonitoringSupport) \ + declare_toplevel_type(PtrQueue) \ \ declare_toplevel_type(G1CollectedHeap*) \ declare_toplevel_type(HeapRegion*) \ declare_toplevel_type(G1MonitoringSupport*) \ - #endif // SHARE_VM_GC_G1_VMSTRUCTS_G1_HPP diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 032fe0a6f6f..268a54e60e0 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -3549,7 +3549,7 @@ void Compile::verify_graph_edges(bool no_dead_code) { void Compile::verify_barriers() { if (UseG1GC) { // Verify G1 pre-barriers - const int marking_offset = in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_active()); + const int marking_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()); ResourceArea *area = Thread::current()->resource_area(); Unique_Node_List visited(area); diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index fac8c4d67fe..92ed15ca3da 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -539,11 +539,11 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de if (tls->Opcode() == Op_ThreadLocal) { int offs = (int)igvn->find_intptr_t_con(adr->in(AddPNode::Offset), Type::OffsetBot); if (offs == in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_buf())) { + SATBMarkQueue::byte_offset_of_buf())) { break; // G1 pre barrier previous oop value store. } if (offs == in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf())) { + DirtyCardQueue::byte_offset_of_buf())) { break; // G1 post barrier card address store. } } diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index 397e6cb1c81..bcdf343aaf8 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -3986,16 +3986,16 @@ void GraphKit::g1_write_barrier_pre(bool do_load, float likely = PROB_LIKELY(0.999); float unlikely = PROB_UNLIKELY(0.999); - BasicType active_type = in_bytes(PtrQueue::byte_width_of_active()) == 4 ? T_INT : T_BYTE; - assert(in_bytes(PtrQueue::byte_width_of_active()) == 4 || in_bytes(PtrQueue::byte_width_of_active()) == 1, "flag width"); + BasicType active_type = in_bytes(SATBMarkQueue::byte_width_of_active()) == 4 ? T_INT : T_BYTE; + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 4 || in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "flag width"); // Offsets into the thread const int marking_offset = in_bytes(JavaThread::satb_mark_queue_offset() + // 648 - PtrQueue::byte_offset_of_active()); + SATBMarkQueue::byte_offset_of_active()); const int index_offset = in_bytes(JavaThread::satb_mark_queue_offset() + // 656 - PtrQueue::byte_offset_of_index()); + SATBMarkQueue::byte_offset_of_index()); const int buffer_offset = in_bytes(JavaThread::satb_mark_queue_offset() + // 652 - PtrQueue::byte_offset_of_buf()); + SATBMarkQueue::byte_offset_of_buf()); // Now the actual pointers into the thread Node* marking_adr = __ AddP(no_base, tls, __ ConX(marking_offset)); @@ -4008,7 +4008,7 @@ void GraphKit::g1_write_barrier_pre(bool do_load, // if (!marking) __ if_then(marking, BoolTest::ne, zero, unlikely); { BasicType index_bt = TypeX_X->basic_type(); - assert(sizeof(size_t) == type2aelembytes(index_bt), "Loading G1 PtrQueue::_index with wrong size."); + assert(sizeof(size_t) == type2aelembytes(index_bt), "Loading G1 SATBMarkQueue::_index with wrong size."); Node* index = __ load(__ ctrl(), index_adr, TypeX_X, index_bt, Compile::AliasIdxRaw); if (do_load) { @@ -4196,9 +4196,9 @@ void GraphKit::g1_write_barrier_post(Node* oop_store, // Offsets into the thread const int index_offset = in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_index()); + DirtyCardQueue::byte_offset_of_index()); const int buffer_offset = in_bytes(JavaThread::dirty_card_queue_offset() + - PtrQueue::byte_offset_of_buf()); + DirtyCardQueue::byte_offset_of_buf()); // Pointers into the thread diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index bd5ceaa9b7a..4551560a6e4 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -290,7 +290,7 @@ void PhaseMacroExpand::eliminate_card_mark(Node* p2x) { cmpx->in(1)->is_Load()) { Node* adr = cmpx->in(1)->as_Load()->in(MemNode::Address); const int marking_offset = in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active()); + SATBMarkQueue::byte_offset_of_active()); if (adr->is_AddP() && adr->in(AddPNode::Base) == top() && adr->in(AddPNode::Address)->Opcode() == Op_ThreadLocal && adr->in(AddPNode::Offset) == MakeConX(marking_offset)) { diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 784c8be3eb7..b38fd110b2d 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -1378,10 +1378,6 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(vframeArrayElement, _bci, int) \ nonstatic_field(vframeArrayElement, _method, Method*) \ \ - nonstatic_field(PtrQueue, _active, bool) \ - nonstatic_field(PtrQueue, _buf, void**) \ - nonstatic_field(PtrQueue, _index, size_t) \ - \ nonstatic_field(AccessFlags, _flags, jint) \ nonstatic_field(elapsedTimer, _counter, jlong) \ nonstatic_field(elapsedTimer, _active, bool) \ @@ -2273,8 +2269,6 @@ typedef CompactHashtable SymbolCompactHashTable; /* Miscellaneous types */ \ /***************/ \ \ - declare_toplevel_type(PtrQueue) \ - \ /* freelist */ \ declare_toplevel_type(FreeChunk*) \ declare_toplevel_type(AdaptiveFreeList*) \ @@ -3066,6 +3060,9 @@ typedef CompactHashtable SymbolCompactHashTable; #define GENERATE_VM_INT_CONSTANT_ENTRY(name) \ { QUOTE(name), (int32_t) name }, +#define GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY(name, value) \ + { (name), (int32_t)(value) }, + #define GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY(name, value) \ { name, (int32_t) value }, @@ -3296,6 +3293,9 @@ VMIntConstantEntry VMStructs::localHotSpotVMIntConstants[] = { VM_INT_CONSTANTS_CMS(GENERATE_VM_INT_CONSTANT_ENTRY) VM_INT_CONSTANTS_PARNEW(GENERATE_VM_INT_CONSTANT_ENTRY) + + VM_INT_CONSTANTS_G1(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY) #endif // INCLUDE_ALL_GCS #if INCLUDE_TRACE From 581c251007ffd4a6544e08f45d27671891684c52 Mon Sep 17 00:00:00 2001 From: Yumin Qi Date: Tue, 17 Nov 2015 15:14:29 -0800 Subject: [PATCH 116/260] 8087223: InterfaceMethod CP entry pointing to a class should cause ICCE Check constantTag for class constant data consistency at method resolution Reviewed-by: coleenp, vlivanov --- hotspot/src/share/vm/ci/ciEnv.cpp | 9 +- hotspot/src/share/vm/ci/ciEnv.hpp | 3 +- hotspot/src/share/vm/ci/ciMethod.cpp | 3 +- .../src/share/vm/interpreter/linkResolver.cpp | 21 +- .../src/share/vm/interpreter/linkResolver.hpp | 21 +- .../src/share/vm/jvmci/jvmciCompilerToVM.cpp | 4 +- hotspot/src/share/vm/jvmci/jvmciEnv.cpp | 8 +- hotspot/src/share/vm/jvmci/jvmciEnv.hpp | 3 +- hotspot/src/share/vm/oops/constantPool.cpp | 23 ++ hotspot/src/share/vm/oops/constantPool.hpp | 3 + hotspot/src/share/vm/prims/methodHandles.cpp | 6 +- hotspot/src/share/vm/runtime/javaCalls.cpp | 6 +- hotspot/src/share/vm/runtime/reflection.cpp | 2 +- .../runtime/8087223/BadMethodHandles.java | 250 ++++++++++++++++++ hotspot/test/runtime/8087223/IntfMethod.java | 156 +++++++++++ 15 files changed, 496 insertions(+), 22 deletions(-) create mode 100644 hotspot/test/runtime/8087223/BadMethodHandles.java create mode 100644 hotspot/test/runtime/8087223/IntfMethod.java diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index 9c9d7b300c2..2e096bb303a 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -704,13 +704,14 @@ Method* ciEnv::lookup_method(InstanceKlass* accessor, InstanceKlass* holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc) { + Bytecodes::Code bc, + constantTag tag) { EXCEPTION_CONTEXT; KlassHandle h_accessor(THREAD, accessor); KlassHandle h_holder(THREAD, holder); LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL)); methodHandle dest_method; - LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true); + LinkInfo link_info(h_holder, name, sig, h_accessor, LinkInfo::needs_access_check, tag); switch (bc) { case Bytecodes::_invokestatic: dest_method = @@ -796,7 +797,9 @@ ciMethod* ciEnv::get_method_by_index_impl(const constantPoolHandle& cpool, if (holder_is_accessible) { // Our declared holder is loaded. InstanceKlass* lookup = declared_holder->get_instanceKlass(); - Method* m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc); + constantTag tag = cpool->tag_ref_at(index); + assert(accessor->get_instanceKlass() == cpool->pool_holder(), "not the pool holder?"); + Method* m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc, tag); if (m != NULL && (bc == Bytecodes::_invokestatic ? m->method_holder()->is_not_initialized() diff --git a/hotspot/src/share/vm/ci/ciEnv.hpp b/hotspot/src/share/vm/ci/ciEnv.hpp index b1a95bd38f6..abffa79e4e5 100644 --- a/hotspot/src/share/vm/ci/ciEnv.hpp +++ b/hotspot/src/share/vm/ci/ciEnv.hpp @@ -158,7 +158,8 @@ private: InstanceKlass* holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc); + Bytecodes::Code bc, + constantTag tag); // Get a ciObject from the object factory. Ensures uniqueness // of ciObjects. diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index 0acf602a4cc..50aa4dc42c1 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -786,7 +786,8 @@ ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, boo Symbol* h_name = name()->get_symbol(); Symbol* h_signature = signature()->get_symbol(); - LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass, check_access); + LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass, + check_access ? LinkInfo::needs_access_check : LinkInfo::skip_access_check); methodHandle m; // Only do exact lookup if receiver klass has been linked. Otherwise, // the vtable has not been setup, and the LinkResolver will fail. diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index 173ec0ec667..42dc138319a 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -245,6 +245,7 @@ LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, TRAPS) { // Get name, signature, and static klass _name = pool->name_ref_at(index); _signature = pool->signature_ref_at(index); + _tag = pool->tag_ref_at(index); _current_klass = KlassHandle(THREAD, pool->pool_holder()); // Coming from the constant pool always checks access @@ -681,6 +682,15 @@ methodHandle LinkResolver::resolve_method(const LinkInfo& link_info, THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } + // check tag at call is method + if (!link_info.tag().is_invalid() && !link_info.tag().is_method()) { + ResourceMark rm(THREAD); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Resolving to non regular method %s", link_info.method_string()); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + } + + // 2. lookup method in resolved klass and its super klasses methodHandle resolved_method = lookup_method_in_klasses(link_info, true, false, CHECK_NULL); @@ -740,6 +750,14 @@ methodHandle LinkResolver::resolve_interface_method(const LinkInfo& link_info, THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } + // check tag at call is an interface method + if (!link_info.tag().is_invalid() && !link_info.tag().is_interface_method()) { + ResourceMark rm(THREAD); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Resolving to non interface method %s", link_info.method_string()); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + } + // lookup method in this interface or its super, java.lang.Object // JDK8: also look for static methods methodHandle resolved_method = lookup_method_in_klasses(link_info, false, true, CHECK_NULL); @@ -917,7 +935,8 @@ void LinkResolver::resolve_static_call(CallInfo& result, resolved_klass->initialize(CHECK); // Use updated LinkInfo (to reresolve with resolved_klass as method_holder?) LinkInfo new_info(resolved_klass, link_info.name(), link_info.signature(), - link_info.current_klass(), link_info.check_access()); + link_info.current_klass(), + link_info.check_access() ? LinkInfo::needs_access_check : LinkInfo::skip_access_check); resolved_method = linktime_resolve_static_method(new_info, CHECK); } diff --git a/hotspot/src/share/vm/interpreter/linkResolver.hpp b/hotspot/src/share/vm/interpreter/linkResolver.hpp index 198eefbe2c0..919496bfa69 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp @@ -135,20 +135,35 @@ class LinkInfo : public StackObj { KlassHandle _resolved_klass; // class that the constant pool entry points to KlassHandle _current_klass; // class that owns the constant pool bool _check_access; + constantTag _tag; public: + enum AccessCheck { + needs_access_check, + skip_access_check + }; + LinkInfo(const constantPoolHandle& pool, int index, TRAPS); + // Condensed information from other call sites within the vm. - LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature, - KlassHandle current_klass, bool check_access = true) : + LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature, KlassHandle current_klass, + AccessCheck check_access = needs_access_check, + constantTag tag = JVM_CONSTANT_Invalid) : _resolved_klass(resolved_klass), _name(name), _signature(signature), _current_klass(current_klass), - _check_access(check_access) {} + _check_access(check_access == needs_access_check && current_klass.not_null()), _tag(tag) {} + + // Case where we just find the method and don't check access against the current class + LinkInfo(KlassHandle resolved_klass, Symbol*name, Symbol* signature) : + _resolved_klass(resolved_klass), + _name(name), _signature(signature), _current_klass(NULL), + _check_access(false), _tag(JVM_CONSTANT_Invalid) {} // accessors Symbol* name() const { return _name; } Symbol* signature() const { return _signature; } KlassHandle resolved_klass() const { return _resolved_klass; } KlassHandle current_klass() const { return _current_klass; } + constantTag tag() const { return _tag; } bool check_access() const { return _check_access; } char* method_string() const; diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp index c0f773e279b..c4d3dfbb6b2 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -574,7 +574,7 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t if (holder_klass->is_interface()) { // do link-time resolution to check all access rules. - LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true); + LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass); methodHandle resolved_method = LinkResolver::linktime_resolve_interface_method_or_null(link_info); if (resolved_method.is_null() || resolved_method->is_private()) { return NULL; @@ -586,7 +586,7 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t return JNIHandles::make_local(THREAD, result); } else { // do link-time resolution to check all access rules. - LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true); + LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass); methodHandle resolved_method = LinkResolver::linktime_resolve_virtual_method_or_null(link_info); if (resolved_method.is_null()) { return NULL; diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp index 348a28601be..808d4924ea8 100644 --- a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp @@ -282,11 +282,12 @@ methodHandle JVMCIEnv::lookup_method(instanceKlassHandle& h_accessor, instanceKlassHandle& h_holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc) { + Bytecodes::Code bc, + constantTag tag) { JVMCI_EXCEPTION_CONTEXT; LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL)); methodHandle dest_method; - LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true); + LinkInfo link_info(h_holder, name, sig, h_accessor, LinkInfo::needs_access_check, tag); switch (bc) { case Bytecodes::_invokestatic: dest_method = @@ -359,7 +360,8 @@ methodHandle JVMCIEnv::get_method_by_index_impl(const constantPoolHandle& cpool, if (holder_is_accessible) { // Our declared holder is loaded. instanceKlassHandle lookup = get_instance_klass_for_declared_method_holder(holder); - methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc); + constantTag tag = cpool->tag_ref_at(index); + methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc, tag); if (!m.is_null() && (bc == Bytecodes::_invokestatic ? InstanceKlass::cast(m->method_holder())->is_not_initialized() diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp index f0291efde26..4f9cf9271b7 100644 --- a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp @@ -125,7 +125,8 @@ private: instanceKlassHandle& holder, Symbol* name, Symbol* sig, - Bytecodes::Code bc); + Bytecodes::Code bc, + constantTag tag); private: diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp index 006a1e5b5a6..9900c45c816 100644 --- a/hotspot/src/share/vm/oops/constantPool.cpp +++ b/hotspot/src/share/vm/oops/constantPool.cpp @@ -409,6 +409,19 @@ int ConstantPool::impl_name_and_type_ref_index_at(int which, bool uncached) { return extract_high_short_from_int(ref_index); } +constantTag ConstantPool::impl_tag_ref_at(int which, bool uncached) { + int pool_index = which; + if (!uncached && cache() != NULL) { + if (ConstantPool::is_invokedynamic_index(which)) { + // Invokedynamic index is index into resolved_references + pool_index = invokedynamic_cp_cache_entry_at(which)->constant_pool_index(); + } else { + // change byte-ordering and go via cache + pool_index = remap_instruction_operand_from_cache(which); + } + } + return tag_at(pool_index); +} int ConstantPool::impl_klass_ref_index_at(int which, bool uncached) { guarantee(!ConstantPool::is_invokedynamic_index(which), @@ -664,6 +677,7 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, in int callee_index = this_cp->method_handle_klass_index_at(index); Symbol* name = this_cp->method_handle_name_ref_at(index); Symbol* signature = this_cp->method_handle_signature_ref_at(index); + constantTag m_tag = this_cp->tag_at(this_cp->method_handle_index_at(index)); if (PrintMiscellaneous) tty->print_cr("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s", ref_kind, index, this_cp->method_handle_index_at(index), @@ -672,6 +686,15 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, in { Klass* k = klass_at_impl(this_cp, callee_index, true, CHECK_NULL); callee = KlassHandle(THREAD, k); } + if ((callee->is_interface() && m_tag.is_method()) || + (!callee->is_interface() && m_tag.is_interface_method())) { + ResourceMark rm(THREAD); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Inconsistent constant data for %s.%s%s at index %d", + callee->name()->as_C_string(), name->as_C_string(), signature->as_C_string(), index); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); + } + KlassHandle klass(THREAD, this_cp->pool_holder()); Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind, callee, name, signature, diff --git a/hotspot/src/share/vm/oops/constantPool.hpp b/hotspot/src/share/vm/oops/constantPool.hpp index 99d77253be9..740e9f77bac 100644 --- a/hotspot/src/share/vm/oops/constantPool.hpp +++ b/hotspot/src/share/vm/oops/constantPool.hpp @@ -664,6 +664,8 @@ class ConstantPool : public Metadata { int remap_instruction_operand_from_cache(int operand); // operand must be biased by CPCACHE_INDEX_TAG + constantTag tag_ref_at(int cp_cache_index) { return impl_tag_ref_at(cp_cache_index, false); } + // Lookup for entries consisting of (name_index, signature_index) int name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt) int signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt) @@ -784,6 +786,7 @@ class ConstantPool : public Metadata { Symbol* impl_signature_ref_at(int which, bool uncached); int impl_klass_ref_index_at(int which, bool uncached); int impl_name_and_type_ref_index_at(int which, bool uncached); + constantTag impl_tag_ref_at(int which, bool uncached); // Used while constructing constant pool (only by ClassFileParser) jint klass_index_at(int which) { diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index 0f58dde7063..0a72474dfa3 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -679,7 +679,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS case IS_METHOD: { CallInfo result; - LinkInfo link_info(defc, name, type, caller, caller.not_null()); + LinkInfo link_info(defc, name, type, caller); { assert(!HAS_PENDING_EXCEPTION, ""); if (ref_kind == JVM_REF_invokeStatic) { @@ -716,7 +716,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS case IS_CONSTRUCTOR: { CallInfo result; - LinkInfo link_info(defc, name, type, caller, caller.not_null()); + LinkInfo link_info(defc, name, type, caller); { assert(!HAS_PENDING_EXCEPTION, ""); if (name == vmSymbols::object_initializer_name()) { @@ -737,7 +737,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS fieldDescriptor result; // find_field initializes fd if found { assert(!HAS_PENDING_EXCEPTION, ""); - LinkInfo link_info(defc, name, type, caller, /*check_access*/false); + LinkInfo link_info(defc, name, type, caller, LinkInfo::skip_access_check); LinkResolver::resolve_field(result, link_info, Bytecodes::_nop, false, THREAD); if (HAS_PENDING_EXCEPTION) { return empty; diff --git a/hotspot/src/share/vm/runtime/javaCalls.cpp b/hotspot/src/share/vm/runtime/javaCalls.cpp index 9acd0200b29..82cbd26b2d4 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.cpp +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp @@ -183,7 +183,7 @@ void JavaCalls::call_virtual(JavaValue* result, KlassHandle spec_klass, Symbol* CallInfo callinfo; Handle receiver = args->receiver(); KlassHandle recvrKlass(THREAD, receiver.is_null() ? (Klass*)NULL : receiver->klass()); - LinkInfo link_info(spec_klass, name, signature, KlassHandle(), /*check_access*/false); + LinkInfo link_info(spec_klass, name, signature); LinkResolver::resolve_virtual_call( callinfo, receiver, recvrKlass, link_info, true, CHECK); methodHandle method = callinfo.selected_method(); @@ -220,7 +220,7 @@ void JavaCalls::call_virtual(JavaValue* result, Handle receiver, KlassHandle spe void JavaCalls::call_special(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) { CallInfo callinfo; - LinkInfo link_info(klass, name, signature, KlassHandle(), /*check_access*/false); + LinkInfo link_info(klass, name, signature); LinkResolver::resolve_special_call(callinfo, link_info, CHECK); methodHandle method = callinfo.selected_method(); assert(method.not_null(), "should have thrown exception"); @@ -255,7 +255,7 @@ void JavaCalls::call_special(JavaValue* result, Handle receiver, KlassHandle kla void JavaCalls::call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) { CallInfo callinfo; - LinkInfo link_info(klass, name, signature, KlassHandle(), /*check_access*/false); + LinkInfo link_info(klass, name, signature); LinkResolver::resolve_static_call(callinfo, link_info, true, CHECK); methodHandle method = callinfo.selected_method(); assert(method.not_null(), "should have thrown exception"); diff --git a/hotspot/src/share/vm/runtime/reflection.cpp b/hotspot/src/share/vm/runtime/reflection.cpp index 45746d67c7c..d44ce3869fa 100644 --- a/hotspot/src/share/vm/runtime/reflection.cpp +++ b/hotspot/src/share/vm/runtime/reflection.cpp @@ -830,7 +830,7 @@ methodHandle Reflection::resolve_interface_call(instanceKlassHandle klass, const Symbol* signature = method->signature(); Symbol* name = method->name(); LinkResolver::resolve_interface_call(info, receiver, recv_klass, - LinkInfo(klass, name, signature, KlassHandle(), false), + LinkInfo(klass, name, signature), true, CHECK_(methodHandle())); return info.selected_method(); diff --git a/hotspot/test/runtime/8087223/BadMethodHandles.java b/hotspot/test/runtime/8087223/BadMethodHandles.java new file mode 100644 index 00000000000..57defac0fe2 --- /dev/null +++ b/hotspot/test/runtime/8087223/BadMethodHandles.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * $bug 8087223 + * @summary Adding constantTag to keep method call consistent with it. + * @compile -XDignore.symbol.file BadMethodHandles.java + * @run main/othervm BadMethodHandles + */ + +import jdk.internal.org.objectweb.asm.*; +import java.io.FileOutputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +public class BadMethodHandles { + + static byte[] dumpBadInterfaceMethodref() { + ClassWriter cw = new ClassWriter(0); + cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadInterfaceMethodref", null, "java/lang/Object", null); + Handle handle1 = + new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "m", "()V"); + Handle handle2 = + new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "staticM", "()V"); + + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null); + mv.visitCode(); + mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitLdcInsn("hello from m"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null); + mv.visitCode(); + mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitLdcInsn("hello from staticM"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 1); + mv.visitEnd(); + } + + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null); + mv.visitCode(); + // REF_invokeStatic + mv.visitLdcInsn(handle1); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null); + mv.visitCode(); + // REF_invokeStatic + mv.visitLdcInsn(handle2); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + cw.visitEnd(); + return cw.toByteArray(); + } + + static byte[] dumpIBad() { + ClassWriter cw = new ClassWriter(0); + cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "IBad", null, "java/lang/Object", null); + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null); + mv.visitCode(); + mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitLdcInsn("hello from m"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null); + mv.visitCode(); + mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitLdcInsn("hello from staticM"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 1); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + static byte[] dumpBadMethodref() { + ClassWriter cw = new ClassWriter(0); + cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadMethodref", null, "java/lang/Object", new String[]{"IBad"}); + Handle handle1 = + new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "m", "()V"); + Handle handle2 = + new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "staticM", "()V"); + + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null); + mv.visitCode(); + // REF_invokeStatic + mv.visitLdcInsn(handle1); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null); + mv.visitCode(); + // REF_invokeStatic + mv.visitLdcInsn(handle2); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + cw.visitEnd(); + return cw.toByteArray(); + } + static class CL extends ClassLoader { + @Override + protected Class findClass(String name) throws ClassNotFoundException { + byte[] classBytes = null; + switch (name) { + case "BadInterfaceMethodref": classBytes = dumpBadInterfaceMethodref(); break; + case "BadMethodref" : classBytes = dumpBadMethodref(); break; + case "IBad" : classBytes = dumpIBad(); break; + default : throw new ClassNotFoundException(name); + } + return defineClass(name, classBytes, 0, classBytes.length); + } + } + + public static void main(String[] args) throws Throwable { + try (FileOutputStream fos = new FileOutputStream("BadInterfaceMethodref.class")) { + fos.write(dumpBadInterfaceMethodref()); + } + try (FileOutputStream fos = new FileOutputStream("IBad.class")) { + fos.write(dumpIBad()); + } + try (FileOutputStream fos = new FileOutputStream("BadMethodref.class")) { + fos.write(dumpBadMethodref()); + } + + Class cls = (new CL()).loadClass("BadInterfaceMethodref"); + String[] methods = {"runm", "runStaticM"}; + System.out.println("Test BadInterfaceMethodref:"); + int success = 0; + for (String name : methods) { + try { + System.out.printf("invoke %s: \n", name); + cls.getMethod(name).invoke(cls.newInstance()); + System.out.println("FAILED (no exception)"); // ICCE should be thrown + } catch (Throwable e) { + if (e instanceof InvocationTargetException && e.getCause() != null && + e.getCause() instanceof IncompatibleClassChangeError) { + System.out.println("PASSED"); + success++; + continue; + } else { + System.out.println("FAILED with exception"); + throw e; + } + } + } + if (success != methods.length) { + throw new Exception("BadInterfaceMethodRef Failed to catch IncompatibleClassChangeError"); + } + System.out.println("Test BadMethodref:"); + cls = (new CL()).loadClass("BadMethodref"); + success = 0; + for (String name : methods) { + try { + System.out.printf("invoke %s: \n", name); + cls.getMethod(name).invoke(cls.newInstance()); + System.out.println("FAILED (no exception)"); // ICCE should be thrown + } catch (Throwable e) { + if (e instanceof InvocationTargetException && e.getCause() != null && + e.getCause() instanceof IncompatibleClassChangeError) { + System.out.println("PASSED"); + success++; + continue; + } else { + System.out.println("FAILED with exception"); + throw e; + } + } + } + if (success != methods.length) { + throw new Exception("BadMethodRef Failed to catch IncompatibleClassChangeError"); + } + + } +} diff --git a/hotspot/test/runtime/8087223/IntfMethod.java b/hotspot/test/runtime/8087223/IntfMethod.java new file mode 100644 index 00000000000..a3a4ee3b8d8 --- /dev/null +++ b/hotspot/test/runtime/8087223/IntfMethod.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * $bug 8087223 + * @summary Adding constantTag to keep method call consistent with it. + * @compile -XDignore.symbol.file IntfMethod.java + * @run main/othervm IntfMethod + * @run main/othervm -Xint IntfMethod + * @run main/othervm -Xcomp IntfMethod + */ + + +import jdk.internal.org.objectweb.asm.*; +import java.io.FileOutputStream; +import java.lang.reflect.InvocationTargetException; +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +public class IntfMethod { + static byte[] dumpC() { + ClassWriter cw = new ClassWriter(0); + cw.visit(52, ACC_PUBLIC | ACC_SUPER, "C", null, "java/lang/Object", new String[]{"I"}); + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testSpecialIntf", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "I", "f1", "()V", /*itf=*/false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testStaticIntf", "()V", null, null); + mv.visitCode(); + mv.visitMethodInsn(INVOKESTATIC, "I", "f2", "()V", /*itf=*/false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testSpecialClass", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "C", "f1", "()V", /*itf=*/true); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f2", "()V", null, null); + mv.visitCode(); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testStaticClass", "()V", null, null); + mv.visitCode(); + mv.visitMethodInsn(INVOKESTATIC, "C", "f2", "()V", /*itf=*/true); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + static byte[] dumpI() { + ClassWriter cw = new ClassWriter(0); + cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "I", null, "java/lang/Object", null); + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "f1", "()V", null, null); + mv.visitCode(); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + mv.visitEnd(); + } + { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f2", "()V", null, null); + mv.visitCode(); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + static class CL extends ClassLoader { + @Override + protected Class findClass(String name) throws ClassNotFoundException { + byte[] classFile; + switch (name) { + case "I": classFile = dumpI(); break; + case "C": classFile = dumpC(); break; + default: + throw new ClassNotFoundException(name); + } + return defineClass(name, classFile, 0, classFile.length); + } + } + + public static void main(String[] args) throws Throwable { + Class cls = (new CL()).loadClass("C"); + try (FileOutputStream fos = new FileOutputStream("I.class")) { fos.write(dumpI()); } + try (FileOutputStream fos = new FileOutputStream("C.class")) { fos.write(dumpC()); } + + int success = 0; + for (String name : new String[] { "testSpecialIntf", "testStaticIntf", "testSpecialClass", "testStaticClass"}) { + System.out.printf("%s: ", name); + try { + cls.getMethod(name).invoke(cls.newInstance()); + System.out.println("FAILED"); + } catch (Throwable e) { + if (e instanceof InvocationTargetException && + e.getCause() != null && e.getCause() instanceof IncompatibleClassChangeError) { + System.out.println("PASSED"); + success++; + continue; + } + } + } + if (success != 4) throw new Exception("Failed to catch ICCE"); + } +} From b0439e6dbfc70f311e54464dc25657bdb09fa9c5 Mon Sep 17 00:00:00 2001 From: Alexander Scherbatiy Date: Wed, 18 Nov 2015 19:13:42 +0400 Subject: [PATCH 117/260] 8081411: Add an API for painting an icon with a SynthContext Reviewed-by: serb, azvegint --- .../java/swing/plaf/gtk/GTKIconFactory.java | 1 + .../com/sun/java/swing/plaf/gtk/GTKStyle.java | 2 +- .../javax/swing/plaf/nimbus/NimbusIcon.java | 4 +- .../swing/plaf/nimbus/NimbusLookAndFeel.java | 2 +- .../swing/plaf/synth/SynthGraphicsUtils.java | 69 +++++++- .../javax/swing/plaf/synth/SynthIcon.java | 82 ++++++++++ .../swing/plaf/synth/SynthLookAndFeel.java | 4 + .../plaf/synth/SynthMenuItemLayoutHelper.java | 13 +- .../swing/plaf/synth/SynthToolBarUI.java | 21 ++- .../javax/swing/plaf/synth/SynthTreeUI.java | 21 ++- .../sun/swing/plaf/synth/SynthIcon.java | 126 --------------- .../swing/plaf/synth/8081411/bug8081411.java | 147 ++++++++++++++++++ 12 files changed, 326 insertions(+), 166 deletions(-) create mode 100644 jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthIcon.java delete mode 100644 jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/SynthIcon.java create mode 100644 jdk/test/javax/swing/plaf/synth/8081411/bug8081411.java diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java index 44ccd4925ce..f83112c6537 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java @@ -24,6 +24,7 @@ */ package com.sun.java.swing.plaf.gtk; +import javax.swing.plaf.synth.SynthIcon; import java.util.*; import javax.swing.plaf.synth.*; import java.awt.*; diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java index 63322a6396a..160540aad78 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java @@ -36,7 +36,7 @@ import javax.swing.plaf.synth.*; import sun.awt.AppContext; import sun.awt.UNIXToolkit; import sun.swing.SwingUtilities2; -import sun.swing.plaf.synth.SynthIcon; +import javax.swing.plaf.synth.SynthIcon; import com.sun.java.swing.plaf.gtk.GTKEngine.WidgetType; import static java.awt.RenderingHints.KEY_TEXT_ANTIALIASING; diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusIcon.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusIcon.java index 696f0a220f8..41e055908b4 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusIcon.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusIcon.java @@ -25,7 +25,7 @@ package javax.swing.plaf.nimbus; import javax.swing.Painter; -import sun.swing.plaf.synth.SynthIcon; +import javax.swing.plaf.synth.SynthIcon; import javax.swing.plaf.synth.SynthContext; import javax.swing.*; @@ -37,7 +37,7 @@ import javax.swing.plaf.UIResource; * An icon that delegates to a painter. * @author rbair */ -class NimbusIcon extends SynthIcon { +class NimbusIcon implements SynthIcon { private int width; private int height; private String prefix; diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java index 71e00249752..c46c6b2e5b1 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java @@ -50,7 +50,7 @@ import javax.swing.border.TitledBorder; import javax.swing.plaf.BorderUIResource; import javax.swing.plaf.ColorUIResource; import sun.swing.ImageIconUIResource; -import sun.swing.plaf.synth.SynthIcon; +import javax.swing.plaf.synth.SynthIcon; import sun.swing.plaf.GTKKeybindings; import sun.swing.plaf.WindowsKeybindings; import sun.security.action.GetPropertyAction; diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthGraphicsUtils.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthGraphicsUtils.java index bf66cee2bcb..e91257ed0f0 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthGraphicsUtils.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthGraphicsUtils.java @@ -31,7 +31,6 @@ import java.awt.*; import javax.swing.*; import javax.swing.plaf.basic.BasicHTML; import javax.swing.text.*; -import sun.swing.plaf.synth.*; /** * Wrapper for primitive graphics calls. @@ -287,8 +286,8 @@ public class SynthGraphicsUtils { return new Dimension(dx, dy); } else if ((text == null) || ((icon != null) && (font == null))) { - return new Dimension(SynthIcon.getIconWidth(icon, ss) + dx, - SynthIcon.getIconHeight(icon, ss) + dy); + return new Dimension(getIconWidth(icon, ss) + dx, + getIconHeight(icon, ss) + dy); } else { FontMetrics fm = c.getFontMetrics(font); @@ -404,7 +403,7 @@ public class SynthGraphicsUtils { paintIconR.x += textOffset; } paintIconR.y += textOffset; - SynthIcon.paintIcon(icon, ss, g, paintIconR.x, paintIconR.y, + paintIcon(icon, ss, g, paintIconR.x, paintIconR.y, paintIconR.width, paintIconR.height); g.setColor(color); } @@ -423,6 +422,62 @@ public class SynthGraphicsUtils { } } + /** + * Returns the icon's width. + * The {@code getIconWidth(context)} method is called for {@code SynthIcon}. + * + * @param icon the icon + * @param context {@code SynthContext} requesting the icon, may be null. + * @return an int specifying the width of the icon. + */ + public static int getIconWidth(Icon icon, SynthContext context) { + if (icon == null) { + return 0; + } + if (icon instanceof SynthIcon) { + return ((SynthIcon) icon).getIconWidth(context); + } + return icon.getIconWidth(); + } + + /** + * Returns the icon's height. + * The {@code getIconHeight(context)} method is called for {@code SynthIcon}. + * + * @param icon the icon + * @param context {@code SynthContext} requesting the icon, may be null. + * @return an int specifying the height of the icon. + */ + public static int getIconHeight(Icon icon, SynthContext context) { + if (icon == null) { + return 0; + } + if (icon instanceof SynthIcon) { + return ((SynthIcon) icon).getIconHeight(context); + } + return icon.getIconHeight(); + } + + /** + * Paints the icon. The {@code paintIcon(context, g, x, y, width, height)} + * method is called for {@code SynthIcon}. + * + * @param icon the icon + * @param context identifies hosting region, may be null. + * @param g the graphics context + * @param x the x location to paint to + * @param y the y location to paint to + * @param width the width of the region to paint to, may be 0 + * @param height the height of the region to paint to, may be 0 + */ + public static void paintIcon(Icon icon, SynthContext context, Graphics g, + int x, int y, int width, int height) { + if (icon instanceof SynthIcon) { + ((SynthIcon) icon).paintIcon(context, g, x, y, width, height); + } else if (icon != null) { + icon.paintIcon(context.getComponent(), g, x, y); + } + } /** * A quick note about how preferred sizes are calculated... Generally @@ -561,7 +616,7 @@ public class SynthGraphicsUtils { if (icon != null) { Rectangle iconRect = lr.getIconRect(); - SynthIcon.paintIcon(icon, lh.getContext(), g, iconRect.x, + paintIcon(icon, lh.getContext(), g, iconRect.x, iconRect.y, iconRect.width, iconRect.height); } } @@ -571,7 +626,7 @@ public class SynthGraphicsUtils { MenuItemLayoutHelper.LayoutResult lr) { if (lh.getCheckIcon() != null) { Rectangle checkRect = lr.getCheckRect(); - SynthIcon.paintIcon(lh.getCheckIcon(), lh.getContext(), g, + paintIcon(lh.getCheckIcon(), lh.getContext(), g, checkRect.x, checkRect.y, checkRect.width, checkRect.height); } } @@ -610,7 +665,7 @@ public class SynthGraphicsUtils { MenuItemLayoutHelper.LayoutResult lr) { if (lh.getArrowIcon() != null) { Rectangle arrowRect = lr.getArrowRect(); - SynthIcon.paintIcon(lh.getArrowIcon(), lh.getContext(), g, + paintIcon(lh.getArrowIcon(), lh.getContext(), g, arrowRect.x, arrowRect.y, arrowRect.width, arrowRect.height); } } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthIcon.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthIcon.java new file mode 100644 index 00000000000..cd5fb0dd5e2 --- /dev/null +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthIcon.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javax.swing.plaf.synth; + +import java.awt.*; +import javax.swing.*; + +/** + * An icon that is passed a {@code SynthContext}. Subclasses need only implement + * the variants that take a {@code SynthContext}, but must be prepared for the + * {@code SynthContext} to be null. + * + * @author Scott Violet + */ +public interface SynthIcon extends Icon { + + /** + * Paints the icon at the specified location for the given synth context. + * + * @param context identifies hosting region, may be null. + * @param g the graphics context + * @param x the x location to paint to + * @param y the y location to paint to + * @param width the width of the region to paint to, may be 0 + * @param height the height of the region to paint to, may be 0 + */ + void paintIcon(SynthContext context, Graphics g, int x, int y, + int width, int height); + + /** + * Returns the icon's width for the given synth context. + * + * @param context {@code SynthContext} requesting the Icon, may be null. + * @return an int specifying the width of the icon. + */ + int getIconWidth(SynthContext context); + + /** + * Returns the icon's height for the given synth context. + * + * @param context {@code SynthContext} requesting the Icon, may be null. + * @return an int specifying the height of the icon. + */ + int getIconHeight(SynthContext context); + + @Override + default void paintIcon(Component c, Graphics g, int x, int y) { + paintIcon(null, g, x, y, getIconWidth(), getIconHeight()); + } + + @Override + default int getIconWidth() { + return getIconWidth(null); + } + + @Override + default int getIconHeight() { + return getIconHeight(null); + } +} diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java index fa4640dec73..3998b354ccb 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java @@ -53,6 +53,10 @@ import sun.swing.plaf.synth.*; * an example of providing your own SynthStyleFactory to * setStyleFactory. *

+ * {@link SynthIcon} interface provides + * {@code paintIcon(synthContext, graphics, x, y, width, height)} method that + * allows to draw the icon with the given {@code SynthContext}. + *

* Warning: * This class implements {@link Serializable} as a side effect of it * extending {@link BasicLookAndFeel}. It is not intended to be serialized. diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuItemLayoutHelper.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuItemLayoutHelper.java index 4cc1824a6eb..0e4a0afdcea 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuItemLayoutHelper.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthMenuItemLayoutHelper.java @@ -27,7 +27,6 @@ package javax.swing.plaf.synth; import sun.swing.StringUIClientPropertyKey; import sun.swing.MenuItemLayoutHelper; -import sun.swing.plaf.synth.SynthIcon; import javax.swing.*; import javax.swing.text.View; @@ -130,8 +129,8 @@ class SynthMenuItemLayoutHelper extends MenuItemLayoutHelper { protected void calcWidthsAndHeights() { // iconRect if (getIcon() != null) { - getIconSize().setWidth(SynthIcon.getIconWidth(getIcon(), context)); - getIconSize().setHeight(SynthIcon.getIconHeight(getIcon(), context)); + getIconSize().setWidth(SynthGraphicsUtils.getIconWidth(getIcon(), context)); + getIconSize().setHeight(SynthGraphicsUtils.getIconHeight(getIcon(), context)); } // accRect @@ -165,16 +164,16 @@ class SynthMenuItemLayoutHelper extends MenuItemLayoutHelper { // checkIcon if (getCheckIcon() != null) { getCheckSize().setWidth( - SynthIcon.getIconWidth(getCheckIcon(), context)); + SynthGraphicsUtils.getIconWidth(getCheckIcon(), context)); getCheckSize().setHeight( - SynthIcon.getIconHeight(getCheckIcon(), context)); + SynthGraphicsUtils.getIconHeight(getCheckIcon(), context)); } // arrowRect if (getArrowIcon() != null) { getArrowSize().setWidth( - SynthIcon.getIconWidth(getArrowIcon(), context)); + SynthGraphicsUtils.getIconWidth(getArrowIcon(), context)); getArrowSize().setHeight( - SynthIcon.getIconHeight(getArrowIcon(), context)); + SynthGraphicsUtils.getIconHeight(getArrowIcon(), context)); } } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthToolBarUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthToolBarUI.java index 51d2fefd17e..bf2b9298973 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthToolBarUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthToolBarUI.java @@ -41,7 +41,6 @@ import javax.swing.JSeparator; import javax.swing.JToolBar; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicToolBarUI; -import sun.swing.plaf.synth.SynthIcon; /** * Provides the Synth L&F UI delegate for @@ -281,10 +280,10 @@ public class SynthToolBarUI extends BasicToolBarUI if (handleIcon != null && toolBar.isFloatable()) { int startX = toolBar.getComponentOrientation().isLeftToRight() ? 0 : toolBar.getWidth() - - SynthIcon.getIconWidth(handleIcon, context); - SynthIcon.paintIcon(handleIcon, context, g, startX, 0, - SynthIcon.getIconWidth(handleIcon, context), - SynthIcon.getIconHeight(handleIcon, context)); + SynthGraphicsUtils.getIconWidth(handleIcon, context); + SynthGraphicsUtils.paintIcon(handleIcon, context, g, startX, 0, + SynthGraphicsUtils.getIconWidth(handleIcon, context), + SynthGraphicsUtils.getIconHeight(handleIcon, context)); } SynthContext subcontext = getContext( @@ -358,7 +357,7 @@ public class SynthToolBarUI extends BasicToolBarUI if (tb.getOrientation() == JToolBar.HORIZONTAL) { dim.width = tb.isFloatable() ? - SynthIcon.getIconWidth(handleIcon, context) : 0; + SynthGraphicsUtils.getIconWidth(handleIcon, context) : 0; Dimension compDim; for (int i = 0; i < tb.getComponentCount(); i++) { Component component = tb.getComponent(i); @@ -370,7 +369,7 @@ public class SynthToolBarUI extends BasicToolBarUI } } else { dim.height = tb.isFloatable() ? - SynthIcon.getIconHeight(handleIcon, context) : 0; + SynthGraphicsUtils.getIconHeight(handleIcon, context) : 0; Dimension compDim; for (int i = 0; i < tb.getComponentCount(); i++) { Component component = tb.getComponent(i); @@ -396,7 +395,7 @@ public class SynthToolBarUI extends BasicToolBarUI if (tb.getOrientation() == JToolBar.HORIZONTAL) { dim.width = tb.isFloatable() ? - SynthIcon.getIconWidth(handleIcon, context) : 0; + SynthGraphicsUtils.getIconWidth(handleIcon, context) : 0; Dimension compDim; for (int i = 0; i < tb.getComponentCount(); i++) { Component component = tb.getComponent(i); @@ -408,7 +407,7 @@ public class SynthToolBarUI extends BasicToolBarUI } } else { dim.height = tb.isFloatable() ? - SynthIcon.getIconHeight(handleIcon, context) : 0; + SynthGraphicsUtils.getIconHeight(handleIcon, context) : 0; Dimension compDim; for (int i = 0; i < tb.getComponentCount(); i++) { Component component = tb.getComponent(i); @@ -449,7 +448,7 @@ public class SynthToolBarUI extends BasicToolBarUI if (tb.getOrientation() == JToolBar.HORIZONTAL) { int handleWidth = tb.isFloatable() ? - SynthIcon.getIconWidth(handleIcon, context) : 0; + SynthGraphicsUtils.getIconWidth(handleIcon, context) : 0; // Note: contentRect does not take insets into account // since it is used for determining the bounds that are @@ -500,7 +499,7 @@ public class SynthToolBarUI extends BasicToolBarUI } } else { int handleHeight = tb.isFloatable() ? - SynthIcon.getIconHeight(handleIcon, context) : 0; + SynthGraphicsUtils.getIconHeight(handleIcon, context) : 0; // See notes above regarding the use of insets contentRect.x = 0; diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTreeUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTreeUI.java index 6f00c947aa0..603540c6a58 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTreeUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTreeUI.java @@ -47,7 +47,6 @@ import javax.swing.tree.TreeCellEditor; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; -import sun.swing.plaf.synth.SynthIcon; /** * Provides the Synth L&F UI delegate for @@ -610,10 +609,10 @@ public class SynthTreeUI extends BasicTreeUI @Override protected void drawCentered(Component c, Graphics graphics, Icon icon, int x, int y) { - int w = SynthIcon.getIconWidth(icon, paintContext); - int h = SynthIcon.getIconHeight(icon, paintContext); + int w = SynthGraphicsUtils.getIconWidth(icon, paintContext); + int h = SynthGraphicsUtils.getIconHeight(icon, paintContext); - SynthIcon.paintIcon(icon, paintContext, graphics, + SynthGraphicsUtils.paintIcon(icon, paintContext, graphics, findCenteredX(x, w), y - h/2, w, h); } @@ -780,16 +779,16 @@ public class SynthTreeUI extends BasicTreeUI // To get the correct context we return an instance of this that fetches // the SynthContext as needed. // - private class ExpandedIconWrapper extends SynthIcon { + private class ExpandedIconWrapper implements SynthIcon { public void paintIcon(SynthContext context, Graphics g, int x, int y, int w, int h) { if (context == null) { context = getContext(tree); - SynthIcon.paintIcon(expandedIcon, context, g, x, y, w, h); + SynthGraphicsUtils.paintIcon(expandedIcon, context, g, x, y, w, h); context.dispose(); } else { - SynthIcon.paintIcon(expandedIcon, context, g, x, y, w, h); + SynthGraphicsUtils.paintIcon(expandedIcon, context, g, x, y, w, h); } } @@ -797,11 +796,11 @@ public class SynthTreeUI extends BasicTreeUI int width; if (context == null) { context = getContext(tree); - width = SynthIcon.getIconWidth(expandedIcon, context); + width = SynthGraphicsUtils.getIconWidth(expandedIcon, context); context.dispose(); } else { - width = SynthIcon.getIconWidth(expandedIcon, context); + width = SynthGraphicsUtils.getIconWidth(expandedIcon, context); } return width; } @@ -810,11 +809,11 @@ public class SynthTreeUI extends BasicTreeUI int height; if (context == null) { context = getContext(tree); - height = SynthIcon.getIconHeight(expandedIcon, context); + height = SynthGraphicsUtils.getIconHeight(expandedIcon, context); context.dispose(); } else { - height = SynthIcon.getIconHeight(expandedIcon, context); + height = SynthGraphicsUtils.getIconHeight(expandedIcon, context); } return height; } diff --git a/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/SynthIcon.java b/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/SynthIcon.java deleted file mode 100644 index 75c4e8358d2..00000000000 --- a/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/SynthIcon.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package sun.swing.plaf.synth; - -import javax.swing.plaf.synth.*; -import java.awt.*; -import javax.swing.*; -import javax.swing.border.Border; -import javax.swing.plaf.UIResource; - -/** - * An icon that is passed a SynthContext. Subclasses need only implement - * the variants that take a SynthContext, but must be prepared for the - * SynthContext to be null. - * - * @author Scott Violet - */ -public abstract class SynthIcon implements Icon { - public static int getIconWidth(Icon icon, SynthContext context) { - if (icon == null) { - return 0; - } - if (icon instanceof SynthIcon) { - return ((SynthIcon)icon).getIconWidth(context); - } - return icon.getIconWidth(); - } - - public static int getIconHeight(Icon icon, SynthContext context) { - if (icon == null) { - return 0; - } - if (icon instanceof SynthIcon) { - return ((SynthIcon)icon).getIconHeight(context); - } - return icon.getIconHeight(); - } - - public static void paintIcon(Icon icon, SynthContext context, Graphics g, - int x, int y, int w, int h) { - if (icon instanceof SynthIcon) { - ((SynthIcon)icon).paintIcon(context, g, x, y, w, h); - } - else if (icon != null) { - icon.paintIcon(context.getComponent(), g, x, y); - } - } - - /** - * Paints the icon at the specified location. - * - * @param context Identifies hosting region, may be null. - * @param x x location to paint to - * @param y y location to paint to - * @param w Width of the region to paint to, may be 0 - * @param h Height of the region to paint to, may be 0 - */ - public abstract void paintIcon(SynthContext context, Graphics g, int x, - int y, int w, int h); - - /** - * Returns the desired width of the Icon. - * - * @param context SynthContext requesting the Icon, may be null. - * @return Desired width of the icon. - */ - public abstract int getIconWidth(SynthContext context); - - /** - * Returns the desired height of the Icon. - * - * @param context SynthContext requesting the Icon, may be null. - * @return Desired height of the icon. - */ - public abstract int getIconHeight(SynthContext context); - - /** - * Paints the icon. This is a cover method for - * paintIcon(null, g, x, y, 0, 0) - */ - public void paintIcon(Component c, Graphics g, int x, int y) { - paintIcon(null, g, x, y, 0, 0); - } - - /** - * Returns the icon's width. This is a cover methods for - * getIconWidth(null). - * - * @return an int specifying the fixed width of the icon. - */ - public int getIconWidth() { - return getIconWidth(null); - } - - /** - * Returns the icon's height. This is a cover method for - * getIconHeight(null). - * - * @return an int specifying the fixed height of the icon. - */ - public int getIconHeight() { - return getIconHeight(null); - } -} diff --git a/jdk/test/javax/swing/plaf/synth/8081411/bug8081411.java b/jdk/test/javax/swing/plaf/synth/8081411/bug8081411.java new file mode 100644 index 00000000000..f155425c3e9 --- /dev/null +++ b/jdk/test/javax/swing/plaf/synth/8081411/bug8081411.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import javax.swing.Icon; +import javax.swing.JMenuItem; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.plaf.synth.Region; +import javax.swing.plaf.synth.SynthConstants; +import javax.swing.plaf.synth.SynthContext; +import javax.swing.plaf.synth.SynthGraphicsUtils; +import javax.swing.plaf.synth.SynthIcon; +import javax.swing.plaf.synth.SynthLookAndFeel; +import javax.swing.plaf.synth.SynthStyle; + +/* + * @test + * @bug 8081411 + * @summary Add an API for painting an icon with a SynthContext + * @author Alexander Scherbatiy + */ +public class bug8081411 { + + private static final Color TEST_COLOR = new Color(71, 71, 72); + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(bug8081411::testSynthIcon); + } + + private static void testSynthIcon() { + + if (!checkAndSetNimbusLookAndFeel()) { + return; + } + + JMenuItem menu = new JMenuItem(); + Icon subMenuIcon = UIManager.getIcon("Menu.arrowIcon"); + + if (!(subMenuIcon instanceof SynthIcon)) { + throw new RuntimeException("Icon is not a SynthIcon!"); + } + + Region region = SynthLookAndFeel.getRegion(menu); + SynthStyle style = SynthLookAndFeel.getStyle(menu, region); + SynthContext synthContext = new SynthContext(menu, region, style, SynthConstants.ENABLED); + + int width = SynthGraphicsUtils.getIconWidth(subMenuIcon, synthContext); + int height = SynthGraphicsUtils.getIconHeight(subMenuIcon, synthContext); + paintAndCheckIcon(subMenuIcon, synthContext, width, height); + + int newWidth = width * 17; + int newHeight = height * 37; + Icon centeredIcon = new CenteredSynthIcon((SynthIcon) subMenuIcon, + newWidth, newHeight); + paintAndCheckIcon(centeredIcon, synthContext, newWidth, newHeight); + } + + private static void paintAndCheckIcon(Icon icon, SynthContext synthContext, + int width, int height) { + + BufferedImage buffImage = new BufferedImage(width, height, + BufferedImage.TYPE_INT_RGB); + Graphics g = buffImage.createGraphics(); + g.setColor(Color.RED); + g.fillRect(0, 0, width, height); + SynthGraphicsUtils.paintIcon(icon, synthContext, g, 0, 0, width, height); + g.dispose(); + + Color iconCenterColor = new Color(buffImage.getRGB(width / 2, height / 2)); + + if (!TEST_COLOR.equals(iconCenterColor)) { + throw new RuntimeException("Icon is painted incorrectly!"); + } + } + + private static boolean checkAndSetNimbusLookAndFeel() { + try { + for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { + if ("Nimbus".equals(info.getName())) { + UIManager.setLookAndFeel(info.getClassName()); + return true; + } + } + return false; + } catch (Exception ignore) { + return false; + } + } + + private static class CenteredSynthIcon implements SynthIcon { + + private final SynthIcon icon; + private final int width; + private final int height; + + public CenteredSynthIcon(SynthIcon icon, int width, int height) { + this.icon = icon; + this.width = width; + this.height = height; + } + + @Override + public void paintIcon(SynthContext syntContext, Graphics g, int x, int y, + int w, int h) { + int dw = icon.getIconWidth(syntContext); + int dh = icon.getIconHeight(syntContext); + int dx = width - dw; + int dy = height - dh; + icon.paintIcon(syntContext, g, x + dx / 2, y + dy / 2, + dw + 2, dh + 2); + } + + @Override + public int getIconWidth(SynthContext sc) { + return width; + } + + @Override + public int getIconHeight(SynthContext sc) { + return height; + } + } +} From 1777e00ccac09b897c0782ec3e57b35198b48688 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Wed, 18 Nov 2015 10:46:02 -0600 Subject: [PATCH 118/260] 8141641: Runtime: implement range for ErrorLogTimeout Implement range=(0, jlong_max/1000) Reviewed-by: coleenp, ddmitriev, dholmes --- hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp | 2 +- hotspot/src/share/vm/runtime/globals.hpp | 3 ++- hotspot/src/share/vm/runtime/thread.cpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp index b25f7ccdd28..ef45b27f0c6 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp @@ -279,7 +279,7 @@ void emit_range_double(const char* name, double min, double max) { // Generate func argument to pass into emit_range_xxx functions #define EMIT_RANGE_CHECK(a, b) , a, b -#define INITIAL_RANGES_SIZE 204 +#define INITIAL_RANGES_SIZE 205 GrowableArray* CommandLineFlagRangeList::_ranges = NULL; // Check the ranges of all flags that have them diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index fb61f555307..eeb61ea36a6 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1031,9 +1031,10 @@ public: product(bool, CreateCoredumpOnCrash, true, \ "Create core/mini dump on VM fatal error") \ \ - product(uintx, ErrorLogTimeout, 2 * 60, \ + product(uint64_t, ErrorLogTimeout, 2 * 60, \ "Timeout, in seconds, to limit the time spent on writing an " \ "error log in case of a crash.") \ + range(0, (uint64_t)max_jlong/1000) \ \ product_pd(bool, UseOSErrorReporting, \ "Let VM fatal error propagate to the OS (ie. WER on Windows)") \ diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index de7c4139059..5291b8025fa 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -1299,7 +1299,7 @@ void WatcherThread::run() { if (!ShowMessageBoxOnError && (OnError == NULL || OnError[0] == '\0') && Arguments::abort_hook() == NULL) { - os::sleep(this, ErrorLogTimeout * 60 * 1000, false); + os::sleep(this, (jlong)ErrorLogTimeout * 1000, false); // in seconds fdStream err(defaultStream::output_fd()); err.print_raw_cr("# [ timer expired, abort... ]"); // skip atexit/vm_exit/vm_abort hooks From 72756888e9da71b64efa5fd3cb4f113553436f8c Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 18 Nov 2015 11:47:55 -0500 Subject: [PATCH 119/260] 8141570: Fix Zero interpreter build for --disable-precompiled-headers Change to include atomic.inline.hpp and allocation.inline.hpp only in .cpp files and some build fixes from Kim to build on ubuntu without devkits Reviewed-by: kbarrett, sgehwolf, erikj --- hotspot/make/linux/makefiles/zeroshark.make | 16 ++++--- hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp | 1 + hotspot/src/share/vm/gc/g1/g1Allocator.cpp | 1 + .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 1 + hotspot/src/share/vm/gc/g1/g1EvacStats.cpp | 2 + hotspot/src/share/vm/gc/g1/g1EvacStats.hpp | 23 +++------- .../src/share/vm/gc/g1/g1EvacStats.inline.hpp | 45 +++++++++++++++++++ hotspot/src/share/vm/runtime/java.cpp | 1 + 8 files changed, 69 insertions(+), 21 deletions(-) create mode 100644 hotspot/src/share/vm/gc/g1/g1EvacStats.inline.hpp diff --git a/hotspot/make/linux/makefiles/zeroshark.make b/hotspot/make/linux/makefiles/zeroshark.make index 3c10770d42a..240946fee3a 100644 --- a/hotspot/make/linux/makefiles/zeroshark.make +++ b/hotspot/make/linux/makefiles/zeroshark.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. # Copyright 2007, 2008 Red Hat, Inc. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # @@ -25,8 +25,16 @@ # Setup common to Zero (non-Shark) and Shark versions of VM -# override this from the main file because some version of llvm do not like -Wundef -WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wunused-function -Wunused-value +# Some versions of llvm do not like -Wundef +ifeq ($(USE_CLANG), true) + WARNING_FLAGS += -Wno-undef +endif +# Suppress some warning flags that are normally turned on for hotspot, +# because some of the zero code has not been updated accordingly. +WARNING_FLAGS += -Wno-return-type \ + -Wno-format-nonliteral -Wno-format-security \ + -Wno-maybe-uninitialized + # The copied fdlibm routines in sharedRuntimeTrig.o must not be optimized OPT_CFLAGS/sharedRuntimeTrig.o = $(OPT_CFLAGS/NOOPT) @@ -42,5 +50,3 @@ endif ifeq ($(ARCH_DATA_MODEL), 64) CFLAGS += -D_LP64=1 endif - -OPT_CFLAGS/compactingPermGenGen.o = -O1 diff --git a/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp b/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp index 9a61b0da769..f7a9c8e8414 100644 --- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp +++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/g1/g1AllocRegion.inline.hpp" +#include "gc/g1/g1EvacStats.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "runtime/orderAccess.inline.hpp" diff --git a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp index 8bd8b376c72..665a7b5ed61 100644 --- a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp +++ b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/g1/g1Allocator.inline.hpp" #include "gc/g1/g1AllocRegion.inline.hpp" +#include "gc/g1/g1EvacStats.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1MarkSweep.hpp" diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index cba9a3eaf36..2b63e5dd67e 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -37,6 +37,7 @@ #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1ErgoVerbose.hpp" #include "gc/g1/g1EvacFailure.hpp" +#include "gc/g1/g1EvacStats.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1Log.hpp" #include "gc/g1/g1MarkSweep.hpp" diff --git a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp index de0e5eda296..8a2317c59bd 100644 --- a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp +++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "memory/allocation.inline.hpp" #include "gc/g1/g1EvacStats.hpp" #include "gc/shared/gcId.hpp" #include "trace/tracing.hpp" @@ -114,3 +115,4 @@ void G1EvacStats::adjust_desired_plab_sz() { reset(); } +G1EvacStats::~G1EvacStats() { } diff --git a/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp b/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp index ffc548d16a3..1d0a53f5453 100644 --- a/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp +++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp @@ -22,11 +22,10 @@ * */ -#ifndef SHARE_VM_gc_G1_G1EVACSTATS_HPP -#define SHARE_VM_gc_G1_G1EVACSTATS_HPP +#ifndef SHARE_VM_GC_G1_G1EVACSTATS_HPP +#define SHARE_VM_GC_G1_G1EVACSTATS_HPP #include "gc/shared/plab.hpp" -#include "runtime/atomic.hpp" // Records various memory allocation statistics gathered during evacuation. class G1EvacStats : public PLABStats { @@ -75,19 +74,11 @@ class G1EvacStats : public PLABStats { // Amount of space in heapwords wasted (unused) in the failing regions when an evacuation failure happens. size_t failure_waste() const { return _failure_waste; } - void add_direct_allocated(size_t value) { - Atomic::add_ptr(value, &_direct_allocated); - } + inline void add_direct_allocated(size_t value); + inline void add_region_end_waste(size_t value); + inline void add_failure_used_and_waste(size_t used, size_t waste); - void add_region_end_waste(size_t value) { - Atomic::add_ptr(value, &_region_end_waste); - Atomic::add_ptr(1, &_regions_filled); - } - - void add_failure_used_and_waste(size_t used, size_t waste) { - Atomic::add_ptr(used, &_failure_used); - Atomic::add_ptr(waste, &_failure_waste); - } + ~G1EvacStats(); }; -#endif // SHARE_VM_gc_G1_G1EVACSTATS_HPP +#endif // SHARE_VM_GC_G1_G1EVACSTATS_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1EvacStats.inline.hpp b/hotspot/src/share/vm/gc/g1/g1EvacStats.inline.hpp new file mode 100644 index 00000000000..337d4625707 --- /dev/null +++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.inline.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_G1_G1EVACSTATS_INLINE_HPP +#define SHARE_VM_GC_G1_G1EVACSTATS_INLINE_HPP + +#include "gc/g1/g1EvacStats.hpp" +#include "runtime/atomic.inline.hpp" + +inline void G1EvacStats::add_direct_allocated(size_t value) { + Atomic::add_ptr(value, &_direct_allocated); +} + +inline void G1EvacStats::add_region_end_waste(size_t value) { + Atomic::add_ptr(value, &_region_end_waste); + Atomic::add_ptr(1, &_regions_filled); +} + +inline void G1EvacStats::add_failure_used_and_waste(size_t used, size_t waste) { + Atomic::add_ptr(used, &_failure_used); + Atomic::add_ptr(waste, &_failure_waste); +} + +#endif // SHARE_VM_GC_G1_G1EVACSTATS_INLINE_HPP diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index 35bb7684be8..1ab815c7d52 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -49,6 +49,7 @@ #include "runtime/arguments.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/compilationPolicy.hpp" +#include "runtime/deoptimization.hpp" #include "runtime/fprofiler.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.hpp" From d56280ca10db96016c9d5f2431f4bf3c614d137b Mon Sep 17 00:00:00 2001 From: Gerald Thornbrugh Date: Wed, 18 Nov 2015 09:32:52 -0800 Subject: [PATCH 120/260] 8141445: Use of Solaris/SPARC M7 libadimalloc.so can generate unknown signal in hs_err file Add libadimalloc.so SIGSEGV defines and a test to validate the correct message is printed in the hs_err file Reviewed-by: dcubed, dholmes --- hotspot/make/test/JtregNative.gmk | 10 ++ hotspot/src/os/posix/vm/os_posix.cpp | 15 +++ .../SEGVOverflow.java | 39 +++++++ .../Testlibadimalloc.java | 104 ++++++++++++++++++ .../libadimalloc.solaris.sparc/liboverflow.c | 72 ++++++++++++ 5 files changed, 240 insertions(+) create mode 100644 hotspot/test/runtime/libadimalloc.solaris.sparc/SEGVOverflow.java create mode 100644 hotspot/test/runtime/libadimalloc.solaris.sparc/Testlibadimalloc.java create mode 100644 hotspot/test/runtime/libadimalloc.solaris.sparc/liboverflow.c diff --git a/hotspot/make/test/JtregNative.gmk b/hotspot/make/test/JtregNative.gmk index b9d1dfa5894..b158b7eddb2 100644 --- a/hotspot/make/test/JtregNative.gmk +++ b/hotspot/make/test/JtregNative.gmk @@ -48,6 +48,16 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \ $(HOTSPOT_TOPDIR)/test/runtime/SameObject \ # +# Add conditional directories here when needed. +ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), solaris-sparc) +BUILD_HOTSPOT_JTREG_NATIVE_SRC += \ + $(HOTSPOT_TOPDIR)/test/runtime/libadimalloc.solaris.sparc +endif + +ifeq ($(TOOLCHAIN_TYPE), solstudio) + BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_liboverflow := -lc +endif + BUILD_HOTSPOT_JTREG_OUTPUT_DIR := $(BUILD_OUTPUT)/support/test/hotspot/jtreg/native BUILD_HOTSPOT_JTREG_IMAGE_DIR := $(TEST_IMAGE_DIR)/hotspot/jtreg diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp index 47ad1217d1e..63fe550518b 100644 --- a/hotspot/src/os/posix/vm/os_posix.cpp +++ b/hotspot/src/os/posix/vm/os_posix.cpp @@ -837,6 +837,21 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t #if defined(IA64) && !defined(AIX) { SIGSEGV, SEGV_PSTKOVF, "SEGV_PSTKOVF", "Paragraph stack overflow" }, #endif +#if defined(__sparc) && defined(SOLARIS) +// define Solaris Sparc M7 ADI SEGV signals +#if !defined(SEGV_ACCADI) +#define SEGV_ACCADI 3 +#endif + { SIGSEGV, SEGV_ACCADI, "SEGV_ACCADI", "ADI not enabled for mapped object." }, +#if !defined(SEGV_ACCDERR) +#define SEGV_ACCDERR 4 +#endif + { SIGSEGV, SEGV_ACCDERR, "SEGV_ACCDERR", "ADI disrupting exception." }, +#if !defined(SEGV_ACCPERR) +#define SEGV_ACCPERR 5 +#endif + { SIGSEGV, SEGV_ACCPERR, "SEGV_ACCPERR", "ADI precise exception." }, +#endif // defined(__sparc) && defined(SOLARIS) { SIGBUS, BUS_ADRALN, "BUS_ADRALN", "Invalid address alignment." }, { SIGBUS, BUS_ADRERR, "BUS_ADRERR", "Nonexistent physical address." }, { SIGBUS, BUS_OBJERR, "BUS_OBJERR", "Object-specific hardware error." }, diff --git a/hotspot/test/runtime/libadimalloc.solaris.sparc/SEGVOverflow.java b/hotspot/test/runtime/libadimalloc.solaris.sparc/SEGVOverflow.java new file mode 100644 index 00000000000..da754da73ac --- /dev/null +++ b/hotspot/test/runtime/libadimalloc.solaris.sparc/SEGVOverflow.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +public class SEGVOverflow { + + static { + System.loadLibrary("overflow"); + } + + native static String nativesegv(); + + public static void main(String[] args) { + String str = nativesegv(); + if (str == null) { + System.out.println("FAILED: malloc returned null"); + } else { + System.out.println(str); + } + } +} diff --git a/hotspot/test/runtime/libadimalloc.solaris.sparc/Testlibadimalloc.java b/hotspot/test/runtime/libadimalloc.solaris.sparc/Testlibadimalloc.java new file mode 100644 index 00000000000..e9a8406f0f1 --- /dev/null +++ b/hotspot/test/runtime/libadimalloc.solaris.sparc/Testlibadimalloc.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test Testlibadimalloc.java + * @bug 8141445 + * @summary make sure the Solaris Sparc M7 libadimalloc.so library generates SIGSEGV's on buffer overflow + * @requires (os.family == "solaris" & os.arch == "sparcv9") + * @library /testlibrary + * @build jdk.test.lib.* + * @compile SEGVOverflow.java + * @run driver Testlibadimalloc + */ + +import java.io.*; +import java.nio.file.*; +import java.util.*; +import jdk.test.lib.ProcessTools; + +public class Testlibadimalloc { + + // Expected return value when java program cores + static final int EXPECTED_RET_VAL = 6; + + public static void main(String[] args) throws Throwable { + + // See if the libadimalloc.so library exists + Path path = Paths.get("/usr/lib/64/libadimalloc.so"); + + // If the libadimalloc.so file does not exist, pass the test + if (!(Files.isRegularFile(path) || Files.isSymbolicLink(path))) { + System.out.println("Test skipped; libadimalloc.so does not exist"); + return; + } + + // Get the JDK, library and class path properties + String libpath = System.getProperty("java.library.path"); + + // Create a new java process for the SEGVOverflow Java/JNI test + ProcessBuilder builder = ProcessTools.createJavaProcessBuilder( + "-Djava.library.path=" + libpath + ":.", "SEGVOverflow"); + + // Add the LD_PRELOAD_64 value to the environment + Map env = builder.environment(); + env.put("LD_PRELOAD_64", "libadimalloc.so"); + + // Start the process, get the pid and then wait for the test to finish + Process process = builder.start(); + long pid = process.getPid(); + int retval = process.waitFor(); + + // make sure the SEGVOverflow test crashed + boolean found = false; + if (retval == EXPECTED_RET_VAL) { + String filename = "hs_err_pid" + pid + ".log"; + Path filepath = Paths.get(filename); + // check to see if hs_err_file exists + if (Files.isRegularFile(filepath)) { + // see if the crash was due to a SEGV_ACCPERR signal + File hs_err_file = new File(filename); + Scanner scanner = new Scanner(hs_err_file); + while (!found && scanner.hasNextLine()) { + String nextline = scanner.nextLine(); + if (nextline.contains("SEGV_ACCPERR")) { + found = true; + } + } + } else { + System.out.println("Test failed; hs_err_file does not exist: " + + filepath); + } + } else { + System.out.println("Test failed; java test program did not " + + "return expected error: expected = " + + EXPECTED_RET_VAL + ", retval = " + retval); + } + // If SEGV_ACCPERR was not found in the hs_err file fail the test + if (!found) { + System.out.println("FAIL: SEGV_ACCPERR not found"); + throw new RuntimeException("FAIL: SEGV_ACCPERR not found"); + } + } +} diff --git a/hotspot/test/runtime/libadimalloc.solaris.sparc/liboverflow.c b/hotspot/test/runtime/libadimalloc.solaris.sparc/liboverflow.c new file mode 100644 index 00000000000..36b5dae9fb0 --- /dev/null +++ b/hotspot/test/runtime/libadimalloc.solaris.sparc/liboverflow.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT jstring JNICALL Java_SEGVOverflow_nativesegv(JNIEnv *env, jobject obj) { + char *buffer1; + char *buffer2; + char *buffer3; + char ch; + + jstring ret = NULL; + + // sleep for a bit to let the libadimalloc library initialize + sleep(5); + + // allocate three buffers + buffer1 = (char *)malloc(64); + buffer2 = (char *)malloc(64); + buffer3 = (char *)malloc(64); + if ((buffer1 == NULL) || (buffer2 == NULL) || (buffer3 == NULL)) { + // this return will result in a test failure + return ret; + } + + // Read past the end of each buffer multiple times to increase the probability + // that an ADI version mismatch occurs so an ADI fault is triggered. + ch = buffer1[70]; + ch = buffer2[70]; + ch = buffer3[70]; + ch = buffer1[140]; + ch = buffer2[140]; + ch = buffer3[140]; + + // create a failed test return value because this test should have cored + buffer1 = "TEST FAILED, a read past the end of a buffer succeeded."; + ret = (*env)->NewStringUTF(env, buffer1); + + return ret; +} + +#ifdef __cplusplus +} +#endif From 267d7007df618762a618a65c3a6c363c8c99bf41 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Thu, 19 Nov 2015 01:52:52 +0300 Subject: [PATCH 121/260] 8143256: The build is broken after JDK-8081411 Reviewed-by: omajid --- .../classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java | 5 ++--- .../share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java index f83112c6537..f19ac21e14d 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -150,8 +150,7 @@ class GTKIconFactory { } } - private static class DelegatingIcon extends SynthIcon implements - UIResource { + private static class DelegatingIcon implements UIResource, SynthIcon { private static final Class[] PARAM_TYPES = new Class[] { SynthContext.class, Graphics.class, int.class, int.class, int.class, int.class, int.class diff --git a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java index 160540aad78..4fa44c758e5 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -992,7 +992,7 @@ class GTKStyle extends SynthStyle implements GTKConstants { /** * An Icon that is fetched using getStockIcon. */ - private static class GTKStockIcon extends SynthIcon { + private static class GTKStockIcon implements SynthIcon { private String key; private int size; private boolean loadedLTR; From 2ae7dcf853f39b9509fc4d029e7c393a11802023 Mon Sep 17 00:00:00 2001 From: Michael Berg Date: Thu, 19 Nov 2015 16:07:22 -0800 Subject: [PATCH 122/260] 8142980: SKX SpecJvm2008 - Derby Fix EVEX and AVX512 problems found by testing on 64-bit SKX and KNL EVEX enabled platforms. Reviewed-by: iveresov, kvn, vlivanov --- hotspot/src/cpu/x86/vm/assembler_x86.cpp | 226 +++++++- hotspot/src/cpu/x86/vm/assembler_x86.hpp | 31 +- hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp | 534 ++++++++++++++++-- hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp | 29 +- .../src/cpu/x86/vm/sharedRuntime_x86_32.cpp | 33 +- .../src/cpu/x86/vm/stubGenerator_x86_64.cpp | 4 +- 6 files changed, 762 insertions(+), 95 deletions(-) diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index 6cd7fb98c72..015a66b7900 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -2152,6 +2152,23 @@ void Assembler::movddup(XMMRegister dst, XMMRegister src) { emit_int8(0xC0 | encode); } +void Assembler::kmovwl(KRegister dst, Register src) { + NOT_LP64(assert(VM_Version::supports_evex(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = kreg_prefix_and_encode(dst, knoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x92); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::kmovdl(KRegister dst, Register src) { + NOT_LP64(assert(VM_Version::supports_evex(), "")); + VexSimdPrefix pre = !_legacy_mode_bw ? VEX_SIMD_F2 : VEX_SIMD_NONE; + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = kreg_prefix_and_encode(dst, knoreg, src, pre, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x92); + emit_int8((unsigned char)(0xC0 | encode)); +} + void Assembler::kmovql(KRegister dst, KRegister src) { NOT_LP64(assert(VM_Version::supports_evex(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); @@ -2187,20 +2204,39 @@ void Assembler::kmovql(KRegister dst, Register src) { emit_int8((unsigned char)(0xC0 | encode)); } -void Assembler::kmovdl(KRegister dst, Register src) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); - VexSimdPrefix pre = !_legacy_mode_bw ? VEX_SIMD_F2 : VEX_SIMD_NONE; +// This instruction produces ZF or CF flags +void Assembler::kortestbl(KRegister src1, KRegister src2) { + NOT_LP64(assert(VM_Version::supports_avx512dq(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(dst, knoreg, src, pre, VEX_OPCODE_0F, &attributes); - emit_int8((unsigned char)0x92); + int encode = kreg_prefix_and_encode(src1, knoreg, src2, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x98); emit_int8((unsigned char)(0xC0 | encode)); } -void Assembler::kmovwl(KRegister dst, Register src) { +// This instruction produces ZF or CF flags +void Assembler::kortestwl(KRegister src1, KRegister src2) { NOT_LP64(assert(VM_Version::supports_evex(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(dst, knoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); - emit_int8((unsigned char)0x92); + int encode = kreg_prefix_and_encode(src1, knoreg, src2, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x98); + emit_int8((unsigned char)(0xC0 | encode)); +} + +// This instruction produces ZF or CF flags +void Assembler::kortestdl(KRegister src1, KRegister src2) { + NOT_LP64(assert(VM_Version::supports_avx512bw(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = kreg_prefix_and_encode(src1, knoreg, src2, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x98); + emit_int8((unsigned char)(0xC0 | encode)); +} + +// This instruction produces ZF or CF flags +void Assembler::kortestql(KRegister src1, KRegister src2) { + NOT_LP64(assert(VM_Version::supports_avx512bw(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = kreg_prefix_and_encode(src1, knoreg, src2, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x98); emit_int8((unsigned char)(0xC0 | encode)); } @@ -2337,6 +2373,63 @@ void Assembler::vmovdqu(Address dst, XMMRegister src) { } // Move Unaligned EVEX enabled Vector (programmable : 8,16,32,64) +void Assembler::evmovdqub(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x6F); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::evmovdqub(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_evex(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x6F); + emit_operand(dst, src); +} + +void Assembler::evmovdqub(Address dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(src != xnoreg, "sanity"); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(dst, 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x7F); + emit_operand(src, dst); +} + +void Assembler::evmovdquw(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x6F); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::evmovdquw(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_evex(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x6F); + emit_operand(dst, src); +} + +void Assembler::evmovdquw(Address dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex(), ""); + assert(src != xnoreg, "sanity"); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + vex_prefix(dst, 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8(0x7F); + emit_operand(src, dst); +} void Assembler::evmovdqul(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); @@ -3033,6 +3126,36 @@ void Assembler::pcmpestri(XMMRegister dst, XMMRegister src, int imm8) { emit_int8(imm8); } +// In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst +void Assembler::pcmpeqb(XMMRegister dst, XMMRegister src) { + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x74); + emit_int8((unsigned char)(0xC0 | encode)); +} + +// In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst +void Assembler::vpcmpeqb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x74); + emit_int8((unsigned char)(0xC0 | encode)); +} + +// In this context, kdst is written the mask used to process the equal components +void Assembler::evpcmpeqb(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(kdst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x74); + emit_int8((unsigned char)(0xC0 | encode)); +} + +// In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst void Assembler::pcmpeqw(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); @@ -3041,9 +3164,9 @@ void Assembler::pcmpeqw(XMMRegister dst, XMMRegister src) { emit_int8((unsigned char)(0xC0 | encode)); } +// In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst void Assembler::vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx(), ""); - assert(!VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); @@ -3051,6 +3174,87 @@ void Assembler::vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int emit_int8((unsigned char)(0xC0 | encode)); } +// In this context, kdst is written the mask used to process the equal components +void Assembler::evpcmpeqw(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(kdst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x75); + emit_int8((unsigned char)(0xC0 | encode)); +} + +// In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst +void Assembler::pcmpeqd(XMMRegister dst, XMMRegister src) { + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x76); + emit_int8((unsigned char)(0xC0 | encode)); +} + +// In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst +void Assembler::vpcmpeqd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x76); + emit_int8((unsigned char)(0xC0 | encode)); +} + +// In this context, kdst is written the mask used to process the equal components +void Assembler::evpcmpeqd(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(kdst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x76); + emit_int8((unsigned char)(0xC0 | encode)); +} + +// In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst +void Assembler::pcmpeqq(XMMRegister dst, XMMRegister src) { + NOT_LP64(assert(VM_Version::supports_sse4_1(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8(0x29); + emit_int8((unsigned char)(0xC0 | encode)); +} + +// In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst +void Assembler::vpcmpeqq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8(0x29); + emit_int8((unsigned char)(0xC0 | encode)); +} + +// In this context, kdst is written the mask used to process the equal components +void Assembler::evpcmpeqq(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int encode = vex_prefix_and_encode(kdst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8(0x29); + emit_int8((unsigned char)(0xC0 | encode)); +} + +// In this context, kdst is written the mask used to process the equal components +void Assembler::evpcmpeqq(KRegister kdst, XMMRegister nds, Address src, int vector_len) { + assert(VM_Version::supports_evex(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int dst_enc = kdst->encoding(); + vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8(0x29); + emit_operand(as_Register(dst_enc), src); +} + void Assembler::pmovmskb(Register dst, XMMRegister src) { assert(VM_Version::supports_sse2(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); @@ -3139,11 +3343,11 @@ void Assembler::pmovzxbw(XMMRegister dst, XMMRegister src) { emit_int8((unsigned char)(0xC0 | encode)); } -void Assembler::vpmovzxbw(XMMRegister dst, Address src) { +void Assembler::vpmovzxbw(XMMRegister dst, Address src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionMark im(this); assert(dst != xnoreg, "sanity"); - InstructionAttr attributes(AVX_256bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_HVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x30); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 8e9c00bbf2c..a5f493905fc 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -1331,13 +1331,18 @@ private: void movddup(XMMRegister dst, XMMRegister src); + void kmovwl(KRegister dst, Register src); + void kmovdl(KRegister dst, Register src); void kmovql(KRegister dst, KRegister src); void kmovql(KRegister dst, Register src); - void kmovdl(KRegister dst, Register src); - void kmovwl(KRegister dst, Register src); void kmovql(Address dst, KRegister src); void kmovql(KRegister dst, Address src); + void kortestbl(KRegister dst, KRegister src); + void kortestwl(KRegister dst, KRegister src); + void kortestdl(KRegister dst, KRegister src); + void kortestql(KRegister dst, KRegister src); + void movdl(XMMRegister dst, Register src); void movdl(Register dst, XMMRegister src); void movdl(XMMRegister dst, Address src); @@ -1362,6 +1367,12 @@ private: void vmovdqu(XMMRegister dst, XMMRegister src); // Move Unaligned 512bit Vector + void evmovdqub(Address dst, XMMRegister src, int vector_len); + void evmovdqub(XMMRegister dst, Address src, int vector_len); + void evmovdqub(XMMRegister dst, XMMRegister src, int vector_len); + void evmovdquw(Address dst, XMMRegister src, int vector_len); + void evmovdquw(XMMRegister dst, Address src, int vector_len); + void evmovdquw(XMMRegister dst, XMMRegister src, int vector_len); void evmovdqul(Address dst, XMMRegister src, int vector_len); void evmovdqul(XMMRegister dst, Address src, int vector_len); void evmovdqul(XMMRegister dst, XMMRegister src, int vector_len); @@ -1507,8 +1518,22 @@ private: void pcmpestri(XMMRegister xmm1, XMMRegister xmm2, int imm8); void pcmpestri(XMMRegister xmm1, Address src, int imm8); + void pcmpeqb(XMMRegister dst, XMMRegister src); + void vpcmpeqb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpcmpeqb(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len); + void pcmpeqw(XMMRegister dst, XMMRegister src); void vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpcmpeqw(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len); + + void pcmpeqd(XMMRegister dst, XMMRegister src); + void vpcmpeqd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpcmpeqd(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len); + + void pcmpeqq(XMMRegister dst, XMMRegister src); + void vpcmpeqq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void evpcmpeqq(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len); + void evpcmpeqq(KRegister kdst, XMMRegister nds, Address src, int vector_len); void pmovmskb(Register dst, XMMRegister src); void vpmovmskb(Register dst, XMMRegister src); @@ -1529,7 +1554,7 @@ private: void pmovzxbw(XMMRegister dst, XMMRegister src); void pmovzxbw(XMMRegister dst, Address src); - void vpmovzxbw(XMMRegister dst, Address src); + void vpmovzxbw(XMMRegister dst, Address src, int vector_len); #ifndef _LP64 // no 32bit push/pop on amd64 void popl(Address dst); diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 68374be6900..9062cbb7730 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -3949,6 +3949,236 @@ void MacroAssembler::testl(Register dst, AddressLiteral src) { testl(dst, as_Address(src)); } +void MacroAssembler::pcmpeqb(XMMRegister dst, XMMRegister src) { + int dst_enc = dst->encoding(); + int src_enc = src->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::pcmpeqb(dst, src); + } else if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::pcmpeqb(dst, src); + } else if (src_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::pcmpeqb(xmm0, src); + movdqu(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else if (dst_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::pcmpeqb(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + movdqu(xmm0, src); + movdqu(xmm1, dst); + Assembler::pcmpeqb(xmm1, xmm0); + movdqu(dst, xmm1); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::pcmpeqw(XMMRegister dst, XMMRegister src) { + int dst_enc = dst->encoding(); + int src_enc = src->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::pcmpeqw(dst, src); + } else if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::pcmpeqw(dst, src); + } else if (src_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::pcmpeqw(xmm0, src); + movdqu(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else if (dst_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::pcmpeqw(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + movdqu(xmm0, src); + movdqu(xmm1, dst); + Assembler::pcmpeqw(xmm1, xmm0); + movdqu(dst, xmm1); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::pcmpestri(XMMRegister dst, Address src, int imm8) { + int dst_enc = dst->encoding(); + if (dst_enc < 16) { + Assembler::pcmpestri(dst, src, imm8); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::pcmpestri(xmm0, src, imm8); + movdqu(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::pcmpestri(XMMRegister dst, XMMRegister src, int imm8) { + int dst_enc = dst->encoding(); + int src_enc = src->encoding(); + if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::pcmpestri(dst, src, imm8); + } else if (src_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::pcmpestri(xmm0, src, imm8); + movdqu(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else if (dst_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::pcmpestri(dst, xmm0, imm8); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + movdqu(xmm0, src); + movdqu(xmm1, dst); + Assembler::pcmpestri(xmm1, xmm0, imm8); + movdqu(dst, xmm1); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::pmovzxbw(XMMRegister dst, XMMRegister src) { + int dst_enc = dst->encoding(); + int src_enc = src->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::pmovzxbw(dst, src); + } else if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::pmovzxbw(dst, src); + } else if (src_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::pmovzxbw(xmm0, src); + movdqu(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else if (dst_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::pmovzxbw(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + movdqu(xmm0, src); + movdqu(xmm1, dst); + Assembler::pmovzxbw(xmm1, xmm0); + movdqu(dst, xmm1); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::pmovzxbw(XMMRegister dst, Address src) { + int dst_enc = dst->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::pmovzxbw(dst, src); + } else if (dst_enc < 16) { + Assembler::pmovzxbw(dst, src); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::pmovzxbw(xmm0, src); + movdqu(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::pmovmskb(Register dst, XMMRegister src) { + int src_enc = src->encoding(); + if (src_enc < 16) { + Assembler::pmovmskb(dst, src); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::pmovmskb(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::ptest(XMMRegister dst, XMMRegister src) { + int dst_enc = dst->encoding(); + int src_enc = src->encoding(); + if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::ptest(dst, src); + } else if (src_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::ptest(xmm0, src); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else if (dst_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::ptest(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + movdqu(xmm0, src); + movdqu(xmm1, dst); + Assembler::ptest(xmm1, xmm0); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + void MacroAssembler::sqrtsd(XMMRegister dst, AddressLiteral src) { if (reachable(src)) { Assembler::sqrtsd(dst, as_Address(src)); @@ -4256,6 +4486,214 @@ void MacroAssembler::vpaddw(XMMRegister dst, XMMRegister nds, Address src, int v } } +void MacroAssembler::vpbroadcastw(XMMRegister dst, XMMRegister src) { + int dst_enc = dst->encoding(); + int src_enc = src->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpbroadcastw(dst, src); + } else if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::vpbroadcastw(dst, src); + } else if (src_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpbroadcastw(xmm0, src); + movdqu(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else if (dst_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::vpbroadcastw(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + movdqu(xmm0, src); + movdqu(xmm1, dst); + Assembler::vpbroadcastw(xmm1, xmm0); + movdqu(dst, xmm1); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::vpcmpeqb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + int src_enc = src->encoding(); + assert(dst_enc == nds_enc, ""); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpcmpeqb(dst, nds, src, vector_len); + } else if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::vpcmpeqb(dst, nds, src, vector_len); + } else if (src_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpcmpeqb(xmm0, xmm0, src, vector_len); + movdqu(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else if (dst_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::vpcmpeqb(dst, dst, xmm0, vector_len); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + movdqu(xmm0, src); + movdqu(xmm1, dst); + Assembler::vpcmpeqb(xmm1, xmm1, xmm0, vector_len); + movdqu(dst, xmm1); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + int src_enc = src->encoding(); + assert(dst_enc == nds_enc, ""); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpcmpeqw(dst, nds, src, vector_len); + } else if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::vpcmpeqw(dst, nds, src, vector_len); + } else if (src_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpcmpeqw(xmm0, xmm0, src, vector_len); + movdqu(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else if (dst_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::vpcmpeqw(dst, dst, xmm0, vector_len); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + movdqu(xmm0, src); + movdqu(xmm1, dst); + Assembler::vpcmpeqw(xmm1, xmm1, xmm0, vector_len); + movdqu(dst, xmm1); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::vpmovzxbw(XMMRegister dst, Address src, int vector_len) { + int dst_enc = dst->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpmovzxbw(dst, src, vector_len); + } else if (dst_enc < 16) { + Assembler::vpmovzxbw(dst, src, vector_len); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpmovzxbw(xmm0, src, vector_len); + movdqu(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::vpmovmskb(Register dst, XMMRegister src) { + int src_enc = src->encoding(); + if (src_enc < 16) { + Assembler::vpmovmskb(dst, src); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::vpmovmskb(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::vpmullw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + int src_enc = src->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpmullw(dst, nds, src, vector_len); + } else if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::vpmullw(dst, dst, src, vector_len); + } else if ((dst_enc < 16) && (nds_enc < 16)) { + // use nds as scratch for src + evmovdqul(nds, src, Assembler::AVX_512bit); + Assembler::vpmullw(dst, dst, nds, vector_len); + } else if ((src_enc < 16) && (nds_enc < 16)) { + // use nds as scratch for dst + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpmullw(nds, nds, src, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else if (dst_enc < 16) { + // use nds as scatch for xmm0 to hold src + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::vpmullw(dst, dst, xmm0, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs are in the upper bank + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm1, src, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpmullw(xmm0, xmm0, xmm1, vector_len); + evmovdqul(dst, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + +void MacroAssembler::vpmullw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { + Assembler::vpmullw(dst, nds, src, vector_len); + } else if (dst_enc < 16) { + Assembler::vpmullw(dst, dst, src, vector_len); + } else if (nds_enc < 16) { + // implies dst_enc in upper bank with src as scratch + evmovdqul(nds, dst, Assembler::AVX_512bit); + Assembler::vpmullw(nds, nds, src, vector_len); + evmovdqul(dst, nds, Assembler::AVX_512bit); + } else { + // worse case scenario, all regs in upper bank + evmovdqul(nds, xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vpmullw(xmm0, xmm0, src, vector_len); + evmovdqul(xmm0, nds, Assembler::AVX_512bit); + } +} + void MacroAssembler::vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { int dst_enc = dst->encoding(); int nds_enc = nds->encoding(); @@ -4374,66 +4812,6 @@ void MacroAssembler::vpsubw(XMMRegister dst, XMMRegister nds, Address src, int v } } - -void MacroAssembler::vpmullw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { - int dst_enc = dst->encoding(); - int nds_enc = nds->encoding(); - int src_enc = src->encoding(); - if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { - Assembler::vpmullw(dst, nds, src, vector_len); - } else if ((dst_enc < 16) && (src_enc < 16)) { - Assembler::vpmullw(dst, dst, src, vector_len); - } else if ((dst_enc < 16) && (nds_enc < 16)) { - // use nds as scratch for src - evmovdqul(nds, src, Assembler::AVX_512bit); - Assembler::vpmullw(dst, dst, nds, vector_len); - } else if ((src_enc < 16) && (nds_enc < 16)) { - // use nds as scratch for dst - evmovdqul(nds, dst, Assembler::AVX_512bit); - Assembler::vpmullw(nds, nds, src, vector_len); - evmovdqul(dst, nds, Assembler::AVX_512bit); - } else if (dst_enc < 16) { - // use nds as scatch for xmm0 to hold src - evmovdqul(nds, xmm0, Assembler::AVX_512bit); - evmovdqul(xmm0, src, Assembler::AVX_512bit); - Assembler::vpmullw(dst, dst, xmm0, vector_len); - evmovdqul(xmm0, nds, Assembler::AVX_512bit); - } else { - // worse case scenario, all regs are in the upper bank - subptr(rsp, 64); - evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); - evmovdqul(nds, xmm0, Assembler::AVX_512bit); - evmovdqul(xmm1, src, Assembler::AVX_512bit); - evmovdqul(xmm0, dst, Assembler::AVX_512bit); - Assembler::vpmullw(xmm0, xmm0, xmm1, vector_len); - evmovdqul(dst, xmm0, Assembler::AVX_512bit); - evmovdqul(xmm0, nds, Assembler::AVX_512bit); - evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); - addptr(rsp, 64); - } -} - -void MacroAssembler::vpmullw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { - int dst_enc = dst->encoding(); - int nds_enc = nds->encoding(); - if (VM_Version::supports_avxonly() || VM_Version::supports_avx512bw()) { - Assembler::vpmullw(dst, nds, src, vector_len); - } else if (dst_enc < 16) { - Assembler::vpmullw(dst, dst, src, vector_len); - } else if (nds_enc < 16) { - // implies dst_enc in upper bank with src as scratch - evmovdqul(nds, dst, Assembler::AVX_512bit); - Assembler::vpmullw(nds, nds, src, vector_len); - evmovdqul(dst, nds, Assembler::AVX_512bit); - } else { - // worse case scenario, all regs in upper bank - evmovdqul(nds, xmm0, Assembler::AVX_512bit); - evmovdqul(xmm0, dst, Assembler::AVX_512bit); - Assembler::vpmullw(xmm0, xmm0, src, vector_len); - evmovdqul(xmm0, nds, Assembler::AVX_512bit); - } -} - void MacroAssembler::vpsraw(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len) { int dst_enc = dst->encoding(); int nds_enc = nds->encoding(); @@ -4638,6 +5016,40 @@ void MacroAssembler::vpsllw(XMMRegister dst, XMMRegister nds, int shift, int vec } } +void MacroAssembler::vptest(XMMRegister dst, XMMRegister src) { + int dst_enc = dst->encoding(); + int src_enc = src->encoding(); + if ((dst_enc < 16) && (src_enc < 16)) { + Assembler::vptest(dst, src); + } else if (src_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, dst, Assembler::AVX_512bit); + Assembler::vptest(xmm0, src); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else if (dst_enc < 16) { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + evmovdqul(xmm0, src, Assembler::AVX_512bit); + Assembler::vptest(dst, xmm0); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } else { + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm0, Assembler::AVX_512bit); + subptr(rsp, 64); + evmovdqul(Address(rsp, 0), xmm1, Assembler::AVX_512bit); + movdqu(xmm0, src); + movdqu(xmm1, dst); + Assembler::vptest(xmm1, xmm0); + evmovdqul(xmm1, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + evmovdqul(xmm0, Address(rsp, 0), Assembler::AVX_512bit); + addptr(rsp, 64); + } +} + // This instruction exists within macros, ergo we cannot control its input // when emitted through those patterns. void MacroAssembler::punpcklbw(XMMRegister dst, XMMRegister src) { @@ -7722,7 +8134,7 @@ void MacroAssembler::string_compare(Register str1, Register str2, vmovdqu(vec1, Address(str1, result, scale)); vpxor(vec1, Address(str2, result, scale)); } else { - vpmovzxbw(vec1, Address(str1, result, scale1)); + vpmovzxbw(vec1, Address(str1, result, scale1), Assembler::AVX_256bit); vpxor(vec1, Address(str2, result, scale2)); } vptest(vec1, vec1); diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index 076600efa34..b4e440f4383 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -1004,6 +1004,19 @@ public: Assembler::pclmulqdq(dst, src, 0x11); } + void pcmpeqb(XMMRegister dst, XMMRegister src); + void pcmpeqw(XMMRegister dst, XMMRegister src); + + void pcmpestri(XMMRegister dst, Address src, int imm8); + void pcmpestri(XMMRegister dst, XMMRegister src, int imm8); + + void pmovzxbw(XMMRegister dst, XMMRegister src); + void pmovzxbw(XMMRegister dst, Address src); + + void pmovmskb(Register dst, XMMRegister src); + + void ptest(XMMRegister dst, XMMRegister src); + void sqrtsd(XMMRegister dst, XMMRegister src) { Assembler::sqrtsd(dst, src); } void sqrtsd(XMMRegister dst, Address src) { Assembler::sqrtsd(dst, src); } void sqrtsd(XMMRegister dst, AddressLiteral src); @@ -1061,15 +1074,23 @@ public: void vpaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpaddw(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void vpbroadcastw(XMMRegister dst, XMMRegister src); + + void vpcmpeqb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + + void vpmovzxbw(XMMRegister dst, Address src, int vector_len); + void vpmovmskb(Register dst, XMMRegister src); + + void vpmullw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpmullw(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpsubb(XMMRegister dst, XMMRegister nds, Address src, int vector_len); void vpsubw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpsubw(XMMRegister dst, XMMRegister nds, Address src, int vector_len); - void vpmullw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); - void vpmullw(XMMRegister dst, XMMRegister nds, Address src, int vector_len); - void vpsraw(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len); void vpsraw(XMMRegister dst, XMMRegister nds, int shift, int vector_len); @@ -1079,6 +1100,8 @@ public: void vpsllw(XMMRegister dst, XMMRegister nds, XMMRegister shift, int vector_len); void vpsllw(XMMRegister dst, XMMRegister nds, int shift, int vector_len); + void vptest(XMMRegister dst, XMMRegister src); + void punpcklbw(XMMRegister dst, XMMRegister src); void punpcklbw(XMMRegister dst, Address src) { Assembler::punpcklbw(dst, src); } diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index d961774fa05..96cfbe56ea1 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp @@ -198,7 +198,7 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ } } - if (vect_words > 0) { + if (save_vectors) { assert(vect_words*wordSize == 128, ""); __ subptr(rsp, 128); // Save upper half of YMM registes for (int n = 0; n < num_xmm_regs; n++) { @@ -266,21 +266,7 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_ve #else assert(!restore_vectors, "vectors are generated only by C2"); #endif - int off = xmm0_off; - int delta = xmm1_off - off; - if (UseSSE == 1) { - assert(additional_frame_bytes == 0, ""); - for (int n = 0; n < num_xmm_regs; n++) { - __ movflt(as_XMMRegister(n), Address(rsp, off*wordSize)); - off += delta; - } - } else if (UseSSE >= 2) { - for (int n = 0; n < num_xmm_regs; n++) { - __ movdqu(as_XMMRegister(n), Address(rsp, off*wordSize+additional_frame_bytes)); - off += delta; - } - } if (restore_vectors) { assert(additional_frame_bytes == 128, ""); if (UseAVX > 2) { @@ -296,6 +282,23 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_ve } __ addptr(rsp, additional_frame_bytes); // Save upper half of YMM registes } + + int off = xmm0_off; + int delta = xmm1_off - off; + + if (UseSSE == 1) { + for (int n = 0; n < num_xmm_regs; n++) { + __ movflt(as_XMMRegister(n), Address(rsp, off*wordSize)); + off += delta; + } + } else if (UseSSE >= 2) { + // additional_frame_bytes only populated for the restore_vector case, else it is 0 + for (int n = 0; n < num_xmm_regs; n++) { + __ movdqu(as_XMMRegister(n), Address(rsp, off*wordSize+additional_frame_bytes)); + off += delta; + } + } + __ pop_FPU_state(); __ addptr(rsp, FPU_regs_live*wordSize); // Pop FPU registers diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index 8ebcd28044a..b68bedf1ad6 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -1439,8 +1439,8 @@ class StubGenerator: public StubCodeGenerator { // Copy 64-bytes per iteration __ BIND(L_loop); if (UseAVX > 2) { - __ evmovdqul(xmm0, Address(from, qword_count, Address::times_8, 32), Assembler::AVX_512bit); - __ evmovdqul(Address(dest, qword_count, Address::times_8, 32), xmm0, Assembler::AVX_512bit); + __ evmovdqul(xmm0, Address(from, qword_count, Address::times_8, 0), Assembler::AVX_512bit); + __ evmovdqul(Address(dest, qword_count, Address::times_8, 0), xmm0, Assembler::AVX_512bit); } else if (UseAVX == 2) { __ vmovdqu(xmm0, Address(from, qword_count, Address::times_8, 32)); __ vmovdqu(Address(dest, qword_count, Address::times_8, 32), xmm0); From ea052022fa2745982c7661ef71b8544b4469721f Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Fri, 20 Nov 2015 10:09:42 +0100 Subject: [PATCH 123/260] 8140390: Char stores/loads accessing byte arrays must be marked as unmatched Mark unmatched char stores/loads emitted by CompactStrings. Reviewed-by: roland, vlivanov, jrose --- hotspot/src/share/vm/opto/graphKit.cpp | 3 ++- hotspot/src/share/vm/opto/idealKit.hpp | 3 +-- hotspot/src/share/vm/opto/library_call.cpp | 6 ++++-- hotspot/src/share/vm/opto/stringopts.cpp | 8 ++++---- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index 54ff117bcc8..aec34626936 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -4387,7 +4387,8 @@ void GraphKit::inflate_string_slow(Node* src, Node* dst, Node* start, Node* coun set_memory(mem, TypeAryPtr::BYTES); Node* ch = load_array_element(control(), src, i_byte, TypeAryPtr::BYTES); Node* st = store_to_memory(control(), array_element_address(dst, i_char, T_BYTE), - AndI(ch, intcon(0xff)), T_CHAR, TypeAryPtr::BYTES, MemNode::unordered); + AndI(ch, intcon(0xff)), T_CHAR, TypeAryPtr::BYTES, MemNode::unordered, + false, false, true /* mismatched */); IfNode* iff = create_and_map_if(head, Bool(CmpI(i_byte, count), BoolTest::lt), PROB_FAIR, COUNT_UNKNOWN); head->init_req(2, IfTrue(iff)); diff --git a/hotspot/src/share/vm/opto/idealKit.hpp b/hotspot/src/share/vm/opto/idealKit.hpp index 79e1c7f81c6..20996c286d6 100644 --- a/hotspot/src/share/vm/opto/idealKit.hpp +++ b/hotspot/src/share/vm/opto/idealKit.hpp @@ -230,8 +230,7 @@ class IdealKit: public StackObj { int adr_idx, MemNode::MemOrd mo, bool require_atomic_access = false, - bool mismatched = false - ); + bool mismatched = false); // Store a card mark ordered after store_oop Node* storeCM(Node* ctl, diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index f8c503da26c..749c4680b23 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -1503,9 +1503,11 @@ bool LibraryCallKit::inline_string_char_access(bool is_store) { Node* adr = array_element_address(value, index, T_CHAR); if (is_store) { - (void) store_to_memory(control(), adr, ch, T_CHAR, TypeAryPtr::BYTES, MemNode::unordered); + (void) store_to_memory(control(), adr, ch, T_CHAR, TypeAryPtr::BYTES, MemNode::unordered, + false, false, true /* mismatched */); } else { - ch = make_load(control(), adr, TypeInt::CHAR, T_CHAR, MemNode::unordered); + ch = make_load(control(), adr, TypeInt::CHAR, T_CHAR, MemNode::unordered, + LoadNode::DependsOnlyOnTest, false, false, true /* mismatched */); set_result(ch); } return true; diff --git a/hotspot/src/share/vm/opto/stringopts.cpp b/hotspot/src/share/vm/opto/stringopts.cpp index b11742f04b3..241384eccc6 100644 --- a/hotspot/src/share/vm/opto/stringopts.cpp +++ b/hotspot/src/share/vm/opto/stringopts.cpp @@ -1293,7 +1293,7 @@ void PhaseStringOpts::getChars(GraphKit& kit, Node* arg, Node* dst_array, BasicT Node* index = __ SubI(charPos, __ intcon((bt == T_BYTE) ? 1 : 2)); Node* ch = __ AddI(r, __ intcon('0')); Node* st = __ store_to_memory(kit.control(), kit.array_element_address(dst_array, index, T_BYTE), - ch, bt, byte_adr_idx, MemNode::unordered); + ch, bt, byte_adr_idx, MemNode::unordered, (bt != T_BYTE) /* mismatched */); iff = kit.create_and_map_if(head, __ Bool(__ CmpI(q, __ intcon(0)), BoolTest::ne), PROB_FAIR, COUNT_UNKNOWN); @@ -1331,7 +1331,7 @@ void PhaseStringOpts::getChars(GraphKit& kit, Node* arg, Node* dst_array, BasicT } else { Node* index = __ SubI(charPos, __ intcon((bt == T_BYTE) ? 1 : 2)); st = __ store_to_memory(kit.control(), kit.array_element_address(dst_array, index, T_BYTE), - sign, bt, byte_adr_idx, MemNode::unordered); + sign, bt, byte_adr_idx, MemNode::unordered, (bt != T_BYTE) /* mismatched */); final_merge->init_req(merge_index + 1, kit.control()); final_mem->init_req(merge_index + 1, st); @@ -1524,7 +1524,7 @@ void PhaseStringOpts::copy_constant_string(GraphKit& kit, IdealKit& ideal, ciTyp } else { val = readChar(src_array, i++); } - __ store(__ ctrl(), adr, __ ConI(val), T_CHAR, byte_adr_idx, MemNode::unordered); + __ store(__ ctrl(), adr, __ ConI(val), T_CHAR, byte_adr_idx, MemNode::unordered, true /* mismatched */); index = __ AddI(index, __ ConI(2)); } if (src_is_byte) { @@ -1612,7 +1612,7 @@ Node* PhaseStringOpts::copy_char(GraphKit& kit, Node* val, Node* dst_array, Node } if (!dcon || !dbyte) { // Destination is UTF16. Store a char. - __ store(__ ctrl(), adr, val, T_CHAR, byte_adr_idx, MemNode::unordered); + __ store(__ ctrl(), adr, val, T_CHAR, byte_adr_idx, MemNode::unordered, true /* mismatched */); __ set(end, __ AddI(start, __ ConI(2))); } if (!dcon) { From e28d9ba105548efaab23e2f8a0a110f3be452eff Mon Sep 17 00:00:00 2001 From: Ahmed Khawaja Date: Fri, 20 Nov 2015 08:29:10 -0800 Subject: [PATCH 124/260] 8143012: CRC32 Intrinsics support on SPARC Reviewed-by: kvn, roland --- .../cpu/sparc/vm/c1_LIRAssembler_sparc.cpp | 18 +- .../cpu/sparc/vm/c1_LIRGenerator_sparc.cpp | 81 +++++- .../sparc/vm/interpreterGenerator_sparc.hpp | 7 +- .../src/cpu/sparc/vm/macroAssembler_sparc.cpp | 240 ++++++++++++++++++ .../src/cpu/sparc/vm/macroAssembler_sparc.hpp | 13 +- .../src/cpu/sparc/vm/stubGenerator_sparc.cpp | 38 +++ .../src/cpu/sparc/vm/stubRoutines_sparc.cpp | 97 ++++++- .../src/cpu/sparc/vm/stubRoutines_sparc.hpp | 5 + .../sparc/vm/templateInterpreter_sparc.cpp | 100 ++++++++ hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp | 9 + .../compiler/intrinsics/crc32/TestCRC32.java | 221 ++++++++++++++++ 11 files changed, 822 insertions(+), 7 deletions(-) create mode 100644 hotspot/test/compiler/intrinsics/crc32/TestCRC32.java diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index 496c9e914da..aa242573d66 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -2812,7 +2812,23 @@ void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst_opr) { } void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) { - fatal("CRC32 intrinsic is not implemented on this platform"); + assert(op->crc()->is_single_cpu(), "crc must be register"); + assert(op->val()->is_single_cpu(), "byte value must be register"); + assert(op->result_opr()->is_single_cpu(), "result must be register"); + Register crc = op->crc()->as_register(); + Register val = op->val()->as_register(); + Register table = op->result_opr()->as_register(); + Register res = op->result_opr()->as_register(); + + assert_different_registers(val, crc, table); + + __ set(ExternalAddress(StubRoutines::crc_table_addr()), table); + __ not1(crc); + __ clruwu(crc); + __ update_byte_crc32(crc, val, table); + __ not1(crc); + + __ mov(crc, res); } void LIR_Assembler::emit_lock(LIR_OpLock* op) { diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp index 992cb8d4742..6185a1d59cd 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp @@ -786,7 +786,86 @@ void LIRGenerator::do_ArrayCopy(Intrinsic* x) { } void LIRGenerator::do_update_CRC32(Intrinsic* x) { - fatal("CRC32 intrinsic is not implemented on this platform"); + // Make all state_for calls early since they can emit code + LIR_Opr result = rlock_result(x); + int flags = 0; + switch (x->id()) { + case vmIntrinsics::_updateCRC32: { + LIRItem crc(x->argument_at(0), this); + LIRItem val(x->argument_at(1), this); + // val is destroyed by update_crc32 + val.set_destroys_register(); + crc.load_item(); + val.load_item(); + __ update_crc32(crc.result(), val.result(), result); + break; + } + case vmIntrinsics::_updateBytesCRC32: + case vmIntrinsics::_updateByteBufferCRC32: { + + bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32); + + LIRItem crc(x->argument_at(0), this); + LIRItem buf(x->argument_at(1), this); + LIRItem off(x->argument_at(2), this); + LIRItem len(x->argument_at(3), this); + + buf.load_item(); + off.load_nonconstant(); + + LIR_Opr index = off.result(); + int offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0; + if(off.result()->is_constant()) { + index = LIR_OprFact::illegalOpr; + offset += off.result()->as_jint(); + } + + LIR_Opr base_op = buf.result(); + + if (index->is_valid()) { + LIR_Opr tmp = new_register(T_LONG); + __ convert(Bytecodes::_i2l, index, tmp); + index = tmp; + if (index->is_constant()) { + offset += index->as_constant_ptr()->as_jint(); + index = LIR_OprFact::illegalOpr; + } else if (index->is_register()) { + LIR_Opr tmp2 = new_register(T_LONG); + LIR_Opr tmp3 = new_register(T_LONG); + __ move(base_op, tmp2); + __ move(index, tmp3); + __ add(tmp2, tmp3, tmp2); + base_op = tmp2; + } else { + ShouldNotReachHere(); + } + } + + LIR_Address* a = new LIR_Address(base_op, offset, T_BYTE); + + BasicTypeList signature(3); + signature.append(T_INT); + signature.append(T_ADDRESS); + signature.append(T_INT); + CallingConvention* cc = frame_map()->c_calling_convention(&signature); + const LIR_Opr result_reg = result_register_for(x->type()); + + LIR_Opr addr = new_pointer_register(); + __ leal(LIR_OprFact::address(a), addr); + + crc.load_item_force(cc->at(0)); + __ move(addr, cc->at(1)); + len.load_item_force(cc->at(2)); + + __ call_runtime_leaf(StubRoutines::updateBytesCRC32(), getThreadTemp(), result_reg, cc->args()); + __ move(result_reg, result); + + break; + } + default: { + ShouldNotReachHere(); + } + } } // _i2l, _i2f, _i2d, _l2i, _l2f, _l2d, _f2i, _f2l, _f2d, _d2i, _d2l, _d2f diff --git a/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp b/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp index 287e9f2971a..f0513d4035b 100644 --- a/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,8 +43,9 @@ void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue); void generate_counter_overflow(Label& Lcontinue); + address generate_CRC32_update_entry(); + address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind); + // Not supported - address generate_CRC32_update_entry() { return NULL; } - address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } #endif // CPU_SPARC_VM_INTERPRETERGENERATOR_SPARC_HPP diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp index a6d5cd68e47..f542993008a 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp @@ -4771,3 +4771,243 @@ void MacroAssembler::movftoi_revbytes(FloatRegister src, Register dst, Register movdtox(src, tmp1); reverse_bytes_32(tmp1, dst, tmp2); } + +void MacroAssembler::fold_128bit_crc32(Register xcrc_hi, Register xcrc_lo, Register xK_hi, Register xK_lo, Register xtmp_hi, Register xtmp_lo, Register buf, int offset) { + xmulx(xcrc_hi, xK_hi, xtmp_lo); + xmulxhi(xcrc_hi, xK_hi, xtmp_hi); + xmulxhi(xcrc_lo, xK_lo, xcrc_hi); + xmulx(xcrc_lo, xK_lo, xcrc_lo); + xor3(xcrc_lo, xtmp_lo, xcrc_lo); + xor3(xcrc_hi, xtmp_hi, xcrc_hi); + ldxl(buf, G0, xtmp_lo); + inc(buf, 8); + ldxl(buf, G0, xtmp_hi); + inc(buf, 8); + xor3(xcrc_lo, xtmp_lo, xcrc_lo); + xor3(xcrc_hi, xtmp_hi, xcrc_hi); +} + +void MacroAssembler::fold_128bit_crc32(Register xcrc_hi, Register xcrc_lo, Register xK_hi, Register xK_lo, Register xtmp_hi, Register xtmp_lo, Register xbuf_hi, Register xbuf_lo) { + mov(xcrc_lo, xtmp_lo); + mov(xcrc_hi, xtmp_hi); + xmulx(xtmp_hi, xK_hi, xtmp_lo); + xmulxhi(xtmp_hi, xK_hi, xtmp_hi); + xmulxhi(xcrc_lo, xK_lo, xcrc_hi); + xmulx(xcrc_lo, xK_lo, xcrc_lo); + xor3(xcrc_lo, xbuf_lo, xcrc_lo); + xor3(xcrc_hi, xbuf_hi, xcrc_hi); + xor3(xcrc_lo, xtmp_lo, xcrc_lo); + xor3(xcrc_hi, xtmp_hi, xcrc_hi); +} + +void MacroAssembler::fold_8bit_crc32(Register xcrc, Register table, Register xtmp, Register tmp) { + and3(xcrc, 0xFF, tmp); + sllx(tmp, 2, tmp); + lduw(table, tmp, xtmp); + srlx(xcrc, 8, xcrc); + xor3(xtmp, xcrc, xcrc); +} + +void MacroAssembler::fold_8bit_crc32(Register crc, Register table, Register tmp) { + and3(crc, 0xFF, tmp); + srlx(crc, 8, crc); + sllx(tmp, 2, tmp); + lduw(table, tmp, tmp); + xor3(tmp, crc, crc); +} + +#define CRC32_TMP_REG_NUM 18 + +#define CRC32_CONST_64 0x163cd6124 +#define CRC32_CONST_96 0x0ccaa009e +#define CRC32_CONST_160 0x1751997d0 +#define CRC32_CONST_480 0x1c6e41596 +#define CRC32_CONST_544 0x154442bd4 + +void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, Register table) { + + Label L_cleanup_loop, L_cleanup_check, L_align_loop, L_align_check; + Label L_main_loop_prologue; + Label L_fold_512b, L_fold_512b_loop, L_fold_128b; + Label L_fold_tail, L_fold_tail_loop; + Label L_8byte_fold_loop, L_8byte_fold_check; + + const Register tmp[CRC32_TMP_REG_NUM] = {L0, L1, L2, L3, L4, L5, L6, G1, I0, I1, I2, I3, I4, I5, I7, O4, O5, G3}; + + Register const_64 = tmp[CRC32_TMP_REG_NUM-1]; + Register const_96 = tmp[CRC32_TMP_REG_NUM-1]; + Register const_160 = tmp[CRC32_TMP_REG_NUM-2]; + Register const_480 = tmp[CRC32_TMP_REG_NUM-1]; + Register const_544 = tmp[CRC32_TMP_REG_NUM-2]; + + set(ExternalAddress(StubRoutines::crc_table_addr()), table); + + not1(crc); // ~c + clruwu(crc); // clear upper 32 bits of crc + + // Check if below cutoff, proceed directly to cleanup code + mov(31, G4); + cmp_and_br_short(len, G4, Assembler::lessEqualUnsigned, Assembler::pt, L_cleanup_check); + + // Align buffer to 8 byte boundry + mov(8, O5); + and3(buf, 0x7, O4); + sub(O5, O4, O5); + and3(O5, 0x7, O5); + sub(len, O5, len); + ba(L_align_check); + delayed()->nop(); + + // Alignment loop, table look up method for up to 7 bytes + bind(L_align_loop); + ldub(buf, 0, O4); + inc(buf); + dec(O5); + xor3(O4, crc, O4); + and3(O4, 0xFF, O4); + sllx(O4, 2, O4); + lduw(table, O4, O4); + srlx(crc, 8, crc); + xor3(O4, crc, crc); + bind(L_align_check); + nop(); + cmp_and_br_short(O5, 0, Assembler::notEqual, Assembler::pt, L_align_loop); + + // Aligned on 64-bit (8-byte) boundry at this point + // Check if still above cutoff (31-bytes) + mov(31, G4); + cmp_and_br_short(len, G4, Assembler::lessEqualUnsigned, Assembler::pt, L_cleanup_check); + // At least 32 bytes left to process + + // Free up registers by storing them to FP registers + for (int i = 0; i < CRC32_TMP_REG_NUM; i++) { + movxtod(tmp[i], as_FloatRegister(2*i)); + } + + // Determine which loop to enter + // Shared prologue + ldxl(buf, G0, tmp[0]); + inc(buf, 8); + ldxl(buf, G0, tmp[1]); + inc(buf, 8); + xor3(tmp[0], crc, tmp[0]); // Fold CRC into first few bytes + and3(crc, 0, crc); // Clear out the crc register + // Main loop needs 128-bytes at least + mov(128, G4); + mov(64, tmp[2]); + cmp_and_br_short(len, G4, Assembler::greaterEqualUnsigned, Assembler::pt, L_main_loop_prologue); + // Less than 64 bytes + nop(); + cmp_and_br_short(len, tmp[2], Assembler::lessUnsigned, Assembler::pt, L_fold_tail); + // Between 64 and 127 bytes + set64(CRC32_CONST_96, const_96, tmp[8]); + set64(CRC32_CONST_160, const_160, tmp[9]); + fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[2], tmp[3], buf, 0); + fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[4], tmp[5], buf, 16); + fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[6], tmp[7], buf, 32); + dec(len, 48); + ba(L_fold_tail); + delayed()->nop(); + + bind(L_main_loop_prologue); + for (int i = 2; i < 8; i++) { + ldxl(buf, G0, tmp[i]); + inc(buf, 8); + } + + // Fold total 512 bits of polynomial on each iteration, + // 128 bits per each of 4 parallel streams + set64(CRC32_CONST_480, const_480, tmp[8]); + set64(CRC32_CONST_544, const_544, tmp[9]); + + mov(128, G4); + bind(L_fold_512b_loop); + fold_128bit_crc32(tmp[1], tmp[0], const_480, const_544, tmp[9], tmp[8], buf, 0); + fold_128bit_crc32(tmp[3], tmp[2], const_480, const_544, tmp[11], tmp[10], buf, 16); + fold_128bit_crc32(tmp[5], tmp[4], const_480, const_544, tmp[13], tmp[12], buf, 32); + fold_128bit_crc32(tmp[7], tmp[6], const_480, const_544, tmp[15], tmp[14], buf, 64); + dec(len, 64); + cmp_and_br_short(len, G4, Assembler::greaterEqualUnsigned, Assembler::pt, L_fold_512b_loop); + + // Fold 512 bits to 128 bits + bind(L_fold_512b); + set64(CRC32_CONST_96, const_96, tmp[8]); + set64(CRC32_CONST_160, const_160, tmp[9]); + + fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[8], tmp[9], tmp[3], tmp[2]); + fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[8], tmp[9], tmp[5], tmp[4]); + fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[8], tmp[9], tmp[7], tmp[6]); + dec(len, 48); + + // Fold the rest of 128 bits data chunks + bind(L_fold_tail); + mov(32, G4); + cmp_and_br_short(len, G4, Assembler::lessEqualUnsigned, Assembler::pt, L_fold_128b); + + set64(CRC32_CONST_96, const_96, tmp[8]); + set64(CRC32_CONST_160, const_160, tmp[9]); + + bind(L_fold_tail_loop); + fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[2], tmp[3], buf, 0); + sub(len, 16, len); + cmp_and_br_short(len, G4, Assembler::greaterEqualUnsigned, Assembler::pt, L_fold_tail_loop); + + // Fold the 128 bits in tmps 0 - 1 into tmp 1 + bind(L_fold_128b); + + set64(CRC32_CONST_64, const_64, tmp[4]); + + xmulx(const_64, tmp[0], tmp[2]); + xmulxhi(const_64, tmp[0], tmp[3]); + + srl(tmp[2], G0, tmp[4]); + xmulx(const_64, tmp[4], tmp[4]); + + srlx(tmp[2], 32, tmp[2]); + sllx(tmp[3], 32, tmp[3]); + or3(tmp[2], tmp[3], tmp[2]); + + xor3(tmp[4], tmp[1], tmp[4]); + xor3(tmp[4], tmp[2], tmp[1]); + dec(len, 8); + + // Use table lookup for the 8 bytes left in tmp[1] + dec(len, 8); + + // 8 8-bit folds to compute 32-bit CRC. + for (int j = 0; j < 4; j++) { + fold_8bit_crc32(tmp[1], table, tmp[2], tmp[3]); + } + srl(tmp[1], G0, crc); // move 32 bits to general register + for (int j = 0; j < 4; j++) { + fold_8bit_crc32(crc, table, tmp[3]); + } + + bind(L_8byte_fold_check); + + // Restore int registers saved in FP registers + for (int i = 0; i < CRC32_TMP_REG_NUM; i++) { + movdtox(as_FloatRegister(2*i), tmp[i]); + } + + ba(L_cleanup_check); + delayed()->nop(); + + // Table look-up method for the remaining few bytes + bind(L_cleanup_loop); + ldub(buf, 0, O4); + inc(buf); + dec(len); + xor3(O4, crc, O4); + and3(O4, 0xFF, O4); + sllx(O4, 2, O4); + lduw(table, O4, O4); + srlx(crc, 8, crc); + xor3(O4, crc, crc); + bind(L_cleanup_check); + nop(); + cmp_and_br_short(len, 0, Assembler::greaterUnsigned, Assembler::pt, L_cleanup_loop); + + not1(crc); +} + diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp index 792a493bc01..d58fc54f1c9 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp @@ -904,7 +904,9 @@ public: inline void ldf(FloatRegisterImpl::Width w, const Address& a, FloatRegister d, int offset = 0); // little-endian - inline void ldxl(Register s1, Register s2, Register d) { ldxa(s1, s2, ASI_PRIMARY_LITTLE, d); } + inline void lduwl(Register s1, Register s2, Register d) { lduwa(s1, s2, ASI_PRIMARY_LITTLE, d); } + inline void ldswl(Register s1, Register s2, Register d) { ldswa(s1, s2, ASI_PRIMARY_LITTLE, d);} + inline void ldxl( Register s1, Register s2, Register d) { ldxa(s1, s2, ASI_PRIMARY_LITTLE, d); } inline void ldfl(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d) { ldfa(w, s1, s2, ASI_PRIMARY_LITTLE, d); } // membar psuedo instruction. takes into account target memory model. @@ -1469,6 +1471,15 @@ public: void movitof_revbytes(Register src, FloatRegister dst, Register tmp1, Register tmp2); void movftoi_revbytes(FloatRegister src, Register dst, Register tmp1, Register tmp2); + // CRC32 code for java.util.zip.CRC32::updateBytes0() instrinsic. + void kernel_crc32(Register crc, Register buf, Register len, Register table); + // Fold 128-bit data chunk + void fold_128bit_crc32(Register xcrc_hi, Register xcrc_lo, Register xK_hi, Register xK_lo, Register xtmp_hi, Register xtmp_lo, Register buf, int offset); + void fold_128bit_crc32(Register xcrc_hi, Register xcrc_lo, Register xK_hi, Register xK_lo, Register xtmp_hi, Register xtmp_lo, Register xbuf_hi, Register xbuf_lo); + // Fold 8-bit data + void fold_8bit_crc32(Register xcrc, Register table, Register xtmp, Register tmp); + void fold_8bit_crc32(Register crc, Register table, Register tmp); + #undef VIRTUAL }; diff --git a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp index e64ffa4f295..df1b5be8097 100644 --- a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp @@ -5292,6 +5292,38 @@ class StubGenerator: public StubCodeGenerator { return start; } +/** + * Arguments: + * + * Inputs: + * O0 - int crc + * O1 - byte* buf + * O2 - int len + * O3 - int* table + * + * Output: + * O0 - int crc result + */ + address generate_updateBytesCRC32() { + assert(UseCRC32Intrinsics, "need VIS3 instructions"); + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32"); + address start = __ pc(); + + const Register crc = O0; // crc + const Register buf = O1; // source java byte array address + const Register len = O2; // length + const Register table = O3; // crc_table address (reuse register) + + __ kernel_crc32(crc, buf, len, table); + + __ retl(); + __ delayed()->nop(); + + return start; + } + void generate_initial() { // Generates all stubs and initializes the entry points @@ -5324,6 +5356,12 @@ class StubGenerator: public StubCodeGenerator { // Build this early so it's available for the interpreter. StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError)); + + if (UseCRC32Intrinsics) { + // set table address before stub generation which use it + StubRoutines::_crc_table_adr = (address)StubRoutines::Sparc::_crc_table; + StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32(); + } } diff --git a/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.cpp b/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.cpp index 63fb86a1509..3a9ca6fffc9 100644 --- a/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,3 +52,98 @@ address StubRoutines::Sparc::_stop_subroutine_entry = NULL; address StubRoutines::Sparc::_flush_callers_register_windows_entry = CAST_FROM_FN_PTR(address, bootstrap_flush_windows); address StubRoutines::Sparc::_partial_subtype_check = NULL; + +uint64_t StubRoutines::Sparc::_crc_by128_masks[] = +{ + /* The fields in this structure are arranged so that they can be + * picked up two at a time with 128-bit loads. + * + * Because of flipped bit order for this CRC polynomials + * the constant for X**N is left-shifted by 1. This is because + * a 64 x 64 polynomial multiply produces a 127-bit result + * but the highest term is always aligned to bit 0 in the container. + * Pre-shifting by one fixes this, at the cost of potentially making + * the 32-bit constant no longer fit in a 32-bit container (thus the + * use of uint64_t, though this is also the size used by the carry- + * less multiply instruction. + * + * In addition, the flipped bit order and highest-term-at-least-bit + * multiply changes the constants used. The 96-bit result will be + * aligned to the high-term end of the target 128-bit container, + * not the low-term end; that is, instead of a 512-bit or 576-bit fold, + * instead it is a 480 (=512-32) or 544 (=512+64-32) bit fold. + * + * This cause additional problems in the 128-to-64-bit reduction; see the + * code for details. By storing a mask in the otherwise unused half of + * a 128-bit constant, bits can be cleared before multiplication without + * storing and reloading. Note that staying on a 128-bit datapath means + * that some data is uselessly stored and some unused data is intersected + * with an irrelevant constant. + */ + + ((uint64_t) 0xffffffffUL), /* low of K_M_64 */ + ((uint64_t) 0xb1e6b092U << 1), /* high of K_M_64 */ + ((uint64_t) 0xba8ccbe8U << 1), /* low of K_160_96 */ + ((uint64_t) 0x6655004fU << 1), /* high of K_160_96 */ + ((uint64_t) 0xaa2215eaU << 1), /* low of K_544_480 */ + ((uint64_t) 0xe3720acbU << 1) /* high of K_544_480 */ +}; + +/** + * crc_table[] from jdk/src/java.base/share/native/libzip/zlib-1.2.8/crc32.h + */ +juint StubRoutines::Sparc::_crc_table[] = +{ + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +}; diff --git a/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.hpp b/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.hpp index eeeb31d608d..e28ec2ffb31 100644 --- a/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.hpp @@ -53,6 +53,9 @@ class Sparc { static address _flush_callers_register_windows_entry; static address _partial_subtype_check; + // masks and table for CRC32 + static uint64_t _crc_by128_masks[]; + static juint _crc_table[]; public: // test assembler stop routine by setting registers @@ -65,6 +68,8 @@ class Sparc { static intptr_t* (*flush_callers_register_windows_func())() { return CAST_TO_FN_PTR(intptr_t* (*)(void), _flush_callers_register_windows_entry); } static address partial_subtype_check() { return _partial_subtype_check; } + + static address crc_by128_masks_addr() { return (address)_crc_by128_masks; } }; #endif // CPU_SPARC_VM_STUBROUTINES_SPARC_HPP diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp index 703a1b0f30c..a76004f786d 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp @@ -803,6 +803,106 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { return NULL; } +/** + * Method entry for static native methods: + * int java.util.zip.CRC32.update(int crc, int b) + */ +address InterpreterGenerator::generate_CRC32_update_entry() { + + if (UseCRC32Intrinsics) { + address entry = __ pc(); + + Label L_slow_path; + // If we need a safepoint check, generate full interpreter entry. + ExternalAddress state(SafepointSynchronize::address_of_state()); + __ set(ExternalAddress(SafepointSynchronize::address_of_state()), O2); + __ set(SafepointSynchronize::_not_synchronized, O3); + __ cmp_and_br_short(O2, O3, Assembler::notEqual, Assembler::pt, L_slow_path); + + // Load parameters + const Register crc = O0; // initial crc + const Register val = O1; // byte to update with + const Register table = O2; // address of 256-entry lookup table + + __ ldub(Gargs, 3, val); + __ lduw(Gargs, 8, crc); + + __ set(ExternalAddress(StubRoutines::crc_table_addr()), table); + + __ not1(crc); // ~crc + __ clruwu(crc); + __ update_byte_crc32(crc, val, table); + __ not1(crc); // ~crc + + // result in O0 + __ retl(); + __ delayed()->nop(); + + // generate a vanilla native entry as the slow path + __ bind(L_slow_path); + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); + return entry; + } + return NULL; +} + +/** + * Method entry for static native methods: + * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len) + * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len) + */ +address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { + + if (UseCRC32Intrinsics) { + address entry = __ pc(); + + Label L_slow_path; + // If we need a safepoint check, generate full interpreter entry. + ExternalAddress state(SafepointSynchronize::address_of_state()); + __ set(ExternalAddress(SafepointSynchronize::address_of_state()), O2); + __ set(SafepointSynchronize::_not_synchronized, O3); + __ cmp_and_br_short(O2, O3, Assembler::notEqual, Assembler::pt, L_slow_path); + + // Load parameters from the stack + const Register crc = O0; // initial crc + const Register buf = O1; // source java byte array address + const Register len = O2; // len + const Register offset = O3; // offset + + // Arguments are reversed on java expression stack + // Calculate address of start element + if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) { + __ lduw(Gargs, 0, len); + __ lduw(Gargs, 8, offset); + __ ldx( Gargs, 16, buf); + __ lduw(Gargs, 32, crc); + __ add(buf, offset, buf); + } else { + __ lduw(Gargs, 0, len); + __ lduw(Gargs, 8, offset); + __ ldx( Gargs, 16, buf); + __ lduw(Gargs, 24, crc); + __ add(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE), buf); // account for the header size + __ add(buf ,offset, buf); + } + + // Call the crc32 kernel + __ MacroAssembler::save_thread(L7_thread_cache); + __ kernel_crc32(crc, buf, len, O3); + __ MacroAssembler::restore_thread(L7_thread_cache); + + // result in O0 + __ retl(); + __ delayed()->nop(); + + // generate a vanilla native entry as the slow path + __ bind(L_slow_path); + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); + return entry; + } + return NULL; +} + // // Interpreter stub for calling a native method. (asm interpreter) // This sets up a somewhat different looking stack for calling the native method diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index 1c42f501bd5..e6a79435447 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -347,6 +347,15 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseAdler32Intrinsics, false); } + if (UseVIS > 2) { + if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) { + FLAG_SET_DEFAULT(UseCRC32Intrinsics, true); + } + } else if (UseCRC32Intrinsics) { + warning("SPARC CRC32 intrinsics require VIS3 insructions support. Intriniscs will be disabled"); + FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); + } + if (FLAG_IS_DEFAULT(ContendedPaddingWidth) && (cache_line_size > ContendedPaddingWidth)) ContendedPaddingWidth = cache_line_size; diff --git a/hotspot/test/compiler/intrinsics/crc32/TestCRC32.java b/hotspot/test/compiler/intrinsics/crc32/TestCRC32.java new file mode 100644 index 00000000000..f7ecc241508 --- /dev/null +++ b/hotspot/test/compiler/intrinsics/crc32/TestCRC32.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8143012 + * @summary CRC32 Intrinsics support on SPARC + * + * @run main/othervm/timeout=720 -Xbatch TestCRC32 -m + */ + +import java.nio.ByteBuffer; +import java.util.zip.Checksum; +import java.util.zip.CRC32; + +public class TestCRC32 { + public static void main(String[] args) { + int offset = Integer.getInteger("offset", 0); + int msgSize = Integer.getInteger("msgSize", 512); + boolean multi = false; + int iters = 20000; + int warmupIters = 20000; + + if (args.length > 0) { + if (args[0].equals("-m")) { + multi = true; + } else { + iters = Integer.valueOf(args[0]); + } + if (args.length > 1) { + warmupIters = Integer.valueOf(args[1]); + } + } + + if (multi) { + test_multi(warmupIters); + return; + } + + System.out.println(" offset = " + offset); + System.out.println("msgSize = " + msgSize + " bytes"); + System.out.println(" iters = " + iters); + + byte[] b = initializedBytes(msgSize, offset); + + CRC32 crc0 = new CRC32(); + CRC32 crc1 = new CRC32(); + CRC32 crc2 = new CRC32(); + + crc0.update(b, offset, msgSize); + + System.out.println("-------------------------------------------------------"); + + /* warm up */ + for (int i = 0; i < warmupIters; i++) { + crc1.reset(); + crc1.update(b, offset, msgSize); + } + + /* measure performance */ + long start = System.nanoTime(); + for (int i = 0; i < iters; i++) { + crc1.reset(); + crc1.update(b, offset, msgSize); + } + long end = System.nanoTime(); + double total = (double)(end - start)/1e9; // in seconds + double thruput = (double)msgSize*iters/1e6/total; // in MB/s + System.out.println("CRC32.update(byte[]) runtime = " + total + " seconds"); + System.out.println("CRC32.update(byte[]) throughput = " + thruput + " MB/s"); + + /* check correctness */ + for (int i = 0; i < iters; i++) { + crc1.reset(); + crc1.update(b, offset, msgSize); + if (!check(crc0, crc1)) break; + } + report("CRCs", crc0, crc1); + + System.out.println("-------------------------------------------------------"); + + ByteBuffer buf = ByteBuffer.allocateDirect(msgSize); + buf.put(b, offset, msgSize); + buf.flip(); + + /* warm up */ + for (int i = 0; i < warmupIters; i++) { + crc2.reset(); + crc2.update(buf); + buf.rewind(); + } + + /* measure performance */ + start = System.nanoTime(); + for (int i = 0; i < iters; i++) { + crc2.reset(); + crc2.update(buf); + buf.rewind(); + } + end = System.nanoTime(); + total = (double)(end - start)/1e9; // in seconds + thruput = (double)msgSize*iters/1e6/total; // in MB/s + System.out.println("CRC32.update(ByteBuffer) runtime = " + total + " seconds"); + System.out.println("CRC32.update(ByteBuffer) throughput = " + thruput + " MB/s"); + + /* check correctness */ + for (int i = 0; i < iters; i++) { + crc2.reset(); + crc2.update(buf); + buf.rewind(); + if (!check(crc0, crc2)) break; + } + report("CRCs", crc0, crc2); + + System.out.println("-------------------------------------------------------"); + } + + private static void report(String s, Checksum crc0, Checksum crc1) { + System.out.printf("%s: crc0 = %08x, crc1 = %08x\n", + s, crc0.getValue(), crc1.getValue()); + } + + private static boolean check(Checksum crc0, Checksum crc1) { + if (crc0.getValue() != crc1.getValue()) { + System.err.printf("ERROR: crc0 = %08x, crc1 = %08x\n", + crc0.getValue(), crc1.getValue()); + return false; + } + return true; + } + + private static byte[] initializedBytes(int M, int offset) { + byte[] bytes = new byte[M + offset]; + for (int i = 0; i < offset; i++) { + bytes[i] = (byte) i; + } + for (int i = offset; i < bytes.length; i++) { + bytes[i] = (byte) (i - offset); + } + return bytes; + } + + private static void test_multi(int iters) { + int len1 = 8; // the 8B/iteration loop + int len2 = 32; // the 32B/iteration loop + int len3 = 4096; // the 4KB/iteration loop + + byte[] b = initializedBytes(len3*16, 0); + int[] offsets = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 256, 512 }; + int[] sizes = { 0, 1, 2, 3, 4, 5, 6, 7, + len1, len1+1, len1+2, len1+3, len1+4, len1+5, len1+6, len1+7, + len1*2, len1*2+1, len1*2+3, len1*2+5, len1*2+7, + len2, len2+1, len2+3, len2+5, len2+7, + len2*2, len2*4, len2*8, len2*16, len2*32, len2*64, + len3, len3+1, len3+3, len3+5, len3+7, + len3*2, len3*4, len3*8, + len1+len2, len1+len2+1, len1+len2+3, len1+len2+5, len1+len2+7, + len1+len3, len1+len3+1, len1+len3+3, len1+len3+5, len1+len3+7, + len2+len3, len2+len3+1, len2+len3+3, len2+len3+5, len2+len3+7, + len1+len2+len3, len1+len2+len3+1, len1+len2+len3+3, + len1+len2+len3+5, len1+len2+len3+7, + (len1+len2+len3)*2, (len1+len2+len3)*2+1, (len1+len2+len3)*2+3, + (len1+len2+len3)*2+5, (len1+len2+len3)*2+7, + (len1+len2+len3)*3, (len1+len2+len3)*3-1, (len1+len2+len3)*3-3, + (len1+len2+len3)*3-5, (len1+len2+len3)*3-7 }; + CRC32[] crc0 = new CRC32[offsets.length*sizes.length]; + CRC32[] crc1 = new CRC32[offsets.length*sizes.length]; + int i, j, k; + + System.out.printf("testing %d cases ...\n", offsets.length*sizes.length); + + /* set the result from interpreter as reference */ + for (i = 0; i < offsets.length; i++) { + for (j = 0; j < sizes.length; j++) { + crc0[i*sizes.length + j] = new CRC32(); + crc1[i*sizes.length + j] = new CRC32(); + crc0[i*sizes.length + j].update(b, offsets[i], sizes[j]); + } + } + + /* warm up the JIT compiler and get result */ + for (k = 0; k < iters; k++) { + for (i = 0; i < offsets.length; i++) { + for (j = 0; j < sizes.length; j++) { + crc1[i*sizes.length + j].reset(); + crc1[i*sizes.length + j].update(b, offsets[i], sizes[j]); + } + } + } + + /* check correctness */ + for (i = 0; i < offsets.length; i++) { + for (j = 0; j < sizes.length; j++) { + if (!check(crc0[i*sizes.length + j], crc1[i*sizes.length + j])) { + System.out.printf("offsets[%d] = %d", i, offsets[i]); + System.out.printf("\tsizes[%d] = %d\n", j, sizes[j]); + } + } + } + } +} From e9d7b653141007eba30cd5595f9596caa691b273 Mon Sep 17 00:00:00 2001 From: Ed Nevill Date: Thu, 19 Nov 2015 15:15:20 +0000 Subject: [PATCH 125/260] 8143067: aarch64: guarantee failure in javac Fix adrp going out of range during code relocation Reviewed-by: aph, kvn --- .../cpu/aarch64/vm/macroAssembler_aarch64.cpp | 80 ++++++++++--------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index a827da7a5be..ca91cb83478 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -91,20 +91,18 @@ int MacroAssembler::pd_patch_instruction_size(address branch, address target) { unsigned offset_lo = dest & 0xfff; offset = adr_page - pc_page; - // We handle 3 types of PC relative addressing + // We handle 4 types of PC relative addressing // 1 - adrp Rx, target_page // ldr/str Ry, [Rx, #offset_in_page] // 2 - adrp Rx, target_page // add Ry, Rx, #offset_in_page // 3 - adrp Rx, target_page (page aligned reloc, offset == 0) - // In the first 2 cases we must check that Rx is the same in the adrp and the - // subsequent ldr/str or add instruction. Otherwise we could accidentally end - // up treating a type 3 relocation as a type 1 or 2 just because it happened - // to be followed by a random unrelated ldr/str or add instruction. - // - // In the case of a type 3 relocation, we know that these are only generated - // for the safepoint polling page, or for the card type byte map base so we - // assert as much and of course that the offset is 0. + // movk Rx, #imm16<<32 + // 4 - adrp Rx, target_page (page aligned reloc, offset == 0) + // In the first 3 cases we must check that Rx is the same in the adrp and the + // subsequent ldr/str, add or movk instruction. Otherwise we could accidentally end + // up treating a type 4 relocation as a type 1, 2 or 3 just because it happened + // to be followed by a random unrelated ldr/str, add or movk instruction. // unsigned insn2 = ((unsigned*)branch)[1]; if (Instruction_aarch64::extract(insn2, 29, 24) == 0b111001 && @@ -123,13 +121,13 @@ int MacroAssembler::pd_patch_instruction_size(address branch, address target) { Instruction_aarch64::patch(branch + sizeof (unsigned), 21, 10, offset_lo); instructions = 2; - } else { - assert((jbyte *)target == - ((CardTableModRefBS*)(Universe::heap()->barrier_set()))->byte_map_base || - target == StubRoutines::crc_table_addr() || - (address)target == os::get_polling_page(), - "adrp must be polling page or byte map base"); - assert(offset_lo == 0, "offset must be 0 for polling page or byte map base"); + } else if (Instruction_aarch64::extract(insn2, 31, 21) == 0b11110010110 && + Instruction_aarch64::extract(insn, 4, 0) == + Instruction_aarch64::extract(insn2, 4, 0)) { + // movk #imm16<<32 + Instruction_aarch64::patch(branch + 4, 20, 5, (uint64_t)target >> 32); + offset &= (1<<20)-1; + instructions = 2; } } int offset_lo = offset & 3; @@ -212,16 +210,16 @@ address MacroAssembler::target_addr_for_insn(address insn_addr, unsigned insn) { // Return the target address for the following sequences // 1 - adrp Rx, target_page // ldr/str Ry, [Rx, #offset_in_page] - // 2 - adrp Rx, target_page ] + // 2 - adrp Rx, target_page // add Ry, Rx, #offset_in_page // 3 - adrp Rx, target_page (page aligned reloc, offset == 0) + // movk Rx, #imm12<<32 + // 4 - adrp Rx, target_page (page aligned reloc, offset == 0) // // In the first two cases we check that the register is the same and // return the target_page + the offset within the page. // Otherwise we assume it is a page aligned relocation and return - // the target page only. The only cases this is generated is for - // the safepoint polling page or for the card table byte map base so - // we assert as much. + // the target page only. // unsigned insn2 = ((unsigned*)insn_addr)[1]; if (Instruction_aarch64::extract(insn2, 29, 24) == 0b111001 && @@ -238,10 +236,12 @@ address MacroAssembler::target_addr_for_insn(address insn_addr, unsigned insn) { unsigned int byte_offset = Instruction_aarch64::extract(insn2, 21, 10); return address(target_page + byte_offset); } else { - assert((jbyte *)target_page == - ((CardTableModRefBS*)(Universe::heap()->barrier_set()))->byte_map_base || - (address)target_page == os::get_polling_page(), - "adrp must be polling page or byte map base"); + if (Instruction_aarch64::extract(insn2, 31, 21) == 0b11110010110 && + Instruction_aarch64::extract(insn, 4, 0) == + Instruction_aarch64::extract(insn2, 4, 0)) { + target_page = (target_page & 0xffffffff) | + ((uint64_t)Instruction_aarch64::extract(insn2, 20, 5) << 32); + } return (address)target_page; } } else { @@ -3964,22 +3964,26 @@ address MacroAssembler::read_polling_page(Register r, relocInfo::relocType rtype void MacroAssembler::adrp(Register reg1, const Address &dest, unsigned long &byte_offset) { relocInfo::relocType rtype = dest.rspec().reloc()->type(); - if (uabs(pc() - dest.target()) >= (1LL << 32)) { - guarantee(rtype == relocInfo::none - || rtype == relocInfo::external_word_type - || rtype == relocInfo::poll_type - || rtype == relocInfo::poll_return_type, - "can only use a fixed address with an ADRP"); - // Out of range. This doesn't happen very often, but we have to - // handle it - mov(reg1, dest); - byte_offset = 0; - } else { - InstructionMark im(this); - code_section()->relocate(inst_mark(), dest.rspec()); - byte_offset = (uint64_t)dest.target() & 0xfff; + unsigned long low_page = (unsigned long)CodeCache::low_bound() >> 12; + unsigned long high_page = (unsigned long)(CodeCache::high_bound()-1) >> 12; + unsigned long dest_page = (unsigned long)dest.target() >> 12; + long offset_low = dest_page - low_page; + long offset_high = dest_page - high_page; + + InstructionMark im(this); + code_section()->relocate(inst_mark(), dest.rspec()); + // 8143067: Ensure that the adrp can reach the dest from anywhere within + // the code cache so that if it is relocated we know it will still reach + if (offset_high >= -(1<<20) && offset_low < (1<<20)) { _adrp(reg1, dest.target()); + } else { + unsigned long pc_page = (unsigned long)pc() >> 12; + long offset = dest_page - pc_page; + offset = (offset & ((1<<20)-1)) << 12; + _adrp(reg1, pc()+offset); + movk(reg1, ((unsigned long)dest.target() >> 32) & 0xffff, 32); } + byte_offset = (unsigned long)dest.target() & 0xfff; } void MacroAssembler::build_frame(int framesize) { From d0382697c4d95c149127e75731d1300331e864dc Mon Sep 17 00:00:00 2001 From: Zoltan Majo Date: Mon, 23 Nov 2015 08:11:30 +0100 Subject: [PATCH 126/260] 8143208: compiler/c1/6855215/Test6855215.java supports_sse2() failed Check that SSE is enabled before using SSE instructions in string-related intrinsics. Make the UseSSE42Intrinsics dependent on UseSSE >= 4. Reviewed-by: kvn --- hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp | 84 ++++++++++--------- hotspot/src/cpu/x86/vm/vm_version_x86.cpp | 18 +++- 2 files changed, 58 insertions(+), 44 deletions(-) diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 9062cbb7730..d73fbe3fe77 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -7387,7 +7387,8 @@ void MacroAssembler::string_indexofC8(Register str1, Register str2, XMMRegister vec, Register tmp, int ae) { ShortBranchVerifier sbv(this); - assert(UseSSE42Intrinsics, "SSE4.2 is required"); + assert(UseSSE42Intrinsics, "SSE4.2 intrinsics are required"); + assert(UseSSE >= 4, "SSE4 must be enabled for SSE4.2 intrinsics to be available"); assert(ae != StrIntrinsicNode::LU, "Invalid encoding"); // This method uses the pcmpestri instruction with bound registers @@ -7565,7 +7566,8 @@ void MacroAssembler::string_indexof(Register str1, Register str2, XMMRegister vec, Register tmp, int ae) { ShortBranchVerifier sbv(this); - assert(UseSSE42Intrinsics, "SSE4.2 is required"); + assert(UseSSE42Intrinsics, "SSE4.2 intrinsics are required"); + assert(UseSSE >= 4, "SSE4 must be enabled for SSE4.2 intrinsics to be available"); assert(ae != StrIntrinsicNode::LU, "Invalid encoding"); // @@ -7882,7 +7884,8 @@ void MacroAssembler::string_indexof(Register str1, Register str2, void MacroAssembler::string_indexof_char(Register str1, Register cnt1, Register ch, Register result, XMMRegister vec1, XMMRegister vec2, XMMRegister vec3, Register tmp) { ShortBranchVerifier sbv(this); - assert(UseSSE42Intrinsics, "SSE4.2 is required"); + assert(UseSSE42Intrinsics, "SSE4.2 intrinsics are required"); + assert(UseSSE >= 4, "SSE4 must be enabled for SSE4.2 intrinsics to be available"); int stride = 8; @@ -7919,36 +7922,32 @@ void MacroAssembler::string_indexof_char(Register str1, Register cnt1, Register pshufd(vec1, vec1, 0); pxor(vec2, vec2); } - if (UseAVX >= 2 || UseSSE42Intrinsics) { - bind(SCAN_TO_8_CHAR); - cmpl(cnt1, stride); - if (UseAVX >= 2) { - jccb(Assembler::less, SCAN_TO_CHAR); - } - if (!(UseAVX >= 2)) { - jccb(Assembler::less, SCAN_TO_CHAR_LOOP); - movdl(vec1, ch); - pshuflw(vec1, vec1, 0x00); - pshufd(vec1, vec1, 0); - pxor(vec2, vec2); - } - movl(tmp, cnt1); - andl(tmp, 0xFFFFFFF8); //vector count (in chars) - andl(cnt1,0x00000007); //tail count (in chars) - - bind(SCAN_TO_8_CHAR_LOOP); - movdqu(vec3, Address(result, 0)); - pcmpeqw(vec3, vec1); - ptest(vec2, vec3); - jcc(Assembler::carryClear, FOUND_CHAR); - addptr(result, 16); - subl(tmp, stride); - jccb(Assembler::notZero, SCAN_TO_8_CHAR_LOOP); + bind(SCAN_TO_8_CHAR); + cmpl(cnt1, stride); + if (UseAVX >= 2) { + jccb(Assembler::less, SCAN_TO_CHAR); + } else { + jccb(Assembler::less, SCAN_TO_CHAR_LOOP); + movdl(vec1, ch); + pshuflw(vec1, vec1, 0x00); + pshufd(vec1, vec1, 0); + pxor(vec2, vec2); } + movl(tmp, cnt1); + andl(tmp, 0xFFFFFFF8); //vector count (in chars) + andl(cnt1,0x00000007); //tail count (in chars) + + bind(SCAN_TO_8_CHAR_LOOP); + movdqu(vec3, Address(result, 0)); + pcmpeqw(vec3, vec1); + ptest(vec2, vec3); + jcc(Assembler::carryClear, FOUND_CHAR); + addptr(result, 16); + subl(tmp, stride); + jccb(Assembler::notZero, SCAN_TO_8_CHAR_LOOP); bind(SCAN_TO_CHAR); testl(cnt1, cnt1); jcc(Assembler::zero, RET_NOT_FOUND); - bind(SCAN_TO_CHAR_LOOP); load_unsigned_short(tmp, Address(result, 0)); cmpl(ch, tmp); @@ -7962,16 +7961,14 @@ void MacroAssembler::string_indexof_char(Register str1, Register cnt1, Register movl(result, -1); jmpb(DONE_LABEL); - if (UseAVX >= 2 || UseSSE42Intrinsics) { - bind(FOUND_CHAR); - if (UseAVX >= 2) { - vpmovmskb(tmp, vec3); - } else { - pmovmskb(tmp, vec3); - } - bsfl(ch, tmp); - addl(result, ch); + bind(FOUND_CHAR); + if (UseAVX >= 2) { + vpmovmskb(tmp, vec3); + } else { + pmovmskb(tmp, vec3); } + bsfl(ch, tmp); + addl(result, ch); bind(FOUND_SEQ_CHAR); subptr(result, str1); @@ -8060,6 +8057,7 @@ void MacroAssembler::string_compare(Register str1, Register str2, } if (UseAVX >= 2 && UseSSE42Intrinsics) { + assert(UseSSE >= 4, "SSE4 must be enabled for SSE4.2 intrinsics to be available"); Label COMPARE_WIDE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_WIDE_TAIL, COMPARE_SMALL_STR; Label COMPARE_WIDE_VECTORS_LOOP, COMPARE_16_CHARS, COMPARE_INDEX_CHAR; Label COMPARE_TAIL_LONG; @@ -8195,6 +8193,7 @@ void MacroAssembler::string_compare(Register str1, Register str2, bind(COMPARE_SMALL_STR); } else if (UseSSE42Intrinsics) { + assert(UseSSE >= 4, "SSE4 must be enabled for SSE4.2 intrinsics to be available"); Label COMPARE_WIDE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL; int pcmpmask = 0x19; // Setup to compare 8-char (16-byte) vectors, @@ -8327,7 +8326,7 @@ void MacroAssembler::has_negatives(Register ary1, Register len, movl(result, len); // copy - if (UseAVX >= 2) { + if (UseAVX >= 2 && UseSSE >= 2) { // With AVX2, use 32-byte vector compare Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; @@ -8362,6 +8361,7 @@ void MacroAssembler::has_negatives(Register ary1, Register len, movl(len, result); // Fallthru to tail compare } else if (UseSSE42Intrinsics) { + assert(UseSSE >= 4, "SSE4 must be for SSE4.2 intrinsics to be available"); // With SSE4.2, use double quad vector compare Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; @@ -8438,7 +8438,7 @@ void MacroAssembler::has_negatives(Register ary1, Register len, // That's it bind(DONE); - if (UseAVX >= 2) { + if (UseAVX >= 2 && UseSSE >= 2) { // clean upper bits of YMM registers vpxor(vec1, vec1); vpxor(vec2, vec2); @@ -8526,6 +8526,7 @@ void MacroAssembler::arrays_equals(bool is_array_equ, Register ary1, Register ar movl(limit, result); // Fallthru to tail compare } else if (UseSSE42Intrinsics) { + assert(UseSSE >= 4, "SSE4 must be enabled for SSE4.2 intrinsics to be available"); // With SSE4.2, use double quad vector compare Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; @@ -8875,6 +8876,7 @@ void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, negptr(len); if (UseSSE42Intrinsics || UseAVX >= 2) { + assert(UseSSE42Intrinsics ? UseSSE >= 4 : true, "SSE4 must be enabled for SSE4.2 intrinsics to be available"); Label L_chars_8_check, L_copy_8_chars, L_copy_8_chars_exit; Label L_chars_16_check, L_copy_16_chars, L_copy_16_chars_exit; @@ -10647,6 +10649,7 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le push(len); if (UseSSE42Intrinsics) { + assert(UseSSE >= 4, "SSE4 must be enabled for SSE4.2 intrinsics to be available"); Label copy_32_loop, copy_16, copy_tail; movl(result, len); @@ -10746,6 +10749,7 @@ void MacroAssembler::byte_array_inflate(Register src, Register dst, Register len assert_different_registers(src, dst, len, tmp2); if (UseSSE42Intrinsics) { + assert(UseSSE >= 4, "SSE4 must be enabled for SSE4.2 intrinsics to be available"); Label copy_8_loop, copy_bytes, copy_tail; movl(tmp2, len); diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index e9d8c257de5..eed88e81342 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -930,10 +930,15 @@ void VM_Version::get_processor_features() { UseXmmI2D = false; } } - if( FLAG_IS_DEFAULT(UseSSE42Intrinsics) ) { - if( supports_sse4_2() && UseSSE >= 4 ) { - UseSSE42Intrinsics = true; + if (supports_sse4_2() && UseSSE >= 4) { + if (FLAG_IS_DEFAULT(UseSSE42Intrinsics)) { + FLAG_SET_DEFAULT(UseSSE42Intrinsics, true); } + } else { + if (UseSSE42Intrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { + warning("SSE4.2 intrinsics require SSE4.2 instructions or higher. Intrinsics will be disabled."); + } + FLAG_SET_DEFAULT(UseSSE42Intrinsics, false); } // some defaults for AMD family 15h @@ -1007,8 +1012,13 @@ void VM_Version::get_processor_features() { } if (supports_sse4_2() && UseSSE >= 4) { if (FLAG_IS_DEFAULT(UseSSE42Intrinsics)) { - UseSSE42Intrinsics = true; + FLAG_SET_DEFAULT(UseSSE42Intrinsics, true); } + } else { + if (UseSSE42Intrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { + warning("SSE4.2 intrinsics require SSE4.2 instructions or higher. Intrinsics will be disabled."); + } + FLAG_SET_DEFAULT(UseSSE42Intrinsics, false); } } if ((cpu_family() == 0x06) && From e2896c949dfec9802599fac5579bd9d8edfa60a6 Mon Sep 17 00:00:00 2001 From: Zoltan Majo Date: Mon, 23 Nov 2015 15:09:45 +0100 Subject: [PATCH 127/260] 8143616: Cleanup: Remove unused PrintNMethodsAtLevel flag Remove the unused PrintNMethodsAtLevel flag. Reviewed-by: roland --- hotspot/src/share/vm/runtime/globals.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 6e2a40c82cc..c6b83da55ab 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1126,9 +1126,6 @@ public: diagnostic(bool, PrintNMethods, false, \ "Print assembly code for nmethods when generated") \ \ - diagnostic(intx, PrintNMethodsAtLevel, -1, \ - "Only print code for nmethods at the given compilation level") \ - \ diagnostic(bool, PrintNativeNMethods, false, \ "Print assembly code for native nmethods when generated") \ \ From 975140c53060bbb311adf75cd3a15de0639185c4 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 19 Nov 2015 12:53:33 +0100 Subject: [PATCH 128/260] 8143307: Crash in C2 local code motion Reviewed-by: kvn --- hotspot/src/share/vm/opto/lcm.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp index 1dd92fa610f..57614f7cddf 100644 --- a/hotspot/src/share/vm/opto/lcm.cpp +++ b/hotspot/src/share/vm/opto/lcm.cpp @@ -498,9 +498,13 @@ Node* PhaseCFG::select( continue; // Schedule IV increment last. - if (e->is_Mach() && e->as_Mach()->ideal_Opcode() == Op_CountedLoopEnd && - e->in(1)->in(1) == n && n->is_iteratively_computed()) - continue; + if (e->is_Mach() && e->as_Mach()->ideal_Opcode() == Op_CountedLoopEnd) { + // Cmp might be matched into CountedLoopEnd node. + Node *cmp = (e->in(1)->ideal_reg() == Op_RegFlags) ? e->in(1) : e; + if (cmp->req() > 1 && cmp->in(1) == n && n->is_iteratively_computed()) { + continue; + } + } uint n_choice = 2; From 71fe04f939e618827c5da84fddcc40f2a4670afb Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Thu, 19 Nov 2015 11:54:32 -0500 Subject: [PATCH 129/260] 8143078: Remove JVM_DefineClassWithSourceCond() API Remove the method and remove unneeded argument to jvm_define_class_common() Reviewed-by: dholmes, coleenp --- hotspot/make/share/makefiles/mapfile-vers | 1 - hotspot/src/share/vm/prims/jvm.cpp | 19 ++++--------------- hotspot/src/share/vm/prims/jvm.h | 11 ----------- 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/hotspot/make/share/makefiles/mapfile-vers b/hotspot/make/share/makefiles/mapfile-vers index 57b5ad37c41..7021e53d444 100644 --- a/hotspot/make/share/makefiles/mapfile-vers +++ b/hotspot/make/share/makefiles/mapfile-vers @@ -31,7 +31,6 @@ JVM_CurrentTimeMillis; JVM_DefineClass; JVM_DefineClassWithSource; - JVM_DefineClassWithSourceCond; JVM_DesiredAssertionStatus; JVM_DoPrivileged; JVM_DumpAllStacks; diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index d25485c051e..45db3542ec2 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -861,11 +861,10 @@ static void is_lock_held_by_thread(Handle loader, PerfCounter* counter, TRAPS) { } // common code for JVM_DefineClass() and JVM_DefineClassWithSource() -// and JVM_DefineClassWithSourceCond() static jclass jvm_define_class_common(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source, - jboolean verify, TRAPS) { + TRAPS) { if (source == NULL) source = "__JVM_DefineClass__"; assert(THREAD->is_Java_thread(), "must be a JavaThread"); @@ -906,8 +905,7 @@ static jclass jvm_define_class_common(JNIEnv *env, const char *name, Handle protection_domain (THREAD, JNIHandles::resolve(pd)); Klass* k = SystemDictionary::resolve_from_stream(class_name, class_loader, protection_domain, &st, - verify != 0, - CHECK_NULL); + true, CHECK_NULL); if (TraceClassResolution && k != NULL) { trace_class_resolution(k); @@ -920,23 +918,14 @@ static jclass jvm_define_class_common(JNIEnv *env, const char *name, JVM_ENTRY(jclass, JVM_DefineClass(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd)) JVMWrapper2("JVM_DefineClass %s", name); - return jvm_define_class_common(env, name, loader, buf, len, pd, NULL, true, THREAD); + return jvm_define_class_common(env, name, loader, buf, len, pd, NULL, THREAD); JVM_END JVM_ENTRY(jclass, JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source)) JVMWrapper2("JVM_DefineClassWithSource %s", name); - return jvm_define_class_common(env, name, loader, buf, len, pd, source, true, THREAD); -JVM_END - -JVM_ENTRY(jclass, JVM_DefineClassWithSourceCond(JNIEnv *env, const char *name, - jobject loader, const jbyte *buf, - jsize len, jobject pd, - const char *source, jboolean verify)) - JVMWrapper2("JVM_DefineClassWithSourceCond %s", name); - - return jvm_define_class_common(env, name, loader, buf, len, pd, source, verify, THREAD); + return jvm_define_class_common(env, name, loader, buf, len, pd, source, THREAD); JVM_END JVM_ENTRY(jclass, JVM_FindLoadedClass(JNIEnv *env, jobject loader, jstring name)) diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index beb5bc8f32a..bc42dbf3edb 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -378,17 +378,6 @@ JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source); -/* Define a class with a source with conditional verification (added HSX 14) - * -Xverify:all will verify anyway, -Xverify:none will not verify, - * -Xverify:remote (default) will obey this conditional - * i.e. true = should_verify_class - */ -JNIEXPORT jclass JNICALL -JVM_DefineClassWithSourceCond(JNIEnv *env, const char *name, - jobject loader, const jbyte *buf, - jsize len, jobject pd, const char *source, - jboolean verify); - /* * Reflection support functions */ From 90cb525183f67ded81f8bab489eebc2e833b2477 Mon Sep 17 00:00:00 2001 From: Omair Majid Date: Thu, 19 Nov 2015 12:52:41 -0500 Subject: [PATCH 130/260] 8142898: Prefer isFile()/isDirectory() over exists() in SoftSynthesizer Reviewed-by: serb --- .../com/sun/media/sound/SoftSynthesizer.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java index 3b12b811fb7..ef2182d6c9e 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java @@ -638,7 +638,7 @@ public final class SoftSynthesizer implements AudioSynthesizer, File javahome = new File(System.getProperties() .getProperty("java.home")); File libaudio = new File(new File(javahome, "lib"), "audio"); - if (libaudio.exists()) { + if (libaudio.isDirectory()) { File foundfile = null; File[] files = libaudio.listFiles(); if (files != null) { @@ -686,9 +686,9 @@ public final class SoftSynthesizer implements AudioSynthesizer, * Look for a default.sf2 */ for (File systemSoundFontDir : systemSoundFontsDir) { - if (systemSoundFontDir.exists()) { + if (systemSoundFontDir.isDirectory()) { File defaultSoundFont = new File(systemSoundFontDir, "default.sf2"); - if (defaultSoundFont.exists()) { + if (defaultSoundFont.isFile()) { try { return new FileInputStream(defaultSoundFont); } catch (IOException e) { @@ -708,7 +708,7 @@ public final class SoftSynthesizer implements AudioSynthesizer, .startsWith("Windows")) { File gm_dls = new File(System.getenv("SystemRoot") + "\\system32\\drivers\\gm.dls"); - if (gm_dls.exists()) { + if (gm_dls.isFile()) { try { return new FileInputStream(gm_dls); } catch (IOException e) { @@ -728,7 +728,7 @@ public final class SoftSynthesizer implements AudioSynthesizer, ".gervill"); File emg_soundbank_file = new File(userhome, "soundbank-emg.sf2"); - if (emg_soundbank_file.exists()) { + if (emg_soundbank_file.isFile()) { try { return new FileInputStream(emg_soundbank_file); } catch (IOException e) { @@ -773,12 +773,14 @@ public final class SoftSynthesizer implements AudioSynthesizer, try { File userhome = new File(System .getProperty("user.home"), ".gervill"); - if (!userhome.exists()) { - userhome.mkdirs(); + if (!userhome.isDirectory()) { + if (!userhome.mkdirs()) { + return null; + } } File emg_soundbank_file = new File( userhome, "soundbank-emg.sf2"); - if (emg_soundbank_file.exists()) { + if (emg_soundbank_file.isFile()) { return null; } return new FileOutputStream(emg_soundbank_file); From cf63d3026e3af5637f898c09dbb7bac91f9fc580 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Fri, 20 Nov 2015 13:02:06 +0100 Subject: [PATCH 131/260] 8043138: Attach API should not require jvmstat rmi protocol Reviewed-by: alanb, mchung, erikj, ihse --- make/Images.gmk | 4 ++-- modules.xml | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/make/Images.gmk b/make/Images.gmk index 04d526f2be6..6bd48bf2502 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -44,8 +44,8 @@ MAIN_MODULES += java.se java.smartcardio jdk.httpserver jdk.sctp \ jdk.vm.ci jdk.management # providers -PROVIDER_MODULES += jdk.charsets jdk.crypto.ec jdk.crypto.pkcs11 jdk.jvmstat jdk.localedata \ - jdk.naming.dns jdk.naming.rmi jdk.zipfs +PROVIDER_MODULES += jdk.charsets jdk.crypto.ec jdk.crypto.pkcs11 jdk.jvmstat jdk.jvmstat.rmi \ + jdk.localedata jdk.naming.dns jdk.naming.rmi jdk.zipfs # tools TOOLS_MODULES += jdk.attach jdk.compiler jdk.dev \ diff --git a/modules.xml b/modules.xml index 68a9de25848..737cbd28fd8 100644 --- a/modules.xml +++ b/modules.xml @@ -1810,16 +1810,31 @@ jdk.jvmstat java.base - java.rmi sun.jvmstat.monitor jdk.attach jdk.jcmd jdk.jconsole + jdk.jvmstat.rmi sun.jvmstat.monitor.event jdk.jcmd + jdk.jvmstat.rmi + + + sun.jvmstat.perfdata.monitor + jdk.jvmstat.rmi + + + + jdk.jvmstat.rmi + java.base + java.rmi + jdk.jvmstat + + sun.jvmstat.monitor.remote + java.rmi From dda3e3761d56d9d205fe55c37c476889ba898e67 Mon Sep 17 00:00:00 2001 From: Rajeev Chamyal Date: Fri, 20 Nov 2015 16:44:33 +0400 Subject: [PATCH 132/260] 8037575: JFrame on Windows doesn't animate when setting ICONIFIED state Reviewed-by: azvegint, alexsch --- .../native/libawt/windows/awt_Frame.cpp | 2 +- .../swing/JFrame/8037575/bug8037575.java | 263 ++++++++++++++++++ 2 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 jdk/test/javax/swing/JFrame/8037575/bug8037575.java diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp index 53f6a50149e..e9a4167a6e1 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp @@ -1372,7 +1372,7 @@ void AwtFrame::_SetState(void *param) } else { // zoom == iconify == FALSE wp.showCmd = focusable ? SW_RESTORE : SW_SHOWNOACTIVATE; } - + ::ShowWindow(hwnd, wp.showCmd); if (zoom && iconify) { wp.flags |= WPF_RESTORETOMAXIMIZED; } else { diff --git a/jdk/test/javax/swing/JFrame/8037575/bug8037575.java b/jdk/test/javax/swing/JFrame/8037575/bug8037575.java new file mode 100644 index 00000000000..cdb16962a18 --- /dev/null +++ b/jdk/test/javax/swing/JFrame/8037575/bug8037575.java @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test @bug 8037575 + * @summary JFrame doesn't animate when setting ICONIFIED state + * @requires (os.family == "windows") + * @run main/manual bug8037575 + */ +import java.awt.Frame; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; +import java.awt.*; +import java.awt.event.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.Timer; + +public class bug8037575 { + + private static boolean theTestPassed; + private static boolean testGeneratedInterrupt; + private static Thread mainThread; + private static int sleepTime = 30000; + private static int waitTime = 2000; + private final static JFrame frame = new JFrame("bug8037575"); + + private static void init() throws Exception { + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + String[] instructions + = { + "1) You see a dialog with buttons and text area.", + "2) Pressing Run button will start test. A new Frame will open automatically" + + " and minimize after 2 seconds.", + "3) Frame should minimize gradually with animation effect.", + "4) If frame disappers without animation then test " + + "failed otherwise passed.", + "5) Pressing Pass/Fail button will mark test as " + + "pass/fail and will shutdown JVM as well"}; + + Sysout.createDialogWithInstructions(instructions); + Sysout.printInstructions(instructions); + } + }); + } + + /** + * *************************************************** + * Standard Test Machinery Section DO NOT modify anything in this section -- + * it's a standard chunk of code which has all of the synchronisation + * necessary for the test harness. By keeping it the same in all tests, it + * is easier to read and understand someone else's test, as well as insuring + * that all tests behave correctly with the test harness. There is a section + * following this for test-defined classes + */ + public static void main(String args[]) throws InterruptedException { + + mainThread = Thread.currentThread(); + try { + init(); + } catch (Exception ex) { + Logger.getLogger(bug8037575.class.getName()).log(Level.SEVERE, null, ex); + } + try { + mainThread.sleep(sleepTime); + } catch (InterruptedException ex) { + Sysout.dispose(); + if (!theTestPassed && testGeneratedInterrupt) { + throw new RuntimeException("Test Failed"); + } + } + if (!testGeneratedInterrupt) { + Sysout.dispose(); + throw new RuntimeException("Test Failed"); + } + } + + public static synchronized void pass() { + theTestPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + public static synchronized void runTest() { + frame.setSize(800, 600); + frame.setVisible(true); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Timer timer = new Timer(waitTime, new AbstractAction() { + @Override + public void actionPerformed(ActionEvent ae) { + frame.setExtendedState(Frame.ICONIFIED); + frame.dispose(); + Sysout.println("Test completed please press/fail button"); + } + }); + timer.setRepeats(false); + timer.start(); + } + + public static synchronized void fail() { + theTestPassed = false; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } +} + +/** + * This is part of the standard test machinery. It creates a dialog (with the + * instructions), and is the interface for sending text messages to the user. To + * print the instructions, send an array of strings to Sysout.createDialog + * WithInstructions method. Put one line of instructions per array entry. To + * display a message for the tester to see, simply call Sysout.println with the + * string to be displayed. This mimics System.out.println but works within the + * test harness as well as standalone. + */ +class Sysout { + + private static TestDialog dialog; + private static JFrame frame; + + public static void createDialogWithInstructions(String[] instructions) { + frame = new JFrame(); + dialog = new TestDialog(frame, "Instructions"); + dialog.printInstructions(instructions); + dialog.setVisible(true); + println("Any messages for the tester will display here."); + } + + public static void printInstructions(String[] instructions) { + dialog.printInstructions(instructions); + } + + public static void println(String messageIn) { + dialog.displayMessage(messageIn); + } + + public static void dispose() { + Sysout.println("Shutting down the Java process.."); + frame.dispose(); + dialog.dispose(); + } +} + +/** + * This is part of the standard test machinery. It provides a place for the test + * instructions to be displayed, and a place for interactive messages to the + * user to be displayed. To have the test instructions displayed, see Sysout. To + * have a message to the user be displayed, see Sysout. Do not call anything in + * this dialog directly. + */ +class TestDialog extends JDialog { + + private TextArea instructionsText; + private TextArea messageText; + private int maxStringLength = 80; + private Panel buttonP = new Panel(); + private JButton run = new JButton("Run"); + private JButton passB = new JButton("Pass"); + private JButton failB = new JButton("Fail"); + + public TestDialog(JFrame frame, String name) { + super(frame, name); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea("", 15, maxStringLength, scrollBoth); + add("North", instructionsText); + + messageText = new TextArea("", 5, maxStringLength, scrollBoth); + add("Center", messageText); + + buttonP.add("East", run); + buttonP.add("East", passB); + buttonP.add("West", failB); + passB.setEnabled(false); + failB.setEnabled(false); + add("South", buttonP); + + run.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent ae) { + bug8037575.runTest(); + passB.setEnabled(true); + failB.setEnabled(true); + } + }); + + passB.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent ae) { + bug8037575.pass(); + } + }); + + failB.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent ae) { + bug8037575.fail(); + } + }); + pack(); + + setVisible(true); + } + + public void printInstructions(String[] instructions) { + instructionsText.setText(""); + String printStr, remainingStr; + for (String instruction : instructions) { + remainingStr = instruction; + while (remainingStr.length() > 0) { + if (remainingStr.length() >= maxStringLength) { + int posOfSpace = remainingStr. + lastIndexOf(' ', maxStringLength - 1); + + if (posOfSpace <= 0) { + posOfSpace = maxStringLength - 1; + } + + printStr = remainingStr.substring(0, posOfSpace + 1); + remainingStr = remainingStr.substring(posOfSpace + 1); + } else { + printStr = remainingStr; + remainingStr = ""; + } + instructionsText.append(printStr + "\n"); + } + } + + } + + public void displayMessage(String messageIn) { + messageText.append(messageIn + "\n"); + } +} \ No newline at end of file From 90c71390a7e0b8682e94f1c021d14e6b2823c583 Mon Sep 17 00:00:00 2001 From: Peter Brunet Date: Fri, 20 Nov 2015 17:54:58 -0600 Subject: [PATCH 133/260] 8056925: Add jaccessinspector and jaccesswalker to the bin directory Add jaccessinspector, jaccesswalker to jdk.accessibility module; update launcher in make Reviewed-by: erikj, van, prr --- .../launcher/Launcher-jdk.accessibility.gmk | 71 + .../native/common/AccessBridgeDebug.cpp | 35 + .../windows/native/common/AccessBridgeDebug.h | 1 + .../jaccessinspector/MessageHistory.cpp | 155 ++ .../native/jaccessinspector/MessageHistory.h | 55 + .../jaccessinspector/jaccessinspector.cpp | 1716 +++++++++++++++++ .../jaccessinspector/jaccessinspector.h | 117 ++ .../jaccessinspectorResource.h | 88 + .../jaccessinspectorWindow.rc | 249 +++ .../native/jaccesswalker/jaccesswalker.cpp | 648 +++++++ .../native/jaccesswalker/jaccesswalker.h | 110 ++ .../jaccesswalker/jaccesswalkerResource.h | 46 + .../jaccesswalker/jaccesswalkerWindow.rc | 182 ++ .../AccessBridgeJavaEntryPoints.cpp | 13 +- .../windows/native/toolscommon/AccessInfo.cpp | 948 +++++++++ .../windows/native/toolscommon/AccessInfo.h | 56 + 16 files changed, 4486 insertions(+), 4 deletions(-) create mode 100644 jdk/src/jdk.accessibility/windows/native/jaccessinspector/MessageHistory.cpp create mode 100644 jdk/src/jdk.accessibility/windows/native/jaccessinspector/MessageHistory.h create mode 100644 jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.cpp create mode 100644 jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.h create mode 100644 jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspectorResource.h create mode 100644 jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspectorWindow.rc create mode 100644 jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp create mode 100644 jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.h create mode 100644 jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalkerResource.h create mode 100644 jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalkerWindow.rc create mode 100644 jdk/src/jdk.accessibility/windows/native/toolscommon/AccessInfo.cpp create mode 100644 jdk/src/jdk.accessibility/windows/native/toolscommon/AccessInfo.h diff --git a/jdk/make/launcher/Launcher-jdk.accessibility.gmk b/jdk/make/launcher/Launcher-jdk.accessibility.gmk index 33fbfc27a9c..0fa486377f1 100644 --- a/jdk/make/launcher/Launcher-jdk.accessibility.gmk +++ b/jdk/make/launcher/Launcher-jdk.accessibility.gmk @@ -56,6 +56,77 @@ ifeq ($(OPENJDK_TARGET_OS), windows) )) TARGETS += $(BUILD_JABSWITCH) + +################################################################################ +# jaccessinspector + + TOPDIR := $(JDK_TOPDIR)/src/jdk.accessibility/windows/native + TOOLS_CFLAGS := $(addprefix -I, \ + $(TOPDIR)/include/bridge \ + $(TOPDIR)/common \ + $(TOPDIR)/toolscommon) + + define SetupInspector + # Parameter 1 File name suffix + # Parameter 2 ACCESSBRIDGE_ARCH_ -D suffix + + $$(eval $$(call SetupNativeCompilation, BUILD_JACCESSINSPECTOR$1, \ + SRC := $(TOPDIR)/jaccessinspector $(TOPDIR)/common \ + $(TOPDIR)/toolscommon $(TOPDIR)/include/bridge, \ + CFLAGS := $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 /EHsc, \ + LDFLAGS := $$(LDFLAGS_JDKEXE) /STACK:655360 Advapi32.lib User32.lib, \ + OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/jdk.accessibility/jaccessinspector$1, \ + OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/jdk.accessibility, \ + PROGRAM := jaccessinspector$1, \ + DEBUG_SYMBOLS := true, \ + VERSIONINFO_RESOURCE := $(TOPDIR)/jaccessinspector/jaccessinspectorWindow.rc, \ + RC_FLAGS := $$(RC_FLAGS) \ + -D "JDK_FNAME=jaccessinspector$1.exe" \ + -D "JDK_INTERNAL_NAME=jaccessinspector$1" \ + -D "JDK_FTYPE=0x01L", \ + )) + + TARGETS += $$(BUILD_JACCESSINSPECTOR$1) + + endef + +################################################################################ +# jaccesswalker + + define SetupWalker + # Parameter 1 File name suffix + # Parameter 2 ACCESSBRIDGE_ARCH_ -D suffix + + $$(eval $$(call SetupNativeCompilation,BUILD_JACCESSWALKER$1, \ + SRC := $(TOPDIR)/jaccesswalker $(TOPDIR)/common \ + $(TOPDIR)/toolscommon $(TOPDIR)/include/bridge, \ + CFLAGS :== $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 /EHsc, \ + LDFLAGS := $$(LDFLAGS_JDKEXE) /STACK:655360 Advapi32.lib Comctl32.lib Gdi32.lib User32.lib, \ + OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/jdk.accessibility/jaccesswalker$1, \ + OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/jdk.accessibility, \ + PROGRAM := jaccesswalker$1, \ + DEBUG_SYMBOLS := true, \ + VERSIONINFO_RESOURCE := $(TOPDIR)/jaccesswalker/jaccesswalkerWindow.rc, \ + RC_FLAGS := $$(RC_FLAGS) \ + -D "JDK_FNAME=jaccesswalker$1.exe" \ + -D "JDK_INTERNAL_NAME=jaccesswalker$1" \ + -D "JDK_FTYPE=0x01L", \ + )) + + TARGETS += $$(BUILD_JACCESSWALKER$1) + + endef + + ifeq ($(OPENJDK_TARGET_CPU_BITS), 32) + $(eval $(call SetupInspector,-32,32)) + $(eval $(call SetupWalker,-32,32)) + $(eval $(call SetupInspector,,LEGACY)) + $(eval $(call SetupWalker,,LEGACY)) + else + $(eval $(call SetupInspector,,64)) + $(eval $(call SetupWalker,,64)) + endif + endif ################################################################################ diff --git a/jdk/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.cpp b/jdk/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.cpp index c9decea3aa4..f41125d8c08 100644 --- a/jdk/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.cpp +++ b/jdk/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.cpp @@ -36,6 +36,41 @@ extern "C" { #endif +/** + * print a GetLastError message + */ +char *printError(char *msg) { + LPVOID lpMsgBuf = NULL; + static char retbuf[256]; + + if (msg != NULL) { + strncpy((char *)retbuf, msg, sizeof(retbuf)); + // if msg text is >= 256 ensure buffer is null terminated + retbuf[255] = '\0'; + } + if (!FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL )) + { + PrintDebugString(" %s: FormatMessage failed", msg); + } else { + PrintDebugString(" %s: %s", msg, (char *)lpMsgBuf); + } + if (lpMsgBuf != NULL) { + strncat((char *)retbuf, ": ", sizeof(retbuf) - strlen(retbuf) - 1); + strncat((char *)retbuf, (char *)lpMsgBuf, sizeof(retbuf) - strlen(retbuf) - 1); + } + return (char *)retbuf; +} + + /** * Send debugging info to the appropriate place */ diff --git a/jdk/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.h b/jdk/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.h index b25fb79b691..1ac7426d6e0 100644 --- a/jdk/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.h +++ b/jdk/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.h @@ -49,6 +49,7 @@ extern "C" { #endif + char *printError(char *msg); void PrintDebugString(char *msg, ...); void PrintJavaDebugString(char *msg, ...); void wPrintJavaDebugString(wchar_t *msg, ...); diff --git a/jdk/src/jdk.accessibility/windows/native/jaccessinspector/MessageHistory.cpp b/jdk/src/jdk.accessibility/windows/native/jaccessinspector/MessageHistory.cpp new file mode 100644 index 00000000000..0975d19bca1 --- /dev/null +++ b/jdk/src/jdk.accessibility/windows/native/jaccessinspector/MessageHistory.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 // includes basic windows functionality +#include +#include "MessageHistory.h" + +size_t MessageHistory::sm_MaxMessages = 1000; + +void MessageHistory::AddMessage(const char * message) { + if ( ( NULL == message ) || ( 0 == message [0] ) ) { + return; + } + + if ( m_Messages.size() >= sm_MaxMessages ) { + // Remove the oldest message + m_Messages.pop_front(); + } + + m_Messages.push_back(std::string (message) ); + m_CurrentPosition = m_Messages.end(); + -- m_CurrentPosition; +} + +const char * MessageHistory::GetFirstMessage() { + if ( m_Messages.empty() ) { + return ""; + } + + m_CurrentPosition = m_Messages.begin(); + return (*m_CurrentPosition).c_str(); +} + +const char * MessageHistory::GetPreviousMessage() { + if ( m_Messages.empty() ) { + return ""; + } + + if ( m_CurrentPosition != m_Messages.begin() ) { + -- m_CurrentPosition; + } + + return (*m_CurrentPosition).c_str(); +} + +const char * MessageHistory::GetNextMessage() { + if ( m_Messages.empty() ) { + return ""; + } + + ++ m_CurrentPosition; + if ( m_CurrentPosition == m_Messages.end() ) { + -- m_CurrentPosition; + } + + return (*m_CurrentPosition).c_str(); +} + +const char * MessageHistory::GetLastMessage() +{ + if ( m_Messages.empty() ) { + return ""; + } + + m_CurrentPosition = m_Messages.end(); + -- m_CurrentPosition; + return (*m_CurrentPosition).c_str(); +} + +BOOL MessageHistory::IsFirstMessage() { + if ( m_Messages.empty() ) { + return FALSE; + } + if ( m_CurrentPosition == m_Messages.begin() ) { + return TRUE; + } + return FALSE; +} + +BOOL MessageHistory::IsLastMessage() { + if ( m_Messages.empty() ) { + return FALSE; + } + stringlist::const_iterator itTest = m_Messages.end(); + -- itTest; + if ( itTest == m_CurrentPosition ) { + return TRUE; + } + return FALSE; +} + +size_t MessageHistory::GetMessageCount() { + size_t ret_val = m_Messages.size(); + return ret_val; +} + +const char * MessageHistory::GetCurrentMessage() { + if ( m_Messages.empty() ) { + return ""; + } + + return (*m_CurrentPosition).c_str(); +} + +const char * MessageHistory::GetMessage(const size_t messageIndex) { + if ( m_Messages.empty() ) { + return ""; + } + + if ( messageIndex >= m_Messages.size() ) { + return ""; + } + + stringlist::const_iterator it = m_Messages.begin(); + std::advance(it, messageIndex); + m_CurrentPosition = it; + + return (*it).c_str(); +} + +size_t MessageHistory::GetCurrentMessageIndex() { + if ( m_Messages.empty() ) { + return 0; + } + + stringlist::const_iterator itBegin = m_Messages.begin(); + size_t ret_val = std::distance(itBegin, m_CurrentPosition); + return ret_val; +} + +void MessageHistory::clear() { + m_Messages.clear(); +} diff --git a/jdk/src/jdk.accessibility/windows/native/jaccessinspector/MessageHistory.h b/jdk/src/jdk.accessibility/windows/native/jaccessinspector/MessageHistory.h new file mode 100644 index 00000000000..8fda329df58 --- /dev/null +++ b/jdk/src/jdk.accessibility/windows/native/jaccessinspector/MessageHistory.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +#ifndef __MessageHistory_H__ +#define __MessageHistory_H__ + +#include +#include + +class MessageHistory +{ +public: + static size_t sm_MaxMessages; +private: + typedef std::list< std::string > stringlist; + stringlist m_Messages; + stringlist::const_iterator m_CurrentPosition; + +public: + void AddMessage(const char * message); + const char * GetFirstMessage(); + const char * GetPreviousMessage(); + const char * GetNextMessage(); + const char * GetLastMessage(); + const char * GetCurrentMessage(); + const char * GetMessage(const size_t messageIndex); + size_t GetCurrentMessageIndex(); + BOOL IsFirstMessage(); + BOOL IsLastMessage(); + size_t GetMessageCount(); + void clear(); +}; +#endif diff --git a/jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.cpp b/jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.cpp new file mode 100644 index 00000000000..7798c64e438 --- /dev/null +++ b/jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.cpp @@ -0,0 +1,1716 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +/* + * A sample Assistive Technology which queries the JavaVM to get the Java + * Accessibility information available for a Java UI object, using the Java + * Access Bridge. + */ + +#include // includes basic windows functionality +#include + +#include "jaccessinspectorResource.h" +#include "AccessBridgeCalls.h" +#include "AccessBridgeCallbacks.h" + +#include +#include +#include + +#include "jaccessinspector.h" +#include "AccessInfo.h" +#include "MessageHistory.h" + +#define TIMER_ID 1 +#define DISPLAY_INFO_MESSAGE WM_USER+1 +#define DISPLAY_HWND_INFO_MESSAGE WM_USER+2 + +HWND theDialogWindow; +HWND theGoToDialogWindow; +HINSTANCE theInstance; +BOOL theAccessBridgeLoadedFlag; + +HHOOK prevKbdHook; +HHOOK prevMouseHook; + +BOOL updateMouse; +BOOL updateF1; +BOOL updateF2; + +BOOL trackMouse; +BOOL trackMouseExited; +BOOL trackMouseClicked; +BOOL trackMousePressed; +BOOL trackMouseReleased; + +BOOL trackFocus; +BOOL trackFocusLost; +BOOL trackCaret; +BOOL trackShutdown; + +BOOL trackMenuSelected; +BOOL trackMenuDeselected; +BOOL trackMenuCanceled; + +BOOL trackPopupVisible; +BOOL trackPopupInvisible; +BOOL trackPopupCanceled; + +//BOOL trackPropertyChange; + +BOOL trackPropertyNameChange; +BOOL trackPropertyDescriptionChange; +BOOL trackPropertyStateChange; +BOOL trackPropertyValueChange; +BOOL trackPropertySelectionChange; +BOOL trackPropertyTextChange; +BOOL trackPropertyCaretChange; +BOOL trackPropertyVisibleDataChange; +BOOL trackPropertyChildChange; +BOOL trackPropertyActiveDescendentChange; +BOOL trackPropertyTableModelChange; + + +FILE *logfile = NULL; + +MessageHistory g_MessageHistory; + +/** + * WinMain + * + */ +int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd) { + MSG msg; + + g_LogStringCallback = AddToMessageHistory; + theInstance = hInst; + theDialogWindow = NULL; + theGoToDialogWindow = NULL; + + updateF1 = FALSE; + updateF2 = FALSE; + updateMouse = FALSE; + + theAccessBridgeLoadedFlag = FALSE; + + ReadActiveEventOptionsFromRegistry (); + + if (InitWindow(hInst)) { + if (initializeAccessBridge() == TRUE) { + theAccessBridgeLoadedFlag = TRUE; + ApplyEventOptions(theDialogWindow); + EnableMessageNavButtons(); + HACCEL hAccel = + ::LoadAccelerators (theInstance, MAKEINTRESOURCE(IDR_ACCELERATOR)); + + while (GetMessage(&msg, NULL, 0, 0)) { + if ( FALSE == TranslateAccelerator(theDialogWindow, hAccel, &msg) ) { + if ( ( ( NULL == theDialogWindow ) || + ( FALSE == IsDialogMessage(theDialogWindow, &msg) ) ) && + ( ( NULL == theGoToDialogWindow ) || + ( FALSE == IsDialogMessage(theGoToDialogWindow, &msg) ) ) ) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } + if (theAccessBridgeLoadedFlag == TRUE) { + shutdownAccessBridge(); + } + SaveActiveEventOptionsToRegistry (); + } + } + return(0); +} + +char szAppName [] = "JACCESSINSPECTORWINDOW"; + +/** + * Real(tm) MS-Windows window initialization + * + */ +BOOL InitWindow (HANDLE hInstance) { + theDialogWindow = CreateDialog((struct HINSTANCE__ *)hInstance, + szAppName, + NULL, + jaccessinspectorDialogProc); + + // If window could not be created, return "failure". + if (!theDialogWindow) + return FALSE; + + if (logfile == null) { + logfile = fopen(JACCESSINSPECTOR_LOG, "w"); // overwrite existing log file + logString(logfile, "Starting jaccessinspector.exe %s\n", getTimeAndDate()); + } + + // Make the window visible, update its client area, & return "success". + SetWindowText(theDialogWindow, "jaccessinspector"); + ShowWindow(theDialogWindow, SW_SHOWNORMAL); + UpdateWindow(theDialogWindow); + + return TRUE; +} + +/** + * Display Accessible information about the object under the mouse + */ +void displayAccessibleInfo(long vmID, AccessibleContext ac, int x, int y) { + char buffer[HUGE_BUFSIZE]; + + getAccessibleInfo(vmID, ac, x, y, buffer, (int)(sizeof(buffer))); + displayAndLog(theDialogWindow, cjaccessinspectorText, logfile, (char *)buffer); +} + +/** + * Display Java event info + */ +void displayJavaEvent(long vmID, AccessibleContext ac, char *announcement) { + char buffer[HUGE_BUFSIZE]; + char *bufOffset; + + strncpy(buffer, announcement, sizeof(buffer)); + + bufOffset = (char *)(buffer + strlen(buffer)); + getAccessibleInfo( vmID, ac, -1, -1, bufOffset, + (int)(sizeof(buffer) - strlen(buffer)) ); + displayAndLog(theDialogWindow, cjaccessinspectorText, logfile, (char *)buffer); +} + + +/** + * Display Accessible propertyChange event info + */ +void displayAccessiblePropertyChange(long vmID, AccessibleContext ac, + char *announcement) { + char buffer[HUGE_BUFSIZE]; + char *bufOffset; + + strncpy(buffer, announcement, sizeof(buffer)); + + bufOffset = (char *) (buffer + strlen(buffer)); + getAccessibleInfo( vmID, ac, -1, -1, bufOffset, + (int)(sizeof(buffer) - strlen(buffer)) ); + displayAndLog(theDialogWindow, cjaccessinspectorText, logfile, (char *)buffer); +} + + +/** + * Update display under mouse when it moves + */ +void echoMouseObject() { + long vmID; + AccessibleContext acParent; + AccessibleContext ac; + POINT p; + HWND hwnd; + RECT windowRect; + + GetCursorPos(&p); + hwnd = WindowFromPoint(p); + if (GetAccessibleContextFromHWND(hwnd, &vmID, &acParent)) { + GetWindowRect(hwnd, &windowRect); + // send the point in global coordinates; Java will handle it! + if (GetAccessibleContextAt(vmID, acParent, (jint) p.x, (jint) p.y, &ac)) { + displayAccessibleInfo(vmID, ac, p.x, p.y); // can handle null + ReleaseJavaObject(vmID, ac); + } + } +} + + +/** + * Update display under HWND the mouse is in + */ +void echoMouseHWNDObject() { + long vmID; + AccessibleContext ac; + POINT p; + HWND hwnd; + + GetCursorPos(&p); + hwnd = WindowFromPoint(p); + + if (GetAccessibleContextFromHWND(hwnd, &vmID, &ac)) { + displayAccessibleInfo(vmID, ac, 0, 0); // can handle null + ReleaseJavaObject(vmID, ac); + } +} + +/** + * Display Accessible information about the object that has focus in + * the topmost Java HWND + * + */ +void displayFocusedObject() { + HWND hWnd; + long vmID; + AccessibleContext ac; + + hWnd = GetTopWindow(NULL); + while (hWnd != NULL) { + if (IsJavaWindow(hWnd)) { + if (GetAccessibleContextWithFocus(hWnd, &vmID, &ac) == TRUE) { + displayAccessibleInfo(vmID, ac, 0, 0); + ReleaseJavaObject(vmID, ac); + } + return; + } else { + hWnd = GetNextWindow(hWnd, GW_HWNDNEXT); + } + } +} + +/* + * Handle notification of the Java application shutting down + */ +void HandleJavaShutdown(long vmID) { + char s[1024]; + wsprintf(s, "Java VM 0x%X terminated\r\n\r\n", vmID); + + displayJavaEvent(vmID, null, s); // intentially passing null AccessibleContext + displayAndLog(theDialogWindow, cjaccessinspectorText, logfile, (char *)s); +} + +/** + * Handle a FocusGained event + */ +void HandleJavaFocusGained(long vmID, FocusEvent event, AccessibleContext ac) { + + char s[1024]; + wsprintf(s, "FocusGained\r\n\r\n"); + + if (ac != (AccessibleContext) 0) { + displayJavaEvent(vmID, ac, s); + } + + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a FocusLost event + */ +void HandleJavaFocusLost(long vmID, FocusEvent event, AccessibleContext ac) { + + // NOTE: calling GetAccessibleContextWithFocus() after a FocusLost event + // would result in a null AccessibleContext being returned, since + // at that point, no object has the focus. If the topmost window + // does not belong to a JavaVM, then no component within a JavaVM + // will have the focus (and again, GetAccessibleContextWithFocus() + // will return a null AccessibleContext). You should always get + // a FocusLost event when a window not belonging to a JavaVM becomes + // topmost. + + char s[1024]; + wsprintf(s, "FocusLost\r\n\r\n"); + + if (ac != (AccessibleContext) 0) { + displayJavaEvent(vmID, ac, s); + } + /* + if (ac != (AccessibleContext) 0) { + displayAccessibleInfo(vmID, ac, 0, 0); + } + */ + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a CaretUpdate event + */ +void HandleJavaCaretUpdate(long vmID, CaretEvent event, AccessibleContext ac) { + if (ac != (AccessibleContext) 0) { + displayAccessibleInfo(vmID, ac, 0, 0); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a MouseClicked event + */ +void HandleMouseClicked(long vmID, MouseEvent event, AccessibleContext ac) { + if (ac != (AccessibleContext) 0) { + displayAccessibleInfo(vmID, ac, 0, 0); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a MouseEntered event + */ +void HandleMouseEntered(long vmID, MouseEvent event, AccessibleContext ac) { + if (ac != (AccessibleContext) 0) { + displayAccessibleInfo(vmID, ac, 0, 0); + } + + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a MouseExited event + */ +void HandleMouseExited(long vmID, MouseEvent event, AccessibleContext ac) { + if (ac != (AccessibleContext) 0) { + displayAccessibleInfo(vmID, ac, 0, 0); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a MousePressed event + */ +void HandleMousePressed(long vmID, MouseEvent event, AccessibleContext ac) { + if (ac != (AccessibleContext) 0) { + displayAccessibleInfo(vmID, ac, 0, 0); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a MouseReleased event + */ +void HandleMouseReleased(long vmID, MouseEvent event, AccessibleContext ac) { + if (ac != (AccessibleContext) 0) { + displayAccessibleInfo(vmID, ac, 0, 0); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a MenuCanceled event + */ +void HandleMenuCanceled(long vmID, MenuEvent event, AccessibleContext ac) { + if (ac != (AccessibleContext) 0) { + displayAccessibleInfo(vmID, ac, 0, 0); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a MenuDeselected event + */ +void HandleMenuDeselected(long vmID, MenuEvent event, AccessibleContext ac) { + if (ac != (AccessibleContext) 0) { + displayAccessibleInfo(vmID, ac, 0, 0); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a MenuSelected event + */ +void HandleMenuSelected(long vmID, MenuEvent event, AccessibleContext ac) { + if (ac != (AccessibleContext) 0) { + displayAccessibleInfo(vmID, ac, 0, 0); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a PopupMenuCanceled event + */ +void HandlePopupMenuCanceled(long vmID, MenuEvent event, AccessibleContext ac) { + if (ac != (AccessibleContext) 0) { + displayAccessibleInfo(vmID, ac, 0, 0); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a PopupMenuWillBecomeInvisible event + */ +void HandlePopupMenuWillBecomeInvisible(long vmID, MenuEvent event, AccessibleContext ac) { + if (ac != (AccessibleContext) 0) { + displayAccessibleInfo(vmID, ac, 0, 0); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a PopupMenuWillBecomeVisible event + */ +void HandlePopupMenuWillBecomeVisible(long vmID, MenuEvent event, AccessibleContext ac) { + if (ac != (AccessibleContext) 0) { + displayAccessibleInfo(vmID, ac, 0, 0); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + + + + +/** + * Handle a HandlePropertyNameChange event + */ +void HandlePropertyNameChange(long vmID, PropertyChangeEvent event, AccessibleContext ac, + wchar_t *oldName, wchar_t *newName) { + char s[1024]; + wsprintf(s, "Name changed event: old = %ls; new = %ls\r\n\r\n", oldName, newName); + + if (ac != (AccessibleContext) 0) { + displayAccessiblePropertyChange(vmID, ac, s); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a HandlePropertyDescriptionChange event + */ +void HandlePropertyDescriptionChange( long vmID, + PropertyChangeEvent event, + AccessibleContext ac, + wchar_t *oldDescription, + wchar_t *newDescription ) { + char s[1024]; + wsprintf( s, "Description changed event: old = %ls; new = %ls\r\n\r\n", + oldDescription, newDescription ); + + if (ac != (AccessibleContext) 0) { + displayAccessiblePropertyChange(vmID, ac, s); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a HandlePropertyStateChange event + */ +void HandlePropertyStateChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac, + wchar_t *oldState, wchar_t *newState ) { + char s[1024]; + wsprintf( s, "State changed event: old = %ls; new = %ls\r\n\r\n", + oldState, newState ); + + if (ac != (AccessibleContext) 0) { + displayAccessiblePropertyChange(vmID, ac, s); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a HandlePropertyValueChange event + */ +void HandlePropertyValueChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac, + wchar_t *oldValue, wchar_t *newValue ) { + char s[1024]; + wsprintf( s, "Value changed event: old = %ls; new = %ls\r\n\r\n", + oldValue, newValue ); + + if (ac != (AccessibleContext) 0) { + displayAccessiblePropertyChange(vmID, ac, s); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a HandlePropertySelectionChange event + */ +void HandlePropertySelectionChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac ) { + if (ac != (AccessibleContext) 0) { + displayAccessiblePropertyChange( vmID, ac, + "Selection changed event\r\n\r\n" ); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a HandlePropertyTextChange event + */ +void HandlePropertyTextChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac ) { + if (ac != (AccessibleContext) 0) { + displayAccessiblePropertyChange(vmID, ac, "Text changed event\r\n\r\n"); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a HandlePropertyCaretChange event + */ +void HandlePropertyCaretChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac, + int oldPosition, int newPosition ) { + char s[1024]; + + wsprintf( s, "Caret changed event: oldPosition = %d; newPosition = %d\r\n\r\n", + oldPosition, newPosition ); + + if (ac != (AccessibleContext) 0) { + displayAccessiblePropertyChange(vmID, ac, s); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a HandlePropertyVisibleDataChange event + */ +void HandlePropertyVisibleDataChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac ) { + if (ac != (AccessibleContext) 0) { + displayAccessiblePropertyChange( vmID, ac, + "VisibleData changed event\r\n\r\n" ); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + +/** + * Handle a HandlePropertyChildChange event + */ +void HandlePropertyChildChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac, + JOBJECT64 oldChild, JOBJECT64 newChild ) { + char buffer[HUGE_BUFSIZE]; + char *bufOffset; + + sprintf( buffer, + "Child property changed event:\r\n=======================\r\n\r\n" ); + + if (oldChild != 0) { + strncat(buffer, "Old Accessible Child info:\r\n\r\n", sizeof(buffer)); + bufOffset = (char *) (buffer + strlen(buffer)); + getAccessibleInfo( vmID, oldChild, 0, 0, bufOffset, + (int)(sizeof(buffer) - strlen(buffer)) ); + strncat(buffer, "\r\n\r\n", sizeof(buffer)); + } + + if (newChild != 0) { + strncat(buffer, "New Accessible Child info:\r\n\r\n", sizeof(buffer)); + bufOffset = (char *) (buffer + strlen(buffer)); + getAccessibleInfo( vmID, newChild, 0, 0, bufOffset, + (int)(sizeof(buffer) - strlen(buffer)) ); + strncat(buffer, "\r\n\r\n", sizeof(buffer)); + } + + if (ac != (AccessibleContext) 0) { + displayAccessiblePropertyChange(vmID, ac, buffer); + } + + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, oldChild); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, newChild); // must always release, to stave off memory leaks +} + +/** + * Handle a HandlePropertyActiveDescendentChange event + */ +void HandlePropertyActiveDescendentChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac, + JOBJECT64 oldActiveDescendent, + JOBJECT64 newActiveDescendent ) { + char buffer[HUGE_BUFSIZE]; + + sprintf( buffer, + "ActiveDescendent property changed event:\r\n=======================\r\n\r\n" ); + +#ifdef _notdef + char *bufOffset; + if (oldActiveDescendent != 0) { + strncat(buffer, "Old Accessible ActiveDescendent info:\r\n\r\n", sizeof(buffer)); + bufOffset = (char *) (buffer + strlen(buffer)); + getAccessibleInfo( vmID, oldActiveDescendent, 0, 0, bufOffset, + (int)(sizeof(buffer) - strlen(buffer)) ); + strncat(buffer, "\r\n\r\n", sizeof(buffer)); + } + + if (newActiveDescendent != 0) { + strncat( buffer, "New Accessible ActiveDescendent info:\r\n\r\n", + sizeof(buffer) ); + bufOffset = (char *) (buffer + strlen(buffer)); + getAccessibleInfo( vmID, newActiveDescendent, 0, 0, bufOffset, + (int)(sizeof(buffer) - strlen(buffer)) ); + strncat(buffer, "\r\n\r\n", sizeof(buffer)); + } +#endif _notdef + + if (newActiveDescendent != (AccessibleContext) 0) { + displayAccessiblePropertyChange(vmID, newActiveDescendent, buffer); + } + + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, oldActiveDescendent); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, newActiveDescendent); // must always release, to stave off memory leaks +} + + +/** + * Handle a HandlePropertyTableModelChange event + */ +void HandlePropertyTableModelChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac, + wchar_t *oldValue, wchar_t *newValue ) { + + char s[1024]; + wsprintf( s, "Table Model Change: old = %ls; new = %ls\r\n\r\n", + oldValue, newValue ); + + if (ac != (AccessibleContext) 0) { + displayAccessiblePropertyChange(vmID, ac, s); + } + ReleaseJavaObject(vmID, ac); // must always release, to stave off memory leaks + ReleaseJavaObject(vmID, event); // must always release, to stave off memory leaks +} + + + +#define DOWN_UP_FLAG 1<<31 + +void CALLBACK TimerProc(HWND hWnd, UINT uTimerMsg, UINT uTimerID, DWORD dwTime) { + // when mouse settles from movement + KillTimer(hWnd, uTimerID); + if (updateMouse == TRUE) { + PostMessage(theDialogWindow, DISPLAY_INFO_MESSAGE, 0, 0); + } +} + +LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) { + // on mouse-up of F1 + if (code < 0) { + CallNextHookEx(prevKbdHook, code, wParam, lParam); + } else if (wParam == VK_F1 && lParam & DOWN_UP_FLAG && updateF1) { + PostMessage(theDialogWindow, DISPLAY_INFO_MESSAGE, wParam, lParam); + } else if (wParam == VK_F2 && lParam & DOWN_UP_FLAG && updateF2) { + PostMessage(theDialogWindow, DISPLAY_HWND_INFO_MESSAGE, wParam, lParam); + } + return 0; +} + +LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam) { + // when mouse settles from movement + if (code < 0) { + CallNextHookEx(prevMouseHook, code, wParam, lParam); + } else { + // reset the timer every time the mouse moves + KillTimer(theDialogWindow, TIMER_ID); + SetTimer(theDialogWindow, TIMER_ID, 1000, (TIMERPROC)TimerProc); + } + return 0; +} + +void exitjaccessinspector(HWND hWnd) { + EndDialog(hWnd, TRUE); + PostQuitMessage (0); +} + +#define INSTALL_EVENT_LISTENER(toggleVal, setFP, handler) \ + if (toggleVal) { \ + setFP(handler); \ + } + +void reinstallEventListeners() { + INSTALL_EVENT_LISTENER(trackMouse, SetMouseEntered, HandleMouseEntered); + INSTALL_EVENT_LISTENER(trackMouseExited, SetMouseExited, HandleMouseExited); + INSTALL_EVENT_LISTENER(trackMouseClicked, SetMouseClicked, HandleMouseClicked); + INSTALL_EVENT_LISTENER(trackMousePressed, SetMousePressed, HandleMousePressed); + INSTALL_EVENT_LISTENER(trackMouseReleased, SetMouseReleased, HandleMouseReleased); + INSTALL_EVENT_LISTENER(trackShutdown, SetJavaShutdown, HandleJavaShutdown); + INSTALL_EVENT_LISTENER(trackFocus, SetFocusGained, HandleJavaFocusGained); + INSTALL_EVENT_LISTENER(trackFocusLost, SetFocusLost, HandleJavaFocusLost); + INSTALL_EVENT_LISTENER(trackCaret, SetCaretUpdate, HandleJavaCaretUpdate); + + INSTALL_EVENT_LISTENER(trackMenuSelected, SetMenuSelected, HandleMenuSelected); + INSTALL_EVENT_LISTENER(trackMenuDeselected, SetMenuDeselected, HandleMenuDeselected); + INSTALL_EVENT_LISTENER(trackMenuCanceled, SetMenuCanceled, HandleMenuCanceled); + + INSTALL_EVENT_LISTENER( trackPopupVisible, SetPopupMenuWillBecomeVisible, + HandlePopupMenuWillBecomeVisible ); + INSTALL_EVENT_LISTENER( trackPopupInvisible, SetPopupMenuWillBecomeInvisible, + HandlePopupMenuWillBecomeInvisible ); + INSTALL_EVENT_LISTENER( trackPopupCanceled, SetPopupMenuCanceled, + HandlePopupMenuCanceled ); + + INSTALL_EVENT_LISTENER( trackPropertyNameChange, SetPropertyNameChange, + HandlePropertyNameChange); + INSTALL_EVENT_LISTENER( trackPropertyDescriptionChange, + SetPropertyDescriptionChange, + HandlePropertyDescriptionChange ); + INSTALL_EVENT_LISTENER( trackPropertyStateChange, SetPropertyStateChange, + HandlePropertyStateChange ); + INSTALL_EVENT_LISTENER( trackPropertyValueChange, SetPropertyValueChange, + HandlePropertyValueChange ); + INSTALL_EVENT_LISTENER( trackPropertySelectionChange, + SetPropertySelectionChange, + HandlePropertySelectionChange ); + INSTALL_EVENT_LISTENER( trackPropertyTextChange, SetPropertyTextChange, + HandlePropertyTextChange ); + INSTALL_EVENT_LISTENER( trackPropertyCaretChange, SetPropertyCaretChange, + HandlePropertyCaretChange ); + INSTALL_EVENT_LISTENER( trackPropertyVisibleDataChange, + SetPropertyVisibleDataChange, + HandlePropertyVisibleDataChange ); + INSTALL_EVENT_LISTENER( trackPropertyChildChange, SetPropertyChildChange, + HandlePropertyChildChange ); + INSTALL_EVENT_LISTENER( trackPropertyActiveDescendentChange, + SetPropertyActiveDescendentChange, + HandlePropertyActiveDescendentChange ); + INSTALL_EVENT_LISTENER( trackPropertyTableModelChange, + SetPropertyTableModelChange, + HandlePropertyTableModelChange ); +} + + +#define TRACK_EVENT_TOGGLE(menuItem, toggleVal, setFP, handler) \ + case menuItem: \ + menu = GetMenu(hWnd); \ + if (toggleVal) { \ + toggleVal = FALSE; \ + CheckMenuItem(menu, menuItem, \ + MF_BYCOMMAND | MF_UNCHECKED); \ + setFP(NULL); \ + } else { \ + toggleVal = TRUE; \ + CheckMenuItem(menu, menuItem, \ + MF_BYCOMMAND | MF_CHECKED); \ + setFP(handler); \ + } \ + MaybeCheckMonitorTheSameEventsAsJAWS(menu); \ + MaybeCheckMonitorAllEvents(menu); \ + return TRUE + +INT_PTR CALLBACK jaccessinspectorDialogProc( HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam ) { + const int minWindowWidth = 540; + const int minWindowHeight = 300; + static int titleBarHeight = ::GetSystemMetrics(SM_CYSIZE); + static int menuBarHeight = ::GetSystemMetrics(SM_CYMENU); + static int borderHeight = ::GetSystemMetrics(SM_CYBORDER); + static int borderWidth = ::GetSystemMetrics(SM_CXBORDER); + static int verticalScrollBarWidth = ::GetSystemMetrics(SM_CXVSCROLL); + int command; + short width, height; + HWND dlgItem; + RECT dlgItemRect; + RECT dialogBoxRect; + LONG lT; + HMENU menu; + DWORD lastError = 0; + + switch (message) { + + case WM_CREATE: + return 0; + + case WM_INITDIALOG: + CheckMenuItem(GetMenu(hWnd), cAccessBridgeDLLLoaded, MF_BYCOMMAND | MF_CHECKED); + return TRUE; + + case WM_CLOSE: + exitjaccessinspector(hWnd); + return TRUE; + + case WM_SIZE: + width = LOWORD(lParam); + height = HIWORD(lParam); + dlgItem = GetDlgItem(theDialogWindow, cjaccessinspectorText); + ::GetWindowRect(dlgItem, &dlgItemRect); + ::GetWindowRect(theDialogWindow, &dialogBoxRect); + lT = dlgItemRect.top - dialogBoxRect.top - titleBarHeight - + menuBarHeight + (borderHeight * 4); + SetWindowPos( dlgItem, NULL, 0, 0, + width - (borderWidth * 2) - verticalScrollBarWidth, + height - lT, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + return FALSE; // let windows finish handling this + + case WM_GETMINMAXINFO: + { + LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam; + lpMMI->ptMinTrackSize.x = minWindowWidth; + lpMMI->ptMinTrackSize.y = minWindowHeight; + return TRUE; + } + break; + + case WM_COMMAND: + command = LOWORD(wParam); + + switch(command) { + case cAccessBridgeDLLLoaded: // toggle; unload or load AccessBridge + if (theAccessBridgeLoadedFlag) { + shutdownAccessBridge(); + theAccessBridgeLoadedFlag = FALSE; + CheckMenuItem( GetMenu(hWnd), cAccessBridgeDLLLoaded, + MF_BYCOMMAND | MF_UNCHECKED ); + } else { + theAccessBridgeLoadedFlag = initializeAccessBridge(); + if (theAccessBridgeLoadedFlag) { + CheckMenuItem( GetMenu(hWnd), cAccessBridgeDLLLoaded, + MF_BYCOMMAND | MF_CHECKED ); + reinstallEventListeners(); + } + } + return TRUE; + + case cExitMenuItem: + exitjaccessinspector(hWnd); + return TRUE; + + TRACK_EVENT_TOGGLE( cTrackMouseMenuItem, trackMouse, SetMouseEntered, + HandleMouseEntered ); + TRACK_EVENT_TOGGLE( cTrackMouseExitedMenuItem, trackMouseExited, + SetMouseExited, HandleMouseExited ); + TRACK_EVENT_TOGGLE( cTrackMouseClickedMenuItem, trackMouseClicked, + SetMouseClicked, HandleMouseClicked ); + TRACK_EVENT_TOGGLE( cTrackMousePressedMenuItem, trackMousePressed, + SetMousePressed, HandleMousePressed ); + TRACK_EVENT_TOGGLE( cTrackMouseReleasedMenuItem, trackMouseReleased, + SetMouseReleased, HandleMouseReleased ); + TRACK_EVENT_TOGGLE( cTrackShutdownMenuItem, trackShutdown, + SetJavaShutdown, HandleJavaShutdown ); + TRACK_EVENT_TOGGLE( cTrackFocusMenuItem, trackFocus, SetFocusGained, + HandleJavaFocusGained ); + TRACK_EVENT_TOGGLE( cTrackFocusLostMenuItem, trackFocusLost, + SetFocusLost, HandleJavaFocusLost ); + TRACK_EVENT_TOGGLE( cTrackCaretMenuItem, trackCaret, SetCaretUpdate, + HandleJavaCaretUpdate ); + + TRACK_EVENT_TOGGLE( cTrackMenuSelectedMenuItem, trackMenuSelected, + SetMenuSelected, HandleMenuSelected ); + TRACK_EVENT_TOGGLE( cTrackMenuDeselectedMenuItem, trackMenuDeselected, + SetMenuDeselected, HandleMenuDeselected ); + TRACK_EVENT_TOGGLE( cTrackMenuCanceledItem, trackMenuCanceled, + SetMenuCanceled, HandleMenuCanceled ); + + TRACK_EVENT_TOGGLE( cTrackPopupBecomeVisibleMenuItem, trackPopupVisible, + SetPopupMenuWillBecomeVisible, + HandlePopupMenuWillBecomeVisible ); + TRACK_EVENT_TOGGLE( cTrackPopupBecomeInvisibleMenuItem, + trackPopupInvisible, + SetPopupMenuWillBecomeInvisible, + HandlePopupMenuWillBecomeInvisible ); + TRACK_EVENT_TOGGLE( cTrackPopupCanceledItem, trackPopupCanceled, + SetPopupMenuCanceled, HandlePopupMenuCanceled ); + + TRACK_EVENT_TOGGLE( cTrackPropertyNameItem, trackPropertyNameChange, + SetPropertyNameChange, HandlePropertyNameChange ); + TRACK_EVENT_TOGGLE( cTrackPropertyDescriptionItem, + trackPropertyDescriptionChange, + SetPropertyDescriptionChange, + HandlePropertyDescriptionChange ); + TRACK_EVENT_TOGGLE( cTrackPropertyStateItem, trackPropertyStateChange, + SetPropertyStateChange, HandlePropertyStateChange ); + TRACK_EVENT_TOGGLE( cTrackPropertyValueItem, trackPropertyValueChange, + SetPropertyValueChange, HandlePropertyValueChange ); + TRACK_EVENT_TOGGLE( cTrackPropertySelectionItem, + trackPropertySelectionChange, + SetPropertySelectionChange, + HandlePropertySelectionChange ); + TRACK_EVENT_TOGGLE( cTrackPropertyTextItem, trackPropertyTextChange, + SetPropertyTextChange, HandlePropertyTextChange ); + TRACK_EVENT_TOGGLE( cTrackPropertyCaretItem, trackPropertyCaretChange, + SetPropertyCaretChange, HandlePropertyCaretChange ); + TRACK_EVENT_TOGGLE( cTrackPropertyVisibleDataItem, + trackPropertyVisibleDataChange, + SetPropertyVisibleDataChange, + HandlePropertyVisibleDataChange ); + TRACK_EVENT_TOGGLE( cTrackPropertyChildItem, trackPropertyChildChange, + SetPropertyChildChange, HandlePropertyChildChange ); + TRACK_EVENT_TOGGLE( cTrackPropertyActiveDescendentItem, + trackPropertyActiveDescendentChange, + SetPropertyActiveDescendentChange, + HandlePropertyActiveDescendentChange ); + TRACK_EVENT_TOGGLE( cTrackPropertyTableModelChangeItem, + trackPropertyTableModelChange, + SetPropertyTableModelChange, + HandlePropertyTableModelChange ); + + case cUpdateFromMouseMenuItem: + menu = GetMenu(hWnd); + if (updateMouse) { + updateMouse = FALSE; + CheckMenuItem( menu, cUpdateFromMouseMenuItem, + MF_BYCOMMAND | MF_UNCHECKED ); + UnhookWindowsHookEx((HHOOK)MouseProc); + KillTimer(hWnd, TIMER_ID); + } else { + updateMouse = TRUE; + CheckMenuItem( menu, cUpdateFromMouseMenuItem, + MF_BYCOMMAND | MF_CHECKED ); + prevMouseHook = SetWindowsHookEx( WH_MOUSE, MouseProc, + theInstance, + ::GetCurrentThreadId() ); + if (! prevMouseHook) { + lastError = ::GetLastError(); + } + } + return TRUE; + + case cUpdateWithF1Item: + menu = GetMenu(hWnd); + if (updateF1) { + updateF1 = FALSE; + CheckMenuItem( menu, cUpdateWithF1Item, + MF_BYCOMMAND | MFS_UNCHECKED ); + UnhookWindowsHookEx((HHOOK)KeyboardProc); + } else { + updateF1 = TRUE; + CheckMenuItem( menu, cUpdateWithF1Item, + MF_BYCOMMAND | MFS_CHECKED ); + prevKbdHook = SetWindowsHookEx( WH_KEYBOARD, KeyboardProc, + theInstance, + ::GetCurrentThreadId() ); + if (! prevKbdHook) { + lastError = ::GetLastError(); + } + } + return TRUE; + + case cUpdateWithF2Item: + menu = GetMenu(hWnd); + if (updateF2) { + updateF2 = FALSE; + CheckMenuItem( menu, cUpdateWithF2Item, + MF_BYCOMMAND | MFS_UNCHECKED ); + UnhookWindowsHookEx((HHOOK)KeyboardProc); + } else { + updateF2 = TRUE; + CheckMenuItem(menu, cUpdateWithF2Item, + MF_BYCOMMAND | MFS_CHECKED); + prevKbdHook = SetWindowsHookEx( WH_KEYBOARD, KeyboardProc, + theInstance, ::GetCurrentThreadId() ); + if (! prevKbdHook) { + lastError = ::GetLastError(); + } + } + return TRUE; + + case cMonitorTheSameEventsAsJAWS: + /* + Causes jaccessinspetor to monitor the same events as JAWS. Useful + when testing to determine if a bug is specific to JAWS or if it can + be reproduced in jaccessinspector as well. + */ + trackMouse = FALSE; + trackMouseExited = FALSE; + trackMouseClicked = FALSE; + trackMousePressed = FALSE; + trackMouseReleased = FALSE; + trackFocus = TRUE; + trackFocusLost = TRUE; + trackCaret = FALSE; + trackShutdown = FALSE; + + trackMenuSelected = FALSE; + trackMenuDeselected = FALSE; + trackMenuCanceled = FALSE; + + trackPopupVisible = FALSE; + trackPopupInvisible = FALSE; + trackPopupCanceled = FALSE; + + trackPropertyNameChange = TRUE; + trackPropertyDescriptionChange = TRUE; + trackPropertyStateChange = TRUE; + trackPropertyValueChange = TRUE; + trackPropertySelectionChange = TRUE; + trackPropertyTextChange = TRUE; + trackPropertyCaretChange = TRUE; + trackPropertyVisibleDataChange = FALSE; + trackPropertyChildChange = TRUE; + trackPropertyActiveDescendentChange = TRUE; + trackPropertyTableModelChange = FALSE; + + ApplyEventOptions(hWnd); + + return TRUE; + + case cMonitorAllEvents: + /* + Causes jaccessinspector to monitor all Java Events and all + Accessibility Events. + */ + trackMouse = TRUE; + trackMouseExited = TRUE; + trackMouseClicked = TRUE; + trackMousePressed = TRUE; + trackMouseReleased = TRUE; + trackFocus = TRUE; + trackFocusLost = TRUE; + trackCaret = TRUE; + trackShutdown = TRUE; + + trackMenuSelected = TRUE; + trackMenuDeselected = TRUE; + trackMenuCanceled = TRUE; + + trackPopupVisible = TRUE; + trackPopupInvisible = TRUE; + trackPopupCanceled = TRUE; + + trackPropertyNameChange = TRUE; + trackPropertyDescriptionChange = TRUE; + trackPropertyStateChange = TRUE; + trackPropertyValueChange = TRUE; + trackPropertySelectionChange = TRUE; + trackPropertyTextChange = TRUE; + trackPropertyCaretChange = TRUE; + trackPropertyVisibleDataChange = TRUE; + trackPropertyChildChange = TRUE; + trackPropertyActiveDescendentChange = TRUE; + trackPropertyTableModelChange = TRUE; + + ApplyEventOptions(hWnd); + + return TRUE; + + case cFirstMessage: + { + const char * messageText = g_MessageHistory.GetFirstMessage (); + if ( ( NULL != messageText ) && ( 0 != messageText [0] ) ) { + ::SetDlgItemText( theDialogWindow, cjaccessinspectorText, + messageText ); + } + EnableMessageNavButtons(); + UpdateMessageNumber(); + return TRUE; + } + break; + + case cPreviousMessage: + { + const char * messageText = g_MessageHistory.GetPreviousMessage (); + if ( ( NULL != messageText ) && ( 0 != messageText [0] ) ) { + ::SetDlgItemText( theDialogWindow, cjaccessinspectorText, + messageText ); + } + EnableMessageNavButtons(); + UpdateMessageNumber(); + return TRUE; + } + break; + + case cNextMessage: + { + const char * messageText = g_MessageHistory.GetNextMessage (); + if ( ( NULL != messageText ) && ( 0 != messageText [0] ) ) { + ::SetDlgItemText( theDialogWindow, cjaccessinspectorText, + messageText ); + } + EnableMessageNavButtons(); + UpdateMessageNumber(); + return TRUE; + } + break; + + case cLastMessage: + { + const char * messageText = g_MessageHistory.GetLastMessage(); + if ( ( NULL != messageText ) && ( 0 != messageText [0] ) ) { + ::SetDlgItemText( theDialogWindow, cjaccessinspectorText, + messageText ); + } + EnableMessageNavButtons(); + UpdateMessageNumber(); + return TRUE; + } + break; + + case cResetAllEvents: + trackMouse = FALSE; + trackMouseExited = FALSE; + trackMouseClicked = FALSE; + trackMousePressed = FALSE; + trackMouseReleased = FALSE; + trackFocus = FALSE; + trackFocusLost = FALSE; + trackCaret = FALSE; + trackShutdown = FALSE; + + trackMenuSelected = FALSE; + trackMenuDeselected = FALSE; + trackMenuCanceled = FALSE; + + trackPopupVisible = FALSE; + trackPopupInvisible = FALSE; + trackPopupCanceled = FALSE; + + trackPropertyNameChange = FALSE; + trackPropertyDescriptionChange = FALSE; + trackPropertyStateChange = FALSE; + trackPropertyValueChange = FALSE; + trackPropertySelectionChange = FALSE; + trackPropertyTextChange = FALSE; + trackPropertyCaretChange = FALSE; + trackPropertyVisibleDataChange = FALSE; + trackPropertyChildChange = FALSE; + trackPropertyActiveDescendentChange = FALSE; + trackPropertyTableModelChange = FALSE; + + ApplyEventOptions(hWnd); + + return TRUE; + + case cGoToMessage: + InitGoToMessageDialogBox(theInstance); + break; + + case cClearMessageHistory: + g_MessageHistory.clear(); + ::SetDlgItemText(theDialogWindow, cjaccessinspectorText, NULL); + EnableMessageNavButtons(); + UpdateMessageNumber(); + break; + } + break; + + case DISPLAY_INFO_MESSAGE: + echoMouseObject(); + return TRUE; + + case DISPLAY_HWND_INFO_MESSAGE: + echoMouseHWNDObject(); + return TRUE; + } + + return FALSE; +} + +#define SaveOptionToRegistry(optionVar) { \ + SetValue = RegSetValueEx( hKey, #optionVar, 0, REG_DWORD, \ + (LPBYTE)(&optionVar), sizeof(DWORD)); \ + if ( ERROR_SUCCESS != SetValue ) { \ + ++ failureCount; \ + } \ +} + +BOOL SaveActiveEventOptionsToRegistry() { + LONG CreateKey = ERROR_SUCCESS; + HKEY hKey = NULL; + DWORD Disposition = 0; + + CreateKey = ::RegCreateKeyEx( HKEY_CURRENT_USER, + jaccessinspectorOptionsRegistryKey, 0, 0, 0, + KEY_READ|KEY_WRITE, 0, &hKey, &Disposition ); + if ( ( ERROR_SUCCESS != CreateKey ) || ( NULL == hKey ) ) { + return FALSE; + } + + LONG SetValue = ERROR_SUCCESS; + unsigned long failureCount = 0; + + SaveOptionToRegistry(trackMouse); + SaveOptionToRegistry(trackMouseExited); + SaveOptionToRegistry(trackMouseClicked); + SaveOptionToRegistry(trackMousePressed); + SaveOptionToRegistry(trackMouseReleased); + SaveOptionToRegistry(trackShutdown); + SaveOptionToRegistry(trackFocus); + SaveOptionToRegistry(trackFocusLost); + SaveOptionToRegistry(trackCaret); + SaveOptionToRegistry(trackMenuSelected); + SaveOptionToRegistry(trackMenuDeselected); + SaveOptionToRegistry(trackMenuCanceled); + SaveOptionToRegistry(trackPopupVisible); + SaveOptionToRegistry(trackPopupInvisible); + SaveOptionToRegistry(trackPopupCanceled); + SaveOptionToRegistry(trackPropertyNameChange); + SaveOptionToRegistry(trackPropertyDescriptionChange); + SaveOptionToRegistry(trackPropertyStateChange); + SaveOptionToRegistry(trackPropertyValueChange); + SaveOptionToRegistry(trackPropertySelectionChange); + SaveOptionToRegistry(trackPropertyTextChange); + SaveOptionToRegistry(trackPropertyCaretChange); + SaveOptionToRegistry(trackPropertyVisibleDataChange); + SaveOptionToRegistry(trackPropertyChildChange); + SaveOptionToRegistry(trackPropertyActiveDescendentChange); + SaveOptionToRegistry(trackPropertyTableModelChange); + + ::RegFlushKey(hKey); + ::RegCloseKey(hKey); + + if ( 0 == failureCount ) { + return TRUE; + } + return FALSE; +} + +#define ReadOptionFromRegistry(optionVar) { \ + Type = Value = 0; \ + ValueSize = sizeof(DWORD); \ + QueryValue = ::RegQueryValueEx( hKey, #optionVar, NULL, &Type, \ + (LPBYTE)(&Value), &ValueSize); \ + if ( ( ERROR_SUCCESS == QueryValue ) && ( REG_DWORD == Type ) ) { \ + optionVar = static_cast(Value); \ + } else { \ + ++ failureCount; \ + } \ +} + +BOOL ReadActiveEventOptionsFromRegistry() { + + trackMouse = FALSE; + trackMouseExited = FALSE; + trackMouseClicked = FALSE; + trackMousePressed = FALSE; + trackMouseReleased = FALSE; + + trackShutdown = FALSE; + trackFocus = FALSE; + trackFocusLost = FALSE; + trackCaret = FALSE; + trackMenuSelected = FALSE; + trackMenuDeselected = FALSE; + trackMenuCanceled = FALSE; + trackPopupVisible = FALSE; + trackPopupInvisible = FALSE; + trackPopupCanceled = FALSE; + + trackPropertyNameChange = FALSE; + trackPropertyDescriptionChange = FALSE; + trackPropertyStateChange = FALSE; + trackPropertyValueChange = FALSE; + trackPropertySelectionChange = FALSE; + trackPropertyTextChange = FALSE; + trackPropertyCaretChange = FALSE; + trackPropertyVisibleDataChange = FALSE; + trackPropertyChildChange = FALSE; + trackPropertyActiveDescendentChange = FALSE; + trackPropertyTableModelChange = FALSE; + + LONG OpenKey = ERROR_SUCCESS; + HKEY hKey = NULL; + OpenKey = ::RegOpenKeyEx( HKEY_CURRENT_USER, + jaccessinspectorOptionsRegistryKey, 0, + KEY_READ, &hKey ); + if ( ( ERROR_SUCCESS != OpenKey ) || ( NULL == hKey ) ) { + return FALSE; + } + + LONG QueryValue = ERROR_SUCCESS; + unsigned long failureCount = 0; + DWORD Type, Value, ValueSize; + + ReadOptionFromRegistry(trackMouse); + ReadOptionFromRegistry(trackMouseExited); + ReadOptionFromRegistry(trackMouseClicked); + ReadOptionFromRegistry(trackMousePressed); + ReadOptionFromRegistry(trackMouseReleased); + ReadOptionFromRegistry(trackShutdown); + ReadOptionFromRegistry(trackFocus); + ReadOptionFromRegistry(trackFocusLost); + ReadOptionFromRegistry(trackCaret); + ReadOptionFromRegistry(trackMenuSelected); + ReadOptionFromRegistry(trackMenuDeselected); + ReadOptionFromRegistry(trackMenuCanceled); + ReadOptionFromRegistry(trackPopupVisible); + ReadOptionFromRegistry(trackPopupInvisible); + ReadOptionFromRegistry(trackPopupCanceled); + ReadOptionFromRegistry(trackPropertyNameChange); + ReadOptionFromRegistry(trackPropertyDescriptionChange); + ReadOptionFromRegistry(trackPropertyStateChange); + ReadOptionFromRegistry(trackPropertyValueChange); + ReadOptionFromRegistry(trackPropertySelectionChange); + ReadOptionFromRegistry(trackPropertyTextChange); + ReadOptionFromRegistry(trackPropertyCaretChange); + ReadOptionFromRegistry(trackPropertyVisibleDataChange); + ReadOptionFromRegistry(trackPropertyChildChange); + ReadOptionFromRegistry(trackPropertyActiveDescendentChange); + ReadOptionFromRegistry(trackPropertyTableModelChange); + + ::RegCloseKey(hKey); + + if ( 0 == failureCount ) { + return TRUE; + } + return FALSE; +} + +#define APPLY_EVENT_OPTION(menuItem, optionVar, setFP, handler) \ +{ \ + if ( optionVar ) { \ + ::CheckMenuItem(menu, menuItem, MF_BYCOMMAND | MF_CHECKED); \ + setFP (handler); \ + } else { \ + ::CheckMenuItem(menu, menuItem, MF_BYCOMMAND | MF_UNCHECKED); \ + setFP (NULL); \ + } \ +} + +void ApplyEventOptions (HWND hWnd) { + + HMENU menu = ::GetMenu (hWnd); + APPLY_EVENT_OPTION( cTrackMouseMenuItem, trackMouse, SetMouseEntered, + HandleMouseEntered ); + APPLY_EVENT_OPTION( cTrackMouseExitedMenuItem, trackMouseExited, + SetMouseExited, HandleMouseExited ); + APPLY_EVENT_OPTION( cTrackMouseClickedMenuItem, trackMouseClicked, + SetMouseClicked, HandleMouseClicked ); + APPLY_EVENT_OPTION( cTrackMousePressedMenuItem, trackMousePressed, + SetMousePressed, HandleMousePressed ); + APPLY_EVENT_OPTION( cTrackMouseReleasedMenuItem, trackMouseReleased, + SetMouseReleased, HandleMouseReleased ); + + APPLY_EVENT_OPTION( cTrackShutdownMenuItem, trackShutdown, SetJavaShutdown, + HandleJavaShutdown ); + APPLY_EVENT_OPTION( cTrackFocusMenuItem, trackFocus, SetFocusGained, + HandleJavaFocusGained ); + APPLY_EVENT_OPTION( cTrackFocusLostMenuItem, trackFocusLost, SetFocusLost, + HandleJavaFocusLost ); + APPLY_EVENT_OPTION( cTrackCaretMenuItem, trackCaret, SetCaretUpdate, + HandleJavaCaretUpdate ); + + APPLY_EVENT_OPTION( cTrackMenuSelectedMenuItem, trackMenuSelected, + SetMenuSelected, HandleMenuSelected ); + APPLY_EVENT_OPTION( cTrackMenuDeselectedMenuItem, trackMenuDeselected, + SetMenuDeselected, HandleMenuDeselected ); + APPLY_EVENT_OPTION( cTrackMenuCanceledItem, trackMenuCanceled, + SetMenuCanceled, HandleMenuCanceled ); + + APPLY_EVENT_OPTION( cTrackPopupBecomeVisibleMenuItem, trackPopupVisible, + SetPopupMenuWillBecomeVisible, + HandlePopupMenuWillBecomeVisible ); + APPLY_EVENT_OPTION( cTrackPopupBecomeInvisibleMenuItem, trackPopupInvisible, + SetPopupMenuWillBecomeInvisible, + HandlePopupMenuWillBecomeInvisible ); + APPLY_EVENT_OPTION( cTrackPopupCanceledItem, trackPopupCanceled, + SetPopupMenuCanceled, HandlePopupMenuCanceled ); + + APPLY_EVENT_OPTION( cTrackPropertyNameItem, trackPropertyNameChange, + SetPropertyNameChange, HandlePropertyNameChange ); + APPLY_EVENT_OPTION( cTrackPropertyDescriptionItem, + trackPropertyDescriptionChange, + SetPropertyDescriptionChange, + HandlePropertyDescriptionChange ); + APPLY_EVENT_OPTION( cTrackPropertyStateItem, trackPropertyStateChange, + SetPropertyStateChange, HandlePropertyStateChange ); + APPLY_EVENT_OPTION( cTrackPropertyValueItem, trackPropertyValueChange, + SetPropertyValueChange, HandlePropertyValueChange ); + APPLY_EVENT_OPTION( cTrackPropertySelectionItem, + trackPropertySelectionChange, + SetPropertySelectionChange, + HandlePropertySelectionChange); + APPLY_EVENT_OPTION( cTrackPropertyTextItem, trackPropertyTextChange, + SetPropertyTextChange, HandlePropertyTextChange ); + APPLY_EVENT_OPTION( cTrackPropertyCaretItem, trackPropertyCaretChange, + SetPropertyCaretChange, HandlePropertyCaretChange ); + APPLY_EVENT_OPTION( cTrackPropertyVisibleDataItem, + trackPropertyVisibleDataChange, + SetPropertyVisibleDataChange, + HandlePropertyVisibleDataChange ); + APPLY_EVENT_OPTION( cTrackPropertyChildItem, trackPropertyChildChange, + SetPropertyChildChange, HandlePropertyChildChange ); + APPLY_EVENT_OPTION( cTrackPropertyActiveDescendentItem, + trackPropertyActiveDescendentChange, + SetPropertyActiveDescendentChange, + HandlePropertyActiveDescendentChange ); + APPLY_EVENT_OPTION( cTrackPropertyTableModelChangeItem, + trackPropertyTableModelChange, + SetPropertyTableModelChange, + HandlePropertyTableModelChange ); + + MaybeCheckMonitorTheSameEventsAsJAWS(menu); + MaybeCheckMonitorAllEvents(menu); +} + +BOOL EnableDlgItem(HWND hDlg, int nIDDlgItem, BOOL bEnable) { + HWND dlgItem = ::GetDlgItem(hDlg, nIDDlgItem); + if ( NULL == dlgItem ) { + return FALSE; + } + return ::EnableWindow (dlgItem, bEnable); +} + +void EnableMessageNavButtons() { + HWND FocusWindow = ::GetFocus(); + int FocusCtrlID = ::GetDlgCtrlID(FocusWindow); + BOOL DisabledFocusWindow = FALSE; + if ( 0 == g_MessageHistory.GetMessageCount () ) { + EnableDlgItem(theDialogWindow, cFirstMessage, FALSE); + EnableDlgItem(theDialogWindow, cPreviousMessage, FALSE); + EnableDlgItem(theDialogWindow, cMessageNumber, FALSE); + EnableDlgItem(theDialogWindow, cNextMessage, FALSE); + EnableDlgItem(theDialogWindow, cLastMessage, FALSE); + } else if ( g_MessageHistory.IsFirstMessage () ) { + EnableDlgItem(theDialogWindow, cFirstMessage, FALSE); + EnableDlgItem(theDialogWindow, cPreviousMessage, FALSE); + EnableDlgItem(theDialogWindow, cMessageNumber, TRUE); + EnableDlgItem(theDialogWindow, cNextMessage, TRUE); + EnableDlgItem(theDialogWindow, cLastMessage, TRUE); + if ( ( cFirstMessage == FocusCtrlID ) || + ( cPreviousMessage == FocusCtrlID ) ) { + DisabledFocusWindow = TRUE; + } + } else if ( g_MessageHistory.IsLastMessage () ) { + EnableDlgItem(theDialogWindow, cFirstMessage, TRUE); + EnableDlgItem(theDialogWindow, cPreviousMessage, TRUE); + EnableDlgItem(theDialogWindow, cMessageNumber, TRUE); + EnableDlgItem(theDialogWindow, cNextMessage, FALSE); + EnableDlgItem(theDialogWindow, cLastMessage, FALSE); + + if ( ( cNextMessage == FocusCtrlID ) || + ( cLastMessage == FocusCtrlID ) ) { + DisabledFocusWindow = TRUE; + } + } else { + EnableDlgItem(theDialogWindow, cFirstMessage, TRUE); + EnableDlgItem(theDialogWindow, cPreviousMessage, TRUE); + EnableDlgItem(theDialogWindow, cMessageNumber, TRUE); + EnableDlgItem(theDialogWindow, cNextMessage, TRUE); + EnableDlgItem(theDialogWindow, cLastMessage, TRUE); + } + + if ( DisabledFocusWindow ) { + /* + We just disabled the window that had the focus. Set focus to the + cjaccessinspectorText window. Otherwise it will no longer be possible + to tab through the controls in jaccessinspector. + */ + HWND jaccessinspectorText = + ::GetDlgItem(theDialogWindow, cjaccessinspectorText); + if ( jaccessinspectorText ) { + ::SetFocus(jaccessinspectorText); + } + } +} + +void WINAPI AddToMessageHistory(const char * message) { + g_MessageHistory.AddMessage(message); + EnableMessageNavButtons(); + UpdateMessageNumber(); +} + +BOOL UpdateMessageNumber () { + HWND dlgItem = ::GetDlgItem(theDialogWindow, cMessageNumber); + if ( NULL == dlgItem ) { + return FALSE; + } + + size_t messageCount = g_MessageHistory.GetMessageCount(); + size_t messageNumber = g_MessageHistory.GetCurrentMessageIndex() + 1; + char text [32] = {0}; + if ( 0 != messageCount ) { + ::_snprintf(text, sizeof(text), "%d of %d", messageNumber, messageCount); + } + return ::SetWindowText(dlgItem, text); +} + +INT_PTR CALLBACK GoToMessageDialogProc( HWND hDlg, UINT message, WPARAM wParam, + LPARAM lParam ) { + BOOL ret_val = FALSE; + switch ( message ) { + case WM_INITDIALOG: + { + /* + This code to center the Go To Message dialog box in the + jaccessinspector window was taken from + . + */ + HWND hwndOwner = NULL; + RECT rcOwner = { 0, 0, 0, 0 }; + RECT rc = { 0, 0, 0, 0 }; + RECT rcDlg = { 0, 0, 0, 0 }; + + // Get the owner window and dialog box rectangles. + if ( NULL == (hwndOwner = GetParent(hDlg)) ) { + hwndOwner = GetDesktopWindow(); + } + + GetWindowRect(hwndOwner, &rcOwner); + GetWindowRect(hDlg, &rcDlg); + CopyRect(&rc, &rcOwner); + + // Offset the owner and dialog box rectangles so that right and + // bottom values represent the width and height, and then offset + // the owner again to discard space taken up by the dialog box. + OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top); + OffsetRect(&rc, -rc.left, -rc.top); + OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom); + + // The new position is the sum of half the remaining space and the + // owner's original position. + SetWindowPos (hDlg, + HWND_TOP, + rcOwner.left + (rc.right / 2), + rcOwner.top + (rc.bottom / 2), + 0, 0, // Ignores size arguments. + SWP_NOSIZE); + } + break; + + case WM_COMMAND: + switch ( LOWORD (wParam) ) { + case IDOK: + { + size_t GoToMessageNumber = 0; + BOOL Translated = FALSE; + GoToMessageNumber = GetDlgItemInt( hDlg, IDC_MESSAGE_NUMBER_EDIT, + &Translated, FALSE ); + EndDialog (hDlg, IDOK); + theGoToDialogWindow = NULL; + + if ( ( Translated ) && ( GoToMessageNumber > 0 ) ) { + const char * messageText = NULL; + if ( (GoToMessageNumber - 1) < + g_MessageHistory.GetMessageCount() ) { + messageText = + g_MessageHistory.GetMessage(GoToMessageNumber - 1); + } else if ( (GoToMessageNumber - 1) >= + g_MessageHistory.GetMessageCount() ) { + messageText = g_MessageHistory.GetLastMessage(); + } + if ( ( NULL != messageText ) && ( 0 != messageText [0] ) ) { + ::SetDlgItemText( theDialogWindow, cjaccessinspectorText, + messageText ); + } + EnableMessageNavButtons(); + UpdateMessageNumber(); + } + } + break; + case IDCANCEL: + EndDialog(hDlg, IDCANCEL); + theGoToDialogWindow = NULL; + break; + } + break; + } + return ret_val; +} + +BOOL InitGoToMessageDialogBox (HANDLE hInstance) { + theGoToDialogWindow = CreateDialog ( + (struct HINSTANCE__ *)hInstance, MAKEINTRESOURCE(IDD_GO_TO_MESSAGE), + theDialogWindow, GoToMessageDialogProc); + + if ( NULL == theGoToDialogWindow ) { + return FALSE; + } + + ShowWindow (theGoToDialogWindow, SW_SHOW); + return TRUE; +} + +BOOL ShouldCheckMonitorTheSameEventsAsJAWS () { + if ( + ( FALSE == trackMouse ) + && ( FALSE == trackMouseExited ) + && ( FALSE == trackMouseClicked ) + && ( FALSE == trackMousePressed ) + && ( FALSE == trackMouseReleased ) + && ( TRUE == trackFocus ) + && ( TRUE == trackFocusLost ) + && ( FALSE == trackCaret ) + && ( FALSE == trackShutdown ) + && ( FALSE == trackMenuSelected ) + && ( FALSE == trackMenuDeselected ) + && ( FALSE == trackMenuCanceled ) + && ( FALSE == trackPopupVisible ) + && ( FALSE == trackPopupInvisible ) + && ( FALSE == trackPopupCanceled ) + && ( TRUE == trackPropertyNameChange ) + && ( TRUE == trackPropertyDescriptionChange ) + && ( TRUE == trackPropertyStateChange ) + && ( TRUE == trackPropertyValueChange ) + && ( TRUE == trackPropertySelectionChange ) + && ( TRUE == trackPropertyTextChange ) + && ( TRUE == trackPropertyCaretChange ) + && ( FALSE == trackPropertyVisibleDataChange ) + && ( TRUE == trackPropertyChildChange ) + && ( TRUE == trackPropertyActiveDescendentChange ) + && ( FALSE == trackPropertyTableModelChange ) + ) + { + return TRUE; + } + + return FALSE; +} + +void MaybeCheckMonitorTheSameEventsAsJAWS(HMENU menu) { + UINT uCheck = MF_BYCOMMAND | MF_UNCHECKED; + if ( ShouldCheckMonitorTheSameEventsAsJAWS() ) { + uCheck = MF_BYCOMMAND | MF_CHECKED; + } + ::CheckMenuItem(menu, cMonitorTheSameEventsAsJAWS, uCheck); +} + +BOOL ShouldCheckMonitorAllEvents() { + if ( + ( TRUE == trackMouse ) + && ( TRUE == trackMouseExited ) + && ( TRUE == trackMouseClicked ) + && ( TRUE == trackMousePressed ) + && ( TRUE == trackMouseReleased ) + && ( TRUE == trackFocus ) + && ( TRUE == trackFocusLost ) + && ( TRUE == trackCaret ) + && ( TRUE == trackShutdown ) + && ( TRUE == trackMenuSelected ) + && ( TRUE == trackMenuDeselected ) + && ( TRUE == trackMenuCanceled ) + && ( TRUE == trackPopupVisible ) + && ( TRUE == trackPopupInvisible ) + && ( TRUE == trackPopupCanceled ) + && ( TRUE == trackPropertyNameChange ) + && ( TRUE == trackPropertyDescriptionChange ) + && ( TRUE == trackPropertyStateChange ) + && ( TRUE == trackPropertyValueChange ) + && ( TRUE == trackPropertySelectionChange ) + && ( TRUE == trackPropertyTextChange ) + && ( TRUE == trackPropertyCaretChange ) + && ( TRUE == trackPropertyVisibleDataChange ) + && ( TRUE == trackPropertyChildChange ) + && ( TRUE == trackPropertyActiveDescendentChange ) + && ( TRUE == trackPropertyTableModelChange ) + ) + { + return TRUE; + } + + return FALSE; +} + +void MaybeCheckMonitorAllEvents(HMENU menu) { + UINT uCheck = MF_BYCOMMAND | MF_UNCHECKED; + if ( ShouldCheckMonitorAllEvents() ) { + uCheck = MF_BYCOMMAND | MF_CHECKED; + } + ::CheckMenuItem(menu, cMonitorAllEvents, uCheck); +} diff --git a/jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.h b/jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.h new file mode 100644 index 00000000000..bbf29d51f36 --- /dev/null +++ b/jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +#define JACCESSINSPECTOR_LOG "jaccessinspector.log" + +void CALLBACK TimerProc(HWND hWnd, UINT uTimerMsg, UINT uTimerID, DWORD dwTime); +LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam); + +BOOL InitWindow(HANDLE hInstance); +INT_PTR CALLBACK jaccessinspectorDialogProc( HWND hDlg, UINT message, + WPARAM wParam, LPARAM lParam ); + +void HandleJavaPropertyChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac, + wchar_t *name, wchar_t *oldValue, + wchar_t *newValue ); + +void HandleJavaShutdown(long vmID); +void HandleJavaFocusGained(long vmID, FocusEvent event, AccessibleContext ac); +void HandleJavaFocusLost(long vmID, FocusEvent event, AccessibleContext ac); + +void HandleJavaCaretUpdate(long vmID, CaretEvent event, AccessibleContext ac); + +void HandleMouseClicked(long vmID, MouseEvent event, AccessibleContext ac); +void HandleMouseEntered(long vmID, MouseEvent event, AccessibleContext ac); +void HandleMouseExited(long vmID, MouseEvent event, AccessibleContext ac); +void HandleMousePressed(long vmID, MouseEvent event, AccessibleContext ac); +void HandleMouseReleased(long vmID, MouseEvent event, AccessibleContext ac); + +void HandleMenuCanceled(long vmID, MenuEvent event, AccessibleContext ac); +void HandleMenuDeselected(long vmID, MenuEvent event, AccessibleContext ac); +void HandleMenuSelected(long vmID, MenuEvent event, AccessibleContext ac); +void HandlePopupMenuCanceled(long vmID, MenuEvent event, AccessibleContext ac); +void HandlePopupMenuWillBecomeInvisible( long vmID, MenuEvent event, + AccessibleContext ac ); +void HandlePopupMenuWillBecomeVisible( long vmID, MenuEvent event, + AccessibleContext ac ); + +void HandlePropertyNameChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac, + wchar_t *oldName, wchar_t *newName); +void HandlePropertyDescriptionChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac, + wchar_t *oldDescription, + wchar_t *newDescription ); +void HandlePropertyStateChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac, + wchar_t *oldState, wchar_t *newState ); +void HandlePropertyValueChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac, + wchar_t *oldValue, wchar_t *newValue ); +void HandlePropertySelectionChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac ); +void HandlePropertyTextChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac ); +void HandlePropertyCaretChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac, + int oldPosition, int newPosition ); +void HandlePropertyVisibleDataChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac ); +void HandlePropertyChildChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac, + jobject oldChild, jobject newChild ); +void HandlePropertyActiveDescendentChange(long vmID, PropertyChangeEvent event, + AccessibleContext ac, + jobject oldActiveDescendent, + jobject newActiveDescendent); + +void HandlePropertyTableModelChange( long vmID, PropertyChangeEvent event, + AccessibleContext ac, + wchar_t *oldValue, wchar_t *newValue ); + +char *getAccessibleInfo( long vmID, AccessibleContext ac, + int x, int y, char *buffer, int bufsize ); + +char *getTimeAndDate(); +void displayAndLogText(char *buffer, ...); + +const char * const jaccessinspectorOptionsRegistryKey = + "Software\\JavaSoft\\Java Development Kit\\jaccessinspector"; +BOOL SaveActiveEventOptionsToRegistry(); +BOOL ReadActiveEventOptionsFromRegistry(); +void ApplyEventOptions(HWND hWnd); +BOOL EnableDlgItem(HWND hDlg, int nIDDlgItem, BOOL bEnable); +void EnableMessageNavButtons(); +void WINAPI AddToMessageHistory(const char * message); +BOOL UpdateMessageNumber(); +INT_PTR CALLBACK GoToMessageDialogProc( HWND hDlg, UINT message, WPARAM wParam, + LPARAM lParam ); +BOOL InitGoToMessageDialogBox(HANDLE hInstance); +BOOL ShouldCheckMonitorTheSameEventsAsJAWS(); +void MaybeCheckMonitorTheSameEventsAsJAWS(HMENU menu); +BOOL ShouldCheckMonitorAllEvents(); +void MaybeCheckMonitorAllEvents(HMENU menu); diff --git a/jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspectorResource.h b/jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspectorResource.h new file mode 100644 index 00000000000..8155551ea31 --- /dev/null +++ b/jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspectorResource.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +#define IDR_ACCELERATOR 102 +#define IDD_GO_TO_MESSAGE 103 +#define cjaccessinspectorText 1001 +#define cFirstMessage 1029 +#define cPreviousMessage 1030 +#define cNextMessage 1031 +#define cLastMessage 1032 +#define cMessageNumber 1033 +#define IDC_MESSAGE_NUMBER_EDIT 1034 +#define cFerretMenus 10000 +#define cFileMenu 10100 +#define cAccessBridgeDLLLoaded 10101 +#define cExitMenuItem 10102 +#define cJavaEventsMenu 10200 +#define cTrackMouseMenuItem 10201 +#define cTrackFocusMenuItem 10203 +#define cTrackCaretMenuItem 10204 +#define cTrackMenuSelectedMenuItem 10205 +#define cTrackMenuDeselectedMenuItem 10206 +#define cTrackMenuCanceledItem 10207 +#define cTrackPopupBecomeVisibleMenuItem 10208 +#define cTrackPopupBecomeInvisibleMenuItem 10209 +#define cTrackPopupCanceledItem 10210 +#define cUpdateSettingsMenu 10300 +#define cUpdateWithF1Item 10301 +#define cUpdateWithF2Item 10302 +#define cUpdateFromMouseMenuItem 10304 +#define cAccessibilityEventsMenu 10400 +#define cTrackPropertyNameItem 10401 +#define cTrackPropertyDescriptionItem 10402 +#define cTrackPropertyStateItem 10403 +#define cTrackPropertyValueItem 10404 +#define cTrackPropertySelectionItem 10405 +#define cTrackPropertyTextItem 10406 +#define cTrackPropertyCaretItem 10407 +#define cTrackPropertyVisibleDataItem 10408 +#define cTrackPropertyChildItem 10409 +#define cTrackPropertyActiveDescendentItem 10410 +#define cTrackPropertyTableModelChangeItem 10411 +#define cTrackShutdownMenuItem 10412 +#define cMonitorTheSameEventsAsJAWS 10413 +#define cTrackFocusLostMenuItem 10414 +#define cTrackMouseExitedMenuItem 10415 +#define cTrackMouseClickedMenuItem 10416 +#define cTrackMousePressedMenuItem 10417 +#define cTrackMouseReleasedMenuItem 10418 +#define cResetAllEvents 10419 +#define cGoToMessage 10420 +#define cClearMessageHistory 10421 +#define cMonitorAllEvents 10422 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 104 +#define _APS_NEXT_COMMAND_VALUE 10423 +#define _APS_NEXT_CONTROL_VALUE 1035 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspectorWindow.rc b/jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspectorWindow.rc new file mode 100644 index 00000000000..e8ba9e37242 --- /dev/null +++ b/jdk/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspectorWindow.rc @@ -0,0 +1,249 @@ +// Microsoft Visual C++ generated resource script. +// +#include "jaccessinspectorResource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +JACCESSINSPECTORWINDOW DIALOG 160, 78, 354, 214 +STYLE DS_SETFONT | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +CAPTION "jaccessinspector" +MENU cjaccessinspectorMenus +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT cjaccessinspectorText,4,24,340,184,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL + PUSHBUTTON "&First Message",cFirstMessage,4,4,60,14 + PUSHBUTTON "&Previous Message",cPreviousMessage,70,4,60,14 + EDITTEXT cMessageNumber,134,4,80,14,ES_CENTER | ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "&Next Message",cNextMessage,218,4,60,14 + PUSHBUTTON "&Last Message",cLastMessage,284,4,60,14 +END + +IDD_GO_TO_MESSAGE DIALOGEX 0, 0, 186, 66 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | WS_POPUP | WS_CAPTION +CAPTION "Go To Message" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Message Number:",IDC_STATIC,14,14,64,8 + EDITTEXT IDC_MESSAGE_NUMBER_EDIT,80,14,90,14,ES_AUTOHSCROLL | ES_NUMBER + DEFPUSHBUTTON "OK",IDOK,35,45,50,14 + PUSHBUTTON "Cancel",IDCANCEL,101,45,50,14 +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "jaccessinspectorResource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + "JACCESSINSPECTORWINDOW", DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 347 + END + + IDD_GO_TO_MESSAGE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 59 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +cjaccessinspectorMenus MENU +BEGIN + POPUP "File" + BEGIN + MENUITEM "AccessBridge DLL Loaded", cAccessBridgeDLLLoaded + MENUITEM "Exit", cExitMenuItem + END + POPUP "UpdateSettings" + BEGIN + MENUITEM "Update from Mouse", cUpdateFromMouseMenuItem + MENUITEM "Update with F2 (mouse HWND)", cUpdateWithF2Item + MENUITEM "Update with F1 (mouse point)", cUpdateWithF1Item + END + POPUP "JavaEvents" + BEGIN + MENUITEM "Track Java Shutdown Events", cTrackShutdownMenuItem + MENUITEM SEPARATOR + MENUITEM "Track Mouse Entered Events", cTrackMouseMenuItem + MENUITEM "Track Mouse Exited Events", cTrackMouseExitedMenuItem + MENUITEM "Track Mouse Clicked Events", cTrackMouseClickedMenuItem + MENUITEM "Track Mouse Pressed Events", cTrackMousePressedMenuItem + MENUITEM "Track Mouse Released Events", cTrackMouseReleasedMenuItem + MENUITEM SEPARATOR + MENUITEM "Track Focus Gained Events", cTrackFocusMenuItem + MENUITEM "Track Focus Lost Events", cTrackFocusLostMenuItem + MENUITEM "Track Caret Events", cTrackCaretMenuItem + MENUITEM SEPARATOR + MENUITEM "Track Menu Selected Events", cTrackMenuSelectedMenuItem + MENUITEM "Track Menu Deselected Events", cTrackMenuDeselectedMenuItem + MENUITEM "Track Menu Canceled Events", cTrackMenuCanceledItem + MENUITEM "Track Popup Visible Events", cTrackPopupBecomeVisibleMenuItem + MENUITEM "Track Popup Inviible Events", cTrackPopupBecomeInvisibleMenuItem + MENUITEM "Track Popup Canceled Events", cTrackPopupCanceledItem + END + POPUP "AccessibilityEvents" + BEGIN + MENUITEM "Track Name Property Events", cTrackPropertyNameItem + MENUITEM "Track Description Property Events", cTrackPropertyDescriptionItem + MENUITEM "Track State Property Events", cTrackPropertyStateItem + MENUITEM "Track Value Property Events", cTrackPropertyValueItem + MENUITEM "Track Selection Property Events", cTrackPropertySelectionItem + MENUITEM "Track Text Property Events", cTrackPropertyTextItem + MENUITEM "Track Caret Property Events", cTrackPropertyCaretItem + MENUITEM "Track Visible Data Property Events", cTrackPropertyVisibleDataItem + MENUITEM "Track Child Property Events", cTrackPropertyChildItem + MENUITEM "Track Active Descendent Property Events", cTrackPropertyActiveDescendentItem + MENUITEM "Track Table Model Change Property Events", cTrackPropertyTableModelChangeItem + END + POPUP "&Options" + BEGIN + MENUITEM "&Monitor the same events as JAWS", cMonitorTheSameEventsAsJAWS + MENUITEM "Monitor &All Events", cMonitorAllEvents + MENUITEM "&Reset All Events", cResetAllEvents + MENUITEM "&Go To Message", cGoToMessage + MENUITEM "&Clear Message History", cClearMessageHistory + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +// Need 2 defines so macro argument to XSTR will get expanded before quoting. +#define XSTR(x) STR(x) +#define STR(x) #x + +VS_VERSION_INFO VERSIONINFO + FILEVERSION JDK_FVER + PRODUCTVERSION JDK_FVER + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + // FILEOS 0x4 is Win32, 0x40004 is Win32 NT only + FILEOS 0x4L + // FILETYPE should be 0x1 for .exe and 0x2 for .dll + FILETYPE JDK_FTYPE + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", XSTR(JDK_COMPANY) "\0" + VALUE "FileDescription", XSTR(JDK_COMPONENT) "\0" + VALUE "FileVersion", XSTR(JDK_VER) "\0" + VALUE "Full Version", XSTR(JDK_BUILD_ID) "\0" + VALUE "InternalName", XSTR(JDK_INTERNAL_NAME) "\0" + VALUE "LegalCopyright", XSTR(JDK_COPYRIGHT) "\0" + VALUE "OriginalFilename", XSTR(JDK_FNAME) "\0" + VALUE "ProductName", XSTR(JDK_NAME) "\0" + VALUE "ProductVersion", XSTR(JDK_VER) "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_ACCELERATOR ACCELERATORS +BEGIN + VK_HOME, cFirstMessage, VIRTKEY, CONTROL, ALT, NOINVERT + "G", cGoToMessage, VIRTKEY, CONTROL, NOINVERT + VK_END, cLastMessage, VIRTKEY, CONTROL, ALT, NOINVERT + VK_NEXT, cNextMessage, VIRTKEY, CONTROL, NOINVERT + VK_PRIOR, cPreviousMessage, VIRTKEY, CONTROL, NOINVERT + "X", cClearMessageHistory, VIRTKEY, CONTROL, NOINVERT +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp b/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp new file mode 100644 index 00000000000..b8602f52f0d --- /dev/null +++ b/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 "jaccesswalker.h" +#include "AccessInfo.h" + +HWND ourHwnd; +HWND topLevelWindow; +int depth = -1; +FILE *logfile; +HMENU popupMenu; + +char theJaccesswalkerClassName[] = "JaccesswalkerWin"; +char theAccessInfoClassName[] = "AccessInfoWin"; + +HWND theJaccesswalkerWindow; +HWND theTreeControlWindow; +HINSTANCE theInstance; +Jaccesswalker *theJaccesswalker; +AccessibleNode *theSelectedNode; +AccessibleNode *thePopupNode; +AccessibleContext theSelectedAccessibleContext; +HWND hwndTV; // handle of tree-view control + +int APIENTRY WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + + if (logfile == null) { + logfile = fopen(JACCESSWALKER_LOG, "w"); // overwrite existing log file + logString(logfile, "Starting jaccesswalker.exe %s\n", getTimeAndDate()); + } + + theInstance = hInstance; + + // start Jaccesswalker + theJaccesswalker = new Jaccesswalker(nCmdShow); + + return 0; +} + +Jaccesswalker::Jaccesswalker(int nCmdShow) { + + HWND hwnd; + static char szAppName[] = "jaccesswalker"; + static char szMenuName[] = "JACCESSWALKERMENU"; + MSG msg; + WNDCLASSEX wc; + + // jaccesswalker window + wc.cbSize = sizeof(wc); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = WinProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = theInstance; + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDI_APPLICATION); + wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); + wc.lpszMenuName = szMenuName; + wc.lpszClassName = szAppName; + wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + RegisterClassEx(&wc); + + // AccessInfo Window + wc.cbSize = sizeof(WNDCLASSEX); + + wc.hInstance = theInstance; + wc.lpszClassName = theAccessInfoClassName; + wc.lpfnWndProc = (WNDPROC)AccessInfoWindowProc; + wc.style = 0; + + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + + wc.lpszMenuName = ""; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + + wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); + + RegisterClassEx(&wc); + + // create the jaccesswalker window + hwnd = CreateWindow(szAppName, + szAppName, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + NULL, + NULL, + theInstance, + NULL); + + ourHwnd = hwnd; + + /* Initialize the common controls. */ + INITCOMMONCONTROLSEX cc; + cc.dwSize = sizeof(INITCOMMONCONTROLSEX); + cc.dwICC = ICC_TREEVIEW_CLASSES; + InitCommonControlsEx(&cc); + + ShowWindow(hwnd, nCmdShow); + + UpdateWindow(hwnd); + + BOOL result = initializeAccessBridge(); + if (result != FALSE) { + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + shutdownAccessBridge(); + } +} + +/* + * the jaccesswalker window proc + */ +LRESULT CALLBACK WinProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { + + int command; + short width, height; + + switch(iMsg) { + + case WM_CREATE: + // create the accessibility tree view + theTreeControlWindow = CreateATreeView(hwnd); + + // load the popup menu + popupMenu = LoadMenu(theInstance, "PopupMenu"); + popupMenu = GetSubMenu(popupMenu, 0); + break; + + case WM_CLOSE: + EndDialog(hwnd, TRUE); + PostQuitMessage (0); + break; + + case WM_SIZE: + width = LOWORD(lParam); + height = HIWORD(lParam); + SetWindowPos(theTreeControlWindow, NULL, 0, 0, width, height, 0); + return FALSE; // let windows finish handling this + + case WM_COMMAND: + command = LOWORD(wParam); + switch(command) { + + case cExitMenuItem: + EndDialog(hwnd, TRUE); + PostQuitMessage (0); + break; + + case cRefreshTreeItem: + // update the accessibility tree + theJaccesswalker->buildAccessibilityTree(); + break; + + case cAPIMenuItem: + // open a new window with the Accessibility API in it for the + // selected element in the tree + if (theSelectedNode != (AccessibleNode *) 0) { + theSelectedNode->displayAPIWindow(); + } + break; + + case cAPIPopupItem: + // open a new window with the Accessibility API in it for the + // element in the tree adjacent to the popup menu + if (thePopupNode != (AccessibleNode *) 0) { + thePopupNode->displayAPIWindow(); + } + break; + + } + break; + + case WM_NOTIFY: // receive tree messages + + NMTREEVIEW *nmptr = (LPNMTREEVIEW) lParam; + switch (nmptr->hdr.code) { + + case TVN_SELCHANGED: + // get the selected tree node + theSelectedNode = (AccessibleNode *) nmptr->itemNew.lParam; + break; + + case NM_RCLICK: + + // display a popup menu over the tree node + POINT p; + GetCursorPos(&p); + TrackPopupMenu(popupMenu, 0, p.x, p.y, 0, hwnd, NULL); + + // get the tree node under the popup menu + TVHITTESTINFO hitinfo; + ScreenToClient(theTreeControlWindow, &p); + hitinfo.pt = p; + HTREEITEM node = TreeView_HitTest(theTreeControlWindow, &hitinfo); + + if (node != null) { + TVITEMEX tvItem; + tvItem.hItem = node; + if (TreeView_GetItem(hwndTV, &tvItem) == TRUE) { + thePopupNode = (AccessibleNode *)tvItem.lParam; + } + } + break; + } + } + return DefWindowProc(hwnd, iMsg, wParam, lParam); +} + +/* + * Accessibility information window proc + */ +LRESULT CALLBACK AccessInfoWindowProc(HWND hWnd, UINT message, + UINT wParam, LONG lParam) { + short width, height; + HWND dlgItem; + + switch (message) { + case WM_CREATE: + RECT rcClient; // dimensions of client area + HWND hwndEdit; // handle of tree-view control + + // Get the dimensions of the parent window's client area, + // and create the edit control. + GetClientRect(hWnd, &rcClient); + hwndEdit = CreateWindow("Edit", + "", + WS_VISIBLE | WS_TABSTOP | WS_CHILD | + ES_MULTILINE | ES_AUTOVSCROLL | + ES_READONLY | WS_VSCROLL, + 0, 0, rcClient.right, rcClient.bottom, + hWnd, + (HMENU) cAccessInfoText, + theInstance, + NULL); + break; + + case WM_CLOSE: + DestroyWindow(hWnd); + break; + + case WM_SIZE: + width = LOWORD(lParam); + height = HIWORD(lParam); + dlgItem = GetDlgItem(hWnd, cAccessInfoText); + SetWindowPos(dlgItem, NULL, 0, 0, width, height, 0); + return FALSE; // let windows finish handling this + break; + + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + + return 0; +} + +/** + * Build a tree (and the treeview control) of all accessible Java components + * + */ +void Jaccesswalker::buildAccessibilityTree() { + TreeView_DeleteAllItems (theTreeControlWindow); + // have MS-Windows call EnumWndProc() with all of the top-level windows + EnumWindows((WNDENUMPROC) EnumWndProc, NULL); +} + +/** + * Create (and display) the accessible component nodes of a parent AccessibleContext + * + */ +BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lParam) { + if (IsJavaWindow(hwnd)) { + long vmID; + AccessibleContext ac; + if (GetAccessibleContextFromHWND(hwnd, &vmID, &ac) == TRUE) { + theJaccesswalker->addComponentNodes(vmID, ac, (AccessibleNode *) NULL, + hwnd, TVI_ROOT, theTreeControlWindow); + } + topLevelWindow = hwnd; + } else { + char szClass [MAX_PATH] = {0}; + ::GetClassNameA(hwnd, szClass, sizeof(szClass) - 1); + if ( ( 0 == ::strcmp(szClass, "IEFrame") ) + || ( 0 == ::strcmp(szClass, "MozillaUIWindowClass") ) ) { + EnumChildWindows(hwnd, (WNDENUMPROC) EnumChildProc, NULL); + } + } + return TRUE; +} + +/* +Detects whether or not the specified Java window is one from which no useable +information can be obtained. + +This function tests for various scenarios I have seen in Java applets where the +Java applet had no meaningful accessible information. It does not detect all +scenarios, just the most common ones. +*/ +BOOL IsInaccessibleJavaWindow(const HWND hwnd) +{ + BOOL ret_val ( FALSE ); + { + BOOL bT ( FALSE ); + long vmIdWindow ( 0 ); + AccessibleContext acWindow ( 0 ); + bT = GetAccessibleContextFromHWND(hwnd, &vmIdWindow, &acWindow); + if ( ( bT ) && ( 0 != vmIdWindow ) && ( 0 != acWindow ) ) { + AccessibleContextInfo infoWindow = {0}; + bT = GetAccessibleContextInfo(vmIdWindow, acWindow, &infoWindow); + if ( ( bT ) + && ( 0 == infoWindow.name [0] ) + && ( 0 == infoWindow.description [0] ) + && ( 0 == ::wcscmp(infoWindow.role_en_US, L"frame") ) ) { + if ( 0 == infoWindow.childrenCount ) { + ret_val = TRUE; + } else if ( 1 == infoWindow.childrenCount ) { + AccessibleContext acChild ( 0 ); + acChild = + GetAccessibleChildFromContext(vmIdWindow, acWindow, 0); + if ( NULL != acChild ) { + AccessibleContextInfo infoChild = {0}; + bT = GetAccessibleContextInfo( vmIdWindow, acChild, + &infoChild ); + if ( ( bT ) + && ( 0 == infoChild.name [0] ) + && ( 0 == infoChild.description [0] ) + && ( 0 == ::wcscmp(infoChild.role_en_US, L"panel") ) + && ( 1 == infoChild.childrenCount ) ) { + AccessibleContext acChild1 ( 0 ); + acChild1 = GetAccessibleChildFromContext( vmIdWindow, + acChild, 0); + if ( NULL != acChild1 ) { + AccessibleContextInfo infoChild1 = {0}; + bT = GetAccessibleContextInfo( vmIdWindow, + acChild1, &infoChild1 ); + if ( ( bT ) + && ( 0 == infoChild1.name [0] ) + && ( 0 == infoChild1.description [0] ) + && ( 0 == ::wcscmp(infoChild1.role_en_US, L"frame") ) + && ( 0 == infoChild1.childrenCount ) ) { + ret_val = TRUE; + } else if ( ( bT ) + && ( 0 == infoChild1.name [0] ) + && ( 0 == infoChild1.description [0] ) + && ( 0 == ::wcscmp( infoChild1.role_en_US, + L"panel") ) + && ( 1 == infoChild1.childrenCount ) ) { + AccessibleContext acChild2 ( 0 ); + acChild2 = GetAccessibleChildFromContext( + vmIdWindow, acChild1, 0 ); + if ( NULL != acChild2 ) { + AccessibleContextInfo infoChild2 = {0}; + bT = GetAccessibleContextInfo( + vmIdWindow, acChild2, &infoChild2 ); + if ( ( bT ) + && ( 0 == infoChild2.name [0] ) + && ( 0 == infoChild2.description [0] ) + && ( 0 == ::wcscmp( infoChild2.role_en_US, + L"frame") ) + && ( 0 == infoChild2.childrenCount ) ) { + ret_val = TRUE; + } + } + } + } + } else if ( ( bT ) + && ( 0 == infoChild.name [0] ) + && ( 0 == infoChild.description [0] ) + && ( 0 == ::wcscmp( infoChild.role_en_US, + L"canvas") ) + && ( 0 == infoChild.childrenCount ) ) { + ret_val = TRUE; + } + } + } + } else if ( ( bT ) + && ( 0 == infoWindow.name [0] ) + && ( 0 == infoWindow.description [0] ) + && ( 0 == ::wcscmp(infoWindow.role_en_US, L"panel") ) ) { + if ( 1 == infoWindow.childrenCount ) { + AccessibleContext acChild ( 0 ); + acChild = GetAccessibleChildFromContext( vmIdWindow, + acWindow, 0 ); + if ( NULL != acChild ) { + AccessibleContextInfo infoChild = {0}; + bT = GetAccessibleContextInfo( vmIdWindow, + acChild, &infoChild ); + if ( ( bT ) + && ( 0 == infoChild.name [0] ) + && ( 0 == infoChild.description [0] ) + && ( 0 == ::wcscmp(infoChild.role_en_US, L"frame") ) + && ( 0 == infoChild.childrenCount ) ) { + ret_val = TRUE; + } else if ( ( bT ) + && ( 0 == infoChild.name [0] ) + && ( 0 == infoChild.description [0] ) + && ( 0 == ::wcscmp( infoChild.role_en_US, + L"panel") ) + && ( 1 == infoChild.childrenCount ) ) { + AccessibleContext acChild1 ( 0 ); + acChild1 = GetAccessibleChildFromContext( vmIdWindow, + acChild, 0); + if ( NULL != acChild1 ) { + AccessibleContextInfo infoChild1 = {0}; + bT = GetAccessibleContextInfo( vmIdWindow, + acChild1, + &infoChild1 ); + if ( ( bT ) + && ( 0 == infoChild1.name [0] ) + && ( 0 == infoChild1.description [0] ) + && ( 0 == ::wcscmp( infoChild1.role_en_US, + L"frame") ) + && ( 0 == infoChild1.childrenCount ) ) { + ret_val = TRUE; + } + } + } + } + } + } + } else if ( FALSE == bT ) { + ret_val = TRUE; + } + } + return ret_val; +} + +BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam) +{ + if ( ( IsJavaWindow(hwnd) ) + && ( FALSE == IsInaccessibleJavaWindow(hwnd) ) ) { + long vmID ( 0 ); + AccessibleContext ac ( 0 ); + if ( TRUE == GetAccessibleContextFromHWND(hwnd, &vmID, &ac) ) { + theJaccesswalker->addComponentNodes( + vmID, ac, (AccessibleNode *) NULL, + hwnd, TVI_ROOT, theTreeControlWindow); + } + topLevelWindow = hwnd; + } else { + EnumChildWindows(hwnd, (WNDENUMPROC) EnumChildProc, NULL); + } + return TRUE; +} + +// CreateATreeView - creates a tree-view control. +// Returns the handle of the new control if successful or NULL +// otherwise. +// hwndParent - handle of the control's parent window +HWND CreateATreeView(HWND hwndParent) { + RECT rcClient; // dimensions of client area + + // Get the dimensions of the parent window's client area, and create + // the tree-view control. + GetClientRect(hwndParent, &rcClient); + hwndTV = CreateWindow(WC_TREEVIEW, + "", + WS_VISIBLE | WS_TABSTOP | WS_CHILD | + TVS_HASLINES | TVS_HASBUTTONS | + TVS_LINESATROOT, + 0, 0, rcClient.right, rcClient.bottom, + hwndParent, + (HMENU) cTreeControl, + theInstance, + NULL); + + return hwndTV; +} + +/** + * Create (and display) the accessible component nodes of a parent AccessibleContext + * + */ +void Jaccesswalker::addComponentNodes(long vmID, AccessibleContext context, + AccessibleNode *parent, HWND hwnd, + HTREEITEM treeNodeParent, HWND treeWnd) { + + AccessibleNode *newNode = new AccessibleNode( vmID, context, parent, hwnd, + treeNodeParent ); + + AccessibleContextInfo info; + if (GetAccessibleContextInfo(vmID, context, &info) != FALSE) { + char s[LINE_BUFSIZE]; + + wsprintf(s, "%ls", info.name); + newNode->setAccessibleName(s); + wsprintf(s, "%ls", info.role); + newNode->setAccessibleRole(s); + + wsprintf(s, "%ls [%ls]", info.name, info.role); + + TVITEM tvi; + tvi.mask = TVIF_PARAM | TVIF_TEXT; + tvi.pszText = (char *) s; // Accessible name and role + tvi.cchTextMax = (int)strlen(s); + tvi.lParam = (long) newNode; // Accessibility information + + TVINSERTSTRUCT tvis; + tvis.hParent = treeNodeParent; + tvis.hInsertAfter = TVI_LAST; + tvis.item = tvi; + + HTREEITEM treeNodeItem = TreeView_InsertItem(treeWnd, &tvis); + + for (int i = 0; i < info.childrenCount; i++) { + addComponentNodes(vmID, GetAccessibleChildFromContext(vmID, context, i), + newNode, hwnd, treeNodeItem, treeWnd); + } + } else { + char s[LINE_BUFSIZE]; + sprintf( s, + "ERROR calling GetAccessibleContextInfo; vmID = %X, context = %X", + vmID, context ); + + TVITEM tvi; + tvi.mask = TVIF_PARAM | TVIF_TEXT; // text and lParam are only valid parts + tvi.pszText = (char *) s; + tvi.cchTextMax = (int)strlen(s); + tvi.lParam = (long) newNode; + + TVINSERTSTRUCT tvis; + tvis.hParent = treeNodeParent; + tvis.hInsertAfter = TVI_LAST; // make tree in order given + tvis.item = tvi; + + HTREEITEM treeNodeItem = TreeView_InsertItem(treeWnd, &tvis); + } +} + +// ----------------------------- + +/** + * Create an AccessibleNode + * + */ +AccessibleNode::AccessibleNode(long JavaVMID, AccessibleContext context, + AccessibleNode *parent, HWND hwnd, + HTREEITEM parentTreeNodeItem) { + vmID = JavaVMID; + ac = context; + parentNode = parent; + baseHWND = hwnd; + treeNodeParent = parentTreeNodeItem; + + // setting accessibleName and accessibleRole not done here, + // in order to minimize calls to the AccessBridge + // (since such a call is needed to enumerate children) +} + +/** + * Destroy an AccessibleNode + * + */ +AccessibleNode::~AccessibleNode() { + ReleaseJavaObject(vmID, ac); +} + +/** + * Set the accessibleName string + * + */ +void AccessibleNode::setAccessibleName(char *name) { + strncpy(accessibleName, name, MAX_STRING_SIZE); +} + +/** + * Set the accessibleRole string + * + */ +void AccessibleNode::setAccessibleRole(char *role) { + strncpy(accessibleRole, role, SHORT_STRING_SIZE); +} + + + + + + + +/** + * Create an API window to show off the info for this AccessibleContext + */ +BOOL AccessibleNode::displayAPIWindow() { + + HWND apiWindow = CreateWindow(theAccessInfoClassName, + "Java Accessibility API view", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + 600, + 750, + HWND_DESKTOP, + NULL, + theInstance, + (void *) NULL); + + if (!apiWindow) { + printError("cannot create API window"); + return FALSE; + } + + char buffer[HUGE_BUFSIZE]; + buffer[0] = '\0'; + getAccessibleInfo(vmID, ac, buffer, sizeof(buffer)); + displayAndLog(apiWindow, cAccessInfoText, logfile, buffer); + + ShowWindow(apiWindow, SW_SHOWNORMAL); + UpdateWindow(apiWindow); + + return TRUE; +} + + + diff --git a/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.h b/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.h new file mode 100644 index 00000000000..b6dd9b8765a --- /dev/null +++ b/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 // includes basic windows functionality +#include +#include +#include +#include "jaccesswalkerResource.h" +#include "AccessBridgeCalls.h" +#include "AccessBridgeCallbacks.h" +#include "AccessBridgeDebug.h" + +#include +#include +#include +#include +#include +#include + +#include + +extern FILE *file; + +#define null NULL +#define JACCESSWALKER_LOG "jaccesswalker.log" + +/** + * A node in the jaccesswalker tree + */ +class AccessibleNode { + + HWND baseHWND; + HTREEITEM treeNodeParent; + long vmID; + AccessibleContext ac; + AccessibleNode *parentNode; + char accessibleName[MAX_STRING_SIZE]; + char accessibleRole[SHORT_STRING_SIZE]; + +public: + AccessibleNode(long vmID, AccessibleContext context, + AccessibleNode *parent, HWND hWnd, + HTREEITEM parentTreeNodeItem); + ~AccessibleNode(); + void setAccessibleName(char *name); + void setAccessibleRole(char *role); + BOOL displayAPIWindow(); // bring up an Accessibility API detail window +}; + + +/** + * The main application class + */ +class Jaccesswalker { + +public: + Jaccesswalker(int nCmdShow); + BOOL InitWindow(int windowMode); + char *getAccessibleInfo( long vmID, AccessibleContext ac, char *buffer, + int bufsize ); + void exitjaccesswalker(HWND hWnd); + void buildAccessibilityTree(); + void addComponentNodes( long vmID, AccessibleContext context, + AccessibleNode *parent, HWND hWnd, + HTREEITEM treeNodeParent, HWND treeWnd ); +}; + +char *getTimeAndDate(); + +void displayAndLogText(char *buffer, ...); + +LRESULT CALLBACK WinProc (HWND, UINT, WPARAM, LPARAM); + +void debugString(char *msg, ...); + +LRESULT CALLBACK jaccesswalkerWindowProc( HWND hDlg, UINT message, UINT wParam, + LONG lParam ); + +BOOL CALLBACK EnumWndProc(HWND hWnd, LPARAM lParam); +BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam); + +HWND CreateATreeView(HWND hwndParent); + +LRESULT CALLBACK AccessInfoWindowProc( HWND hWnd, UINT message, UINT wParam, + LONG lParam ); + +char *getAccessibleInfo( long vmID, AccessibleContext ac, char *buffer, + int bufsize ); diff --git a/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalkerResource.h b/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalkerResource.h new file mode 100644 index 00000000000..905e13924c3 --- /dev/null +++ b/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalkerResource.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +#define cTreeControl 1001 +#define cAccessInfoText 2001 +#define cMonkeyMenus 10000 +#define cFileMenu 10100 +#define cRefreshTreeItem 10101 +#define cExitMenuItem 10103 +#define cSettingsMenu 10200 +#define cAPIMenuItem 10201 +#define cAPIPopupItem 10202 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40003 +#define _APS_NEXT_CONTROL_VALUE 1032 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalkerWindow.rc b/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalkerWindow.rc new file mode 100644 index 00000000000..372e7b83bc7 --- /dev/null +++ b/jdk/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalkerWindow.rc @@ -0,0 +1,182 @@ +//Microsoft Developer Studio generated resource script. +// +#include "jaccesswalkerResource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +JACCESSWALKERWINDOW DIALOG DISCARDABLE 160, 78, 294, 214 +STYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | + WS_THICKFRAME +CAPTION "jaccesswalker" +MENU 10000 +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Tree1",cTreeControl,"SysTreeView32",TVS_HASBUTTONS | + TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | + WS_BORDER | WS_TABSTOP,4,0,283,214 +END + +EXPLORERWINDOW DIALOG DISCARDABLE 160, 78, 294, 214 +STYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | + WS_THICKFRAME +CAPTION "Java Accessibility Information" +MENU 10000 +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT cAccessInfoText,4,0,283,214,ES_MULTILINE | ES_AUTOVSCROLL | + ES_READONLY | WS_VSCROLL +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "jaccesswalkerResource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + "JACCESSWALKERWINDOW", DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 287 + END + + "ACCESSINFOWINDOW", DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 287 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +JACCESSWALKERMENU MENU DISCARDABLE +BEGIN + POPUP "File" + BEGIN + MENUITEM "Refresh Tree", cRefreshTreeItem + MENUITEM SEPARATOR + MENUITEM "Exit", cExitMenuItem + END + POPUP "Panels" + BEGIN + MENUITEM "Display Accessibility Information", cAPIMenuItem + END +END + + +PopupMenu MENU + { + POPUP "" + { + MENUITEM "Display Accessibility Information", cAPIPopupItem + } + } + + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +// Need 2 defines so macro argument to XSTR will get expanded before quoting. +#define XSTR(x) STR(x) +#define STR(x) #x + +VS_VERSION_INFO VERSIONINFO + FILEVERSION JDK_FVER + PRODUCTVERSION JDK_FVER + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + // FILEOS 0x4 is Win32, 0x40004 is Win32 NT only + FILEOS 0x4L + // FILETYPE should be 0x1 for .exe and 0x2 for .dll + FILETYPE JDK_FTYPE + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", XSTR(JDK_COMPANY) "\0" + VALUE "FileDescription", XSTR(JDK_COMPONENT) "\0" + VALUE "FileVersion", XSTR(JDK_VER) "\0" + VALUE "Full Version", XSTR(JDK_BUILD_ID) "\0" + VALUE "InternalName", XSTR(JDK_INTERNAL_NAME) "\0" + VALUE "LegalCopyright", XSTR(JDK_COPYRIGHT) "\0" + VALUE "OriginalFilename", XSTR(JDK_FNAME) "\0" + VALUE "ProductName", XSTR(JDK_NAME) "\0" + VALUE "ProductVersion", XSTR(JDK_VER) "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END diff --git a/jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.cpp b/jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.cpp index 75a7b6d8d0d..c1054b48f76 100644 --- a/jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.cpp +++ b/jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.cpp @@ -3487,10 +3487,15 @@ AccessBridgeJavaEntryPoints::getAccessibleTextInfo(jobject accessibleContext, // Get the index at the given point if (getAccessibleIndexAtPointFromContextMethod != (jmethodID) 0) { - textInfo->indexAtPoint = jniEnv->CallIntMethod(accessBridgeObject, - getAccessibleIndexAtPointFromContextMethod, - accessibleContext, x, y); - EXCEPTION_CHECK("Getting AccessibleIndexAtPoint - call to CallIntMethod()", FALSE); + // If x or y is -1 return -1 + if (x == -1 || y == -1) { + textInfo->indexAtPoint = -1; + } else { + textInfo->indexAtPoint = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleIndexAtPointFromContextMethod, + accessibleContext, x, y); + EXCEPTION_CHECK("Getting AccessibleIndexAtPoint - call to CallIntMethod()", FALSE); + } PrintDebugString(" Index at point = %d", textInfo->indexAtPoint); } else { PrintDebugString(" Error! either env == 0 or getAccessibleIndexAtPointFromContextMethod == 0"); diff --git a/jdk/src/jdk.accessibility/windows/native/toolscommon/AccessInfo.cpp b/jdk/src/jdk.accessibility/windows/native/toolscommon/AccessInfo.cpp new file mode 100644 index 00000000000..564c2e29bce --- /dev/null +++ b/jdk/src/jdk.accessibility/windows/native/toolscommon/AccessInfo.cpp @@ -0,0 +1,948 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 "AccessBridgeCalls.h" +#include "AccessInfo.h" +#include +#include + +LogStringCallbackFP g_LogStringCallback = NULL; + +/* + * returns formatted date and time + */ +char *getTimeAndDate() { + static char datebuf[64]; + struct tm *newtime; + char am_pm[] = "AM"; + time_t long_time; + + time( &long_time ); /* Get time as long integer. */ + newtime = localtime( &long_time ); /* Convert to local time. */ + + if( newtime->tm_hour > 12 ) /* Set up extension. */ + strcpy( am_pm, "PM" ); + if( newtime->tm_hour > 12 ) /* Convert from 24-hour */ + newtime->tm_hour -= 12; /* to 12-hour clock. */ + if( newtime->tm_hour == 0 ) /*Set hour to 12 if midnight. */ + newtime->tm_hour = 12; + + sprintf(datebuf, "%.19s %s\n", asctime( newtime ), am_pm ); + return (char *)datebuf; +} + + +/* + * displays a message in a dialog and writes the message to a logfile + */ +void displayAndLog(HWND hDlg, int nIDDlgItem, FILE *logfile, char *msg, ...) { + + if (hDlg == NULL || msg == NULL) { + return; + } + + char tmpbuf[HUGE_BUFSIZE]; + va_list argprt; + + va_start(argprt, msg); + vsprintf(tmpbuf, msg, argprt); + + SetDlgItemText(hDlg, nIDDlgItem, tmpbuf); + + fprintf(logfile, "\n****************************************\n"); + fprintf(logfile, "%s\n", getTimeAndDate()); + fprintf(logfile, "%s\n", tmpbuf); + fflush(logfile); + + if ( NULL != g_LogStringCallback ) + { + g_LogStringCallback (tmpbuf); + } +} + +/* + * writes a text string to a logfile + */ +void logString(FILE *logfile, char *msg, ...) { + + if (logfile == NULL || msg == NULL) { + return; + } + + char tmpbuf[LINE_BUFSIZE]; + va_list argprt; + + va_start(argprt, msg); + vsprintf(tmpbuf, msg, argprt); + + fprintf(logfile, tmpbuf); + fprintf(logfile, "\n"); + fflush(logfile); +} + +/* + * safely appends a message to a buffer + */ +BOOL appendToBuffer(char *buf, size_t buflen, char *msg, ...) { + + static char warning[] = + "\nNot enough buffer space; remaining information truncated.\n"; + size_t warningLength = strlen(warning) + 1; + + if (buf == NULL || msg == NULL) { + return FALSE; + } + + char tmpbuf[LARGE_BUFSIZE]; + va_list argprt; + + va_start(argprt, msg); + vsprintf(tmpbuf, msg, argprt); + + // verify there's enough space in the buffer + size_t spaceRemaining = buflen - strlen(buf) - 1; + if (spaceRemaining <= warningLength) { + strncat(buf, warning, spaceRemaining); + return FALSE; + } + strncat(buf, tmpbuf, spaceRemaining); + return TRUE; +} + +/** + * returns accessibility information for an AccessibleContext + */ +char *getAccessibleInfo(long vmID, AccessibleContext ac, char *buffer, + int bufsize) { + return getAccessibleInfo(vmID, ac, 0, 0, buffer, bufsize); +} + +/** + * returns accessibility information at the specified coordinates in an + * AccessibleContext + */ +char *getAccessibleInfo(long vmID, AccessibleContext ac, int x, int y, + char *buffer, int bufsize) { + + wchar_t tmpBuf[LINE_BUFSIZE]; + wchar_t name[LINE_BUFSIZE]; + int i, j; + long start; + long end; + + if (buffer == NULL || bufsize <= 0) { + return NULL; + } + buffer[0] = NULL; + + /* ===== AccessBridge / J2SE version information ===== */ + + AccessBridgeVersionInfo versionInfo; + BOOL result = GetVersionInfo(vmID, &versionInfo); + + if (result == FALSE) { + appendToBuffer( buffer, bufsize, + "\r\nERROR: cannot get version information", bufsize ); + } else { + appendToBuffer(buffer, bufsize, "Version Information:"); + appendToBuffer( buffer, bufsize, + "\r\n Java virtual machine version: %ls", + versionInfo.VMversion ); + appendToBuffer( buffer, bufsize, + "\r\n Access Bridge Java class version: %ls", + versionInfo.bridgeJavaClassVersion ); + appendToBuffer( buffer, bufsize, + "\r\n Access Bridge Java DLL version: %ls", + versionInfo.bridgeJavaDLLVersion ); + appendToBuffer( buffer, bufsize, + "\r\n Access Bridge Windows DLL version: %ls", + versionInfo.bridgeWinDLLVersion ); + } + + if (ac == (AccessibleContext) 0) { + return buffer; + } + + + /* ===== core AccessibleContext information ===== */ + + AccessibleContextInfo info; + if (GetAccessibleContextInfo(vmID, ac, &info) == FALSE) { + appendToBuffer( buffer, bufsize, + "\r\nERROR: GetAccessibleContextInfo failed ", bufsize ); + } else { + appendToBuffer( buffer, bufsize, + "\r\n\r\nAccessibleContext information", bufsize ); + if (x >= 0 && y >= 0) { + appendToBuffer(buffer, bufsize, " at mouse point [%d, %d]:", x, y); + } else { + appendToBuffer(buffer, bufsize, ":", bufsize); + } + + appendToBuffer(buffer, bufsize, "\r\n Name: %ls", info.name); + if ( getVirtualAccessibleName( vmID, ac, name, + (sizeof(name) / sizeof(wchar_t)) ) == FALSE ) { + appendToBuffer( buffer, bufsize, + "\r\n\r\nERROR: getVirtualAccessibleName", bufsize ); + } else { + appendToBuffer(buffer, bufsize, "\r\n Virtual Name: %ls", name); + } + appendToBuffer( buffer, bufsize, "\r\n Description: %ls", + info.description ); + appendToBuffer(buffer, bufsize, "\r\n Role: %ls", info.role); + appendToBuffer( buffer, bufsize, "\r\n Role in en_US locale: %ls", + info.role_en_US ); + appendToBuffer(buffer, bufsize, "\r\n States: %ls", info.states); + appendToBuffer( buffer, bufsize, "\r\n States in en_US locale: %ls", + info.states_en_US ); + appendToBuffer( buffer, bufsize, "\r\n Index in parent: %d", + info.indexInParent ); + appendToBuffer( buffer, bufsize, "\r\n Children count: %d", + info.childrenCount ); + appendToBuffer( buffer, bufsize, + "\r\n Bounding rectangle: [%d, %d, %d, %d]", + info.x, info.y, info.x + info.width, + info.y + info.height ); + + /* top-level window info */ + AccessibleContext topAC = getTopLevelObject(vmID, ac); + if (topAC == NULL) { + appendToBuffer( buffer, bufsize, + "\r\nERROR: getTopLevelObject failed", bufsize ); + } else { + AccessibleContextInfo topInfo; + if (GetAccessibleContextInfo(vmID, topAC, &topInfo) == FALSE) { + appendToBuffer( + buffer, bufsize, + "\r\nERROR: GetAccessibleContextInfo failed for top-level window ", + bufsize ); + } else { + if (getVirtualAccessibleName(vmID, topAC, name, + (sizeof(name) / sizeof(wchar_t)) ) == FALSE) { + appendToBuffer( buffer, bufsize, + "\r\n\r\nERROR: getVirtualAccessibleName", + bufsize ); + } else { + appendToBuffer( buffer, bufsize, + "\r\n Top-level window name: %ls", + name ); + } + appendToBuffer( buffer, bufsize, + "\r\n Top-level window role: %ls", + topInfo.role ) ; + } + ReleaseJavaObject(vmID, topAC); + + } + + /* ===== AccessibleParent information ===== */ + + AccessibleContext parentAC = GetAccessibleParentFromContext(vmID, ac); + if (parentAC == NULL) { + appendToBuffer(buffer, bufsize, "\r\n No parent", bufsize); + } else { + AccessibleContextInfo parentInfo; + if (GetAccessibleContextInfo(vmID, parentAC, &parentInfo) == FALSE) { + appendToBuffer( buffer, bufsize, + "\r\nERROR: GetAccessibleContextInfo failed for parent", + bufsize ); + } else { + appendToBuffer( buffer, bufsize, "\r\n Parent name: %ls", + parentInfo.name ); + if ( getVirtualAccessibleName( vmID, parentAC, name, + (sizeof(name) / sizeof(wchar_t)) ) == FALSE ) { + appendToBuffer( buffer, bufsize, + "\r\n\r\nERROR: getVirtualAccessibleName", + bufsize ); + } else { + appendToBuffer( buffer, bufsize, + "\r\n Parent virtual name: %ls", name ); + } + appendToBuffer( buffer, bufsize, "\r\n Parent role: %ls", + parentInfo.role ); + } + ReleaseJavaObject(vmID, parentAC); + } + + + /* ====== visible children ===== */ + int nChildren = getVisibleChildrenCount(vmID, ac); + if (nChildren == -1) { + appendToBuffer( buffer, bufsize, + "\r\nERROR: GetVisibleChildrenCount failed", + bufsize ); + } else { + appendToBuffer( buffer, bufsize, + "\r\n Visible descendents count: %d", + nChildren ); + } + + if (nChildren > 0) { + VisibleChildrenInfo visibleChildrenInfo; + if (getVisibleChildren(vmID, ac, 0, &visibleChildrenInfo) == FALSE) { + appendToBuffer( buffer, bufsize, + "\r\nERROR: GetVisibleChildren failed", + bufsize ); + } else { + AccessibleContextInfo childACInfo; + for ( int child = 0; + child < visibleChildrenInfo.returnedChildrenCount; + child++ ) { + AccessibleContext childAC = + visibleChildrenInfo.children[child]; + if (GetAccessibleContextInfo(vmID, childAC, &childACInfo)) { + if ( getVirtualAccessibleName( vmID, childAC, name, + (sizeof(name) / sizeof(wchar_t))) == FALSE) { + appendToBuffer( buffer, bufsize, + "\r\n\r\nERROR: getVirtualAccessibleName", + bufsize ); + } else { + appendToBuffer( buffer, bufsize, + "\r\n Descendent %d name: %ls", child, + name ); + } + appendToBuffer( buffer, bufsize, + "\r\n Descendent %d role: %ls", + child, childACInfo.role ); + } + ReleaseJavaObject(vmID, childAC); + } + } + } + + /* ===== AccessibleSelection ===== */ + + if (info.accessibleSelection == TRUE) { + + int selCount; + AccessibleContext selectedAC; + + appendToBuffer( buffer, bufsize, + "\r\n\r\nAccessible Selection information:", + bufsize ); + + if ((selCount = GetAccessibleSelectionCountFromContext(vmID, ac)) != -1) { + appendToBuffer( buffer, bufsize, "\r\n Selection count: %d", + selCount ); + + for (i = 0; i < selCount; i++) { + if ( ( selectedAC = + GetAccessibleSelectionFromContext(vmID, ac, i) ) == NULL ) { + appendToBuffer( buffer, bufsize, + "\r\nERROR: GetAccessibleSelectionFromContext failed forselection %d", + i ); + } else { + if (GetAccessibleContextInfo(vmID, selectedAC, &info) == FALSE) { + appendToBuffer( buffer, bufsize, + "\r\nERROR: GetAccessibleContextInfo failed for selection %d", i); + } else { + if ( getVirtualAccessibleName( vmID, selectedAC, name, + (sizeof(name) / sizeof(wchar_t)) ) == FALSE ) { + appendToBuffer( buffer, bufsize, + "\r\n\r\nERROR: getVirtualAccessibleName", bufsize); + } else { + appendToBuffer( buffer, bufsize, + "\r\n Selection %d name: %ls", i, name ); + } + appendToBuffer( buffer, bufsize, + "\r\n Selection %d role: %ls", i, info.role); + appendToBuffer( buffer, bufsize, + "\r\n Index in parent of selection %d: %d", + i, info.indexInParent ); + } + ReleaseJavaObject(vmID, selectedAC); + } + } + } + } + + // ====== Accessible KeyBindings, Icons and Actions ====== + + AccessibleKeyBindings keyBindings; + if (getAccessibleKeyBindings(vmID, ac, &keyBindings) == TRUE && + keyBindings.keyBindingsCount > 0) { + + appendToBuffer( buffer, bufsize, + "\r\n\r\nAccessibleKeyBinding info:", bufsize ); + appendToBuffer( buffer, bufsize, + "\r\n Number of key bindings: %d", + keyBindings.keyBindingsCount ); + + for (j = 0; j < keyBindings.keyBindingsCount; j++) { + + appendToBuffer( buffer, bufsize, + "\r\n Key binding %d character: %c", j, + keyBindings.keyBindingInfo[j].character ); + appendToBuffer( buffer, bufsize, + "\r\n Key binding %d modifiers: %d", j, + keyBindings.keyBindingInfo[j].modifiers ); + } + } + + AccessibleIcons icons; + if (getAccessibleIcons(vmID, ac, &icons) == TRUE && + icons.iconsCount > 0) { + + appendToBuffer( buffer, bufsize, + "\r\n\r\nAccessibleIcons info:", bufsize ); + appendToBuffer( buffer, bufsize, + "\r\n Number of icons: %d", icons.iconsCount ); + + for (j = 0; j < icons.iconsCount; j++) { + + appendToBuffer( buffer, bufsize, + "\r\n Icon %d description: %ls", j, + icons.iconInfo[j].description ); + appendToBuffer( buffer, bufsize, + "\r\n Icon %d height: %d", j, + icons.iconInfo[j].height ); + appendToBuffer( buffer, bufsize, + "\r\n Icon %d width: %d", j, + icons.iconInfo[j].width ); + } + } + + AccessibleActions actions; + if (getAccessibleActions(vmID, ac, &actions) == TRUE && + actions.actionsCount > 0) { + + appendToBuffer( buffer, bufsize, "\r\n\r\nAccessibleActions info:", + bufsize ); + appendToBuffer( buffer, bufsize, "\r\n Number of actions: %d", + actions.actionsCount ); + + for (j = 0; j < actions.actionsCount; j++) { + appendToBuffer( buffer, bufsize, "\r\n Action %d name: %ls", + j, actions.actionInfo[j].name ); + } + } + + /* ===== AccessibleRelationSet ===== */ + + AccessibleRelationSetInfo relationSetInfo; + if (getAccessibleRelationSet(vmID, ac, &relationSetInfo) == FALSE) { + appendToBuffer( buffer, bufsize, + "\r\nGetAccessibleRelationSet failed.", bufsize ); + } else { + int i; + AccessibleContextInfo relInfo; + + if (relationSetInfo.relationCount > 0) { + appendToBuffer( buffer, bufsize, + "\r\n\r\nAccessibleRelationSet information:", + bufsize ); + appendToBuffer( buffer, bufsize, + "\r\n Number of relations: %d", + relationSetInfo.relationCount ); + } + for (i = 0; i < relationSetInfo.relationCount; i++) { + AccessibleRelationInfo relationInfo = + relationSetInfo.relations[i]; + + appendToBuffer( buffer, bufsize, + "\r\n Relation %d key: %ls", i, + relationInfo.key ); + appendToBuffer( buffer, bufsize, + "\r\n Relation %d target count: %d", i, + relationInfo.targetCount ); + for (j = 0; j < relationInfo.targetCount; j++) { + if (GetAccessibleContextInfo( + vmID, relationInfo.targets[j], &relInfo ) == FALSE) { + appendToBuffer( buffer, bufsize, + "\r\nERROR: GetAccessibleContextInfo failed.", + bufsize ); + } else { + // Core AccessibleContext information for relation target + if ( getVirtualAccessibleName( vmID, relationInfo.targets[j], + name, (sizeof(name) / sizeof(wchar_t)) ) == FALSE ) { + appendToBuffer( buffer, bufsize, + "\r\n\r\nERROR: getVirtualAccessibleName", bufsize ); + } else { + appendToBuffer( buffer, bufsize, + "\r\n Target %d name: %ls", + j, name ); + } + appendToBuffer( buffer, bufsize, + "\r\n Target %d role: %ls", j, + relInfo.role); + } + ReleaseJavaObject(vmID, relationInfo.targets[j]); + + } + } + } + + /* ===== AccessibleValue ===== */ + + if (info.accessibleInterfaces & cAccessibleValueInterface) { + + appendToBuffer( buffer, bufsize, + "\r\n\r\nAccessible Value information:", bufsize); + + if ( GetCurrentAccessibleValueFromContext( vmID, ac, tmpBuf, + (sizeof(tmpBuf) / sizeof(wchar_t)) ) == TRUE ) { + appendToBuffer( buffer, bufsize, "\r\n Current Value: %ls", + tmpBuf ); + } + if ( GetMaximumAccessibleValueFromContext( vmID, ac, tmpBuf, + (sizeof(tmpBuf) / sizeof(wchar_t))) == TRUE ) { + appendToBuffer( buffer, bufsize, + "\r\n Maximum Value: %ls", tmpBuf ); + } + if ( GetMinimumAccessibleValueFromContext( vmID, ac, tmpBuf, + (sizeof(tmpBuf) / sizeof(wchar_t)) ) == TRUE ) { + appendToBuffer( buffer, bufsize, + "\r\n Minimum Value: %ls", tmpBuf ); + } + } + + + /* ===== AccessibleTable ===== */ + + AccessibleTableInfo tableInfo; + + if ( (info.accessibleInterfaces & cAccessibleTableInterface) == + cAccessibleTableInterface ) { + if (getAccessibleTableInfo(vmID, ac, &tableInfo) != TRUE) { + appendToBuffer( buffer, bufsize, + "\r\nERROR: getAccessibleTableInfo failed", + bufsize ); + } else { + appendToBuffer( buffer, bufsize, + "\r\n\r\nAccessibleTable info:", bufsize ); + + int trow = getAccessibleTableRow( vmID, + tableInfo.accessibleTable, 3 ); + appendToBuffer( buffer, bufsize, + "\r\n getAccessibleTableRow: %d", trow); + + int tcol = + getAccessibleTableColumn(vmID, tableInfo.accessibleTable, 2); + appendToBuffer( buffer, bufsize, + "\r\n getAccessibleTableColumn: %d", tcol ); + + int tindex = getAccessibleTableIndex( vmID, + tableInfo.accessibleTable, + 2, 3 ); + appendToBuffer( buffer, bufsize, + "\r\n getAccessibleTableIndex: %d", + tindex ); + + // Core info + appendToBuffer( buffer, bufsize, + "\r\n table row count: %d", + tableInfo.rowCount ); + appendToBuffer( buffer, bufsize, + "\r\n table column count: %d", + tableInfo.columnCount ); + + AccessibleTableCellInfo tableCellInfo; + for (int i = 0; i < tableInfo.rowCount; i++) { + for (int j = 0; j < tableInfo.columnCount; j++) { + + if ( !getAccessibleTableCellInfo( vmID, + tableInfo.accessibleTable, + i, j, + &tableCellInfo ) ) { + + appendToBuffer( + buffer, bufsize, + "\r\nERROR: GetAccessibleTableCellInfo failed.", + bufsize ); + } else { + appendToBuffer( buffer, bufsize, + "\r\n\r\n AccessibleTable cell[%d,%d] info:", + i, j ); + appendToBuffer( buffer, bufsize, + "\r\n Index: %ld", tableCellInfo.index ); + appendToBuffer( buffer, bufsize, + "\r\n Row extent: %ld", + tableCellInfo.rowExtent ); + appendToBuffer( buffer, bufsize, + "\r\n Column extent: %ld", + tableCellInfo.columnExtent ); + appendToBuffer( buffer, bufsize, + "\r\n Is selected?: %ld", + tableCellInfo.isSelected ); + + AccessibleContextInfo cellACInfo; + if ( !GetAccessibleContextInfo( + vmID, + tableCellInfo.accessibleContext, + &cellACInfo ) ) { + appendToBuffer( buffer, bufsize, + "\r\nERROR: GetAccessibleContextInfo failed for table cell [%d,%d].", + i, j ); + } else { + if ( !getVirtualAccessibleName( vmID, + tableCellInfo.accessibleContext, name, + (sizeof(name) / sizeof(wchar_t)) ) ) { + appendToBuffer( buffer, bufsize, + "\r\n\r\nERROR: getVirtualAccessibleName", + bufsize ); + } else { + appendToBuffer( buffer, bufsize, + "\r\n Name: %ls", name ); + } + appendToBuffer( buffer, bufsize, + "\r\n Role: %ls", + cellACInfo.role ); + } + ReleaseJavaObject( vmID, + tableCellInfo.accessibleContext ); + } + } + } + + // Get the column headers + AccessibleTableInfo columnInfo; + if ( !getAccessibleTableColumnHeader(vmID, ac, &columnInfo)) { + appendToBuffer( buffer, bufsize, + "\r\nERROR: getAccessibleTableColumnHeader failed.", + bufsize ); + } else { + appendToBuffer( buffer, bufsize, + "\r\n\r\nAccessibleTable column header info:", bufsize ); + + // Core info + appendToBuffer( buffer, bufsize, + "\r\n Column header row count: %d", + columnInfo.rowCount ); + appendToBuffer( buffer, bufsize, + "\r\n Column header column count: %d", + columnInfo.columnCount ); + + } + + // Get the selected rows + int numSelections = + getAccessibleTableRowSelectionCount( vmID, + tableInfo.accessibleTable ); + appendToBuffer( buffer, bufsize, + "\r\n\r\nRow selection count: %d", + numSelections ); + jint *selections = new jint[numSelections]; + + if ( !getAccessibleTableRowSelections( vmID, + tableInfo.accessibleTable, + numSelections, + selections ) ) { + appendToBuffer( buffer, bufsize, + "\r\nERROR: getAccessibleTableRowSelections failed.", + bufsize ); + } else { + appendToBuffer(buffer, bufsize, " \r\n Row selections: "); + for (int j = 0; j < numSelections; j++) { + appendToBuffer(buffer, bufsize, " %d", selections[j]); + } + } + + // Get column header info + for (int i = 0; i < columnInfo.columnCount; i++) { + if ( !getAccessibleTableCellInfo( vmID, + columnInfo.accessibleTable, + 0, i, &tableCellInfo ) ) { + + appendToBuffer( buffer, bufsize, + "\r\nERROR: GetAccessibleTableCellInfo failed.", + bufsize ); + } else { + appendToBuffer( buffer, bufsize, + "\r\n\r\nColumn header [0,%d] cell info.", i ); + appendToBuffer( buffer, bufsize, + "\r\n Index: %ld", tableCellInfo.index ); + appendToBuffer( buffer, bufsize, + "\r\n Row extent: %ld", + tableCellInfo.rowExtent ); + appendToBuffer( buffer, bufsize, + "\r\n Column extent: %ld", + tableCellInfo.columnExtent ); + appendToBuffer( buffer, bufsize, + "\r\n Is selected: %ld", + tableCellInfo.isSelected ); + + AccessibleContextInfo cellACInfo; + if ( !GetAccessibleContextInfo( vmID, + tableCellInfo.accessibleContext, &cellACInfo ) ) { + appendToBuffer( buffer, bufsize, + "\r\nERROR: GetAccessibleContextInfo failed.", + bufsize ); + } else { + if ( !getVirtualAccessibleName( vmID, + tableCellInfo.accessibleContext, name, + (sizeof(name) / sizeof(wchar_t)) ) ) { + appendToBuffer( buffer, bufsize, + "\r\n\r\nERROR: getVirtualAccessibleName", + bufsize ); + } else { + appendToBuffer( buffer, bufsize, + "\r\n Name: %ls", name ); + } + appendToBuffer( buffer, bufsize, + "\r\n Role: %ls", cellACInfo.role ); + } + ReleaseJavaObject(vmID, tableCellInfo.accessibleContext); + } + } + } + } + + /* ===== AccessibleText ===== */ + + if (info.accessibleText == TRUE) { + AccessibleTextInfo textInfo; + AccessibleTextItemsInfo textItems; + AccessibleTextSelectionInfo textSelection; + AccessibleTextRectInfo rectInfo; + AccessibleTextAttributesInfo attributeInfo; + + appendToBuffer( buffer, bufsize, + "\r\n\r\nAccessible Text information:", bufsize); + + if (GetAccessibleTextInfo(vmID, ac, &textInfo, x, y) == TRUE) { + appendToBuffer( buffer, bufsize, + "\r\n Mouse point at text index: %d", + textInfo.indexAtPoint ); + appendToBuffer( buffer, bufsize, + "\r\n Caret at text index: %d", + textInfo.caretIndex ); + appendToBuffer( buffer, bufsize, + "\r\n Char count: %d", + textInfo.charCount ); + } + if ( GetAccessibleTextSelectionInfo(vmID, ac, &textSelection) ) { + + appendToBuffer( buffer, bufsize, + "\r\n Selection start index: %d", + textSelection.selectionStartIndex ); + appendToBuffer( buffer, bufsize, + "\r\n Selection end index: %d", + textSelection.selectionEndIndex ); + appendToBuffer( buffer, bufsize, + "\r\n Selected text: %ls", + textSelection.selectedText ); + } + + /* ===== AccessibleText information at the mouse point ===== */ + + appendToBuffer( buffer, bufsize, + "\r\n\r\n At mouse point index: %d", textInfo.indexAtPoint); + + if (GetAccessibleTextRect(vmID, ac, &rectInfo, textInfo.indexAtPoint)) { + + appendToBuffer( buffer, bufsize, + "\r\n Character bounding rectangle: [%d, %d, %d, %d]", + rectInfo.x, rectInfo.y, rectInfo.width, rectInfo.height ); + } + + if ( GetAccessibleTextLineBounds( vmID, ac, textInfo.indexAtPoint, + &start, &end ) ) { + if ( GetAccessibleTextRange( vmID, ac, start, end, tmpBuf, + (sizeof(tmpBuf) / sizeof(wchar_t)) ) ) { + appendToBuffer( buffer, bufsize, + "\r\n Line bounds: [%d, %d]", start, end); + } + } + if ( GetAccessibleTextItems( vmID, ac, &textItems, + textInfo.indexAtPoint ) ) { + + appendToBuffer( buffer, bufsize, + "\r\n Character: %lc", textItems.letter ); + appendToBuffer( buffer, bufsize, + "\r\n Word: %ls", textItems.word ); + appendToBuffer( buffer, bufsize, + "\r\n Sentence: %ls", textItems.sentence ); + } + + /* ===== AccessibleText attributes ===== */ + + if (GetAccessibleTextAttributes(vmID, ac, + textInfo.indexAtPoint, + &attributeInfo)) { + + appendToBuffer( buffer, bufsize, "\r\n Core attributes: %s", + attributeInfo.bold ? "bold" : "not bold" ); + appendToBuffer( buffer, bufsize, ", %s", + attributeInfo.italic ? "italic" : "not italic" ); + appendToBuffer( buffer, bufsize, ", %s", + attributeInfo.underline ? "underline" : "not underline" ); + appendToBuffer( buffer, bufsize, ", %s", + attributeInfo.strikethrough ? "strikethrough" : + "not strikethrough" ); + appendToBuffer( buffer, bufsize, ", %s", + attributeInfo.superscript ? "superscript" : + "not superscript" ); + appendToBuffer( buffer, bufsize, ", %s", + attributeInfo.subscript ? "subscript" : "not subscript" ); + + appendToBuffer( buffer, bufsize, + "\r\n Background color: %ls", + attributeInfo.backgroundColor ); + appendToBuffer( buffer, bufsize, + "\r\n Foreground color: %ls", + attributeInfo.foregroundColor ); + appendToBuffer( buffer, bufsize, + "\r\n Font family: %ls", + attributeInfo.fontFamily ); + appendToBuffer( buffer, bufsize, + "\r\n Font size: %d", + attributeInfo.fontSize ); + + appendToBuffer( buffer, bufsize, + "\r\n First line indent: %f", + attributeInfo.firstLineIndent ); + appendToBuffer( buffer, bufsize, + "\r\n Left indent: %f", + attributeInfo.leftIndent ); + appendToBuffer( buffer, bufsize, + "\r\n Right indent: %f", + attributeInfo.rightIndent ); + appendToBuffer( buffer, bufsize, + "\r\n Line spacing: %f", + attributeInfo.lineSpacing ); + appendToBuffer( buffer, bufsize, + "\r\n Space above: %f", + attributeInfo.spaceAbove ); + appendToBuffer( buffer, bufsize, + "\r\n Space below: %f", + attributeInfo.spaceBelow ); + + appendToBuffer( buffer, bufsize, + "\r\n Full attribute string: %ls", + attributeInfo.fullAttributesString ); + + // get the attribute run length + short runLength = -1; + if ( getTextAttributesInRange( vmID, ac, textInfo.indexAtPoint, + textInfo.indexAtPoint + 100, + &attributeInfo, &runLength ) ) { + appendToBuffer( buffer, bufsize, + "\r\n Attribute run: %d", runLength ); + } else { + appendToBuffer( buffer, bufsize, + "\r\n getTextAttributesInRangeFailed" ); + } + } + + /* ===== AccessibleText information at the caret index ===== */ + + appendToBuffer( buffer, bufsize, + "\r\n\r\n At caret index: %d", textInfo.caretIndex); + + if (getCaretLocation(vmID, ac, &rectInfo, textInfo.caretIndex)) { + appendToBuffer( buffer, bufsize, + "\r\n Caret bounding rectangle: [%d, %d, %d, %d]", + rectInfo.x, rectInfo.y, rectInfo.width, rectInfo.height ); + } + + if (GetAccessibleTextRect(vmID, ac, &rectInfo, textInfo.caretIndex)) { + + appendToBuffer( buffer, bufsize, + "\r\n Character bounding rectangle: [%d, %d, %d, %d]", + rectInfo.x, rectInfo.y, rectInfo.width, rectInfo.height ); + } + + if ( GetAccessibleTextLineBounds( vmID, ac, textInfo.caretIndex, + &start, &end ) ) { + if ( GetAccessibleTextRange( vmID, ac, start, end, tmpBuf, + (sizeof(tmpBuf) / sizeof(wchar_t)) ) ) { + + appendToBuffer( buffer, bufsize, + "\r\n Line bounds: [%d, %d]", start, end); + } + } + if (GetAccessibleTextItems(vmID, ac, &textItems, textInfo.caretIndex)) { + + appendToBuffer( buffer, bufsize, + "\r\n Character: %lc", textItems.letter ); + appendToBuffer( buffer, bufsize, + "\r\n Word: %ls", textItems.word ); + appendToBuffer( buffer, bufsize, + "\r\n Sentence: %ls", textItems.sentence ); + } + + /* ===== AccessibleText attributes ===== */ + + if (GetAccessibleTextAttributes(vmID, ac, textInfo.caretIndex, &attributeInfo)) { + + appendToBuffer( buffer, bufsize, "\r\n Core attributes: %s", + attributeInfo.bold ? "bold" : "not bold" ); + appendToBuffer( buffer, bufsize, ", %s", + attributeInfo.italic ? "italic" : "not italic" ); + appendToBuffer( buffer, bufsize, ", %s", + attributeInfo.underline ? "underline" : "not underline" ); + appendToBuffer( buffer, bufsize, ", %s", + attributeInfo.strikethrough ? "strikethrough" : + "not strikethrough" ); + appendToBuffer( buffer, bufsize, ", %s", + attributeInfo.superscript ? "superscript" : + "not superscript" ); + appendToBuffer( buffer, bufsize, ", %s", + attributeInfo.subscript ? "subscript" : "not subscript"); + + appendToBuffer( buffer, bufsize, + "\r\n Background color: %ls", + attributeInfo.backgroundColor ); + appendToBuffer( buffer, bufsize, + "\r\n Foreground color: %ls", + attributeInfo.foregroundColor ); + appendToBuffer( buffer, bufsize, + "\r\n Font family: %ls", attributeInfo.fontFamily ); + appendToBuffer( buffer, bufsize, + "\r\n Font size: %d", attributeInfo.fontSize); + + + appendToBuffer( buffer, bufsize, + "\r\n First line indent: %f", + attributeInfo.firstLineIndent ); + appendToBuffer( buffer, bufsize, + "\r\n Left indent: %f", attributeInfo.leftIndent ); + appendToBuffer( buffer, bufsize, + "\r\n Right indent: %f", attributeInfo.rightIndent ); + appendToBuffer( buffer, bufsize, + "\r\n Line spacing: %f", attributeInfo.lineSpacing ); + appendToBuffer( buffer, bufsize, + "\r\n Space above: %f", attributeInfo.spaceAbove ); + appendToBuffer( buffer, bufsize, + "\r\n Space below: %f", attributeInfo.spaceBelow ); + appendToBuffer( buffer, bufsize, + "\r\n Full attribute string: %ls", + attributeInfo.fullAttributesString ); + // get the attribute run length + short runLength = -1; + if ( getTextAttributesInRange( vmID, ac, textInfo.caretIndex, + textInfo.caretIndex + 100, + &attributeInfo, &runLength ) ) { + appendToBuffer( buffer, bufsize, + "\r\n Attribute run: %d", runLength); + } else { + appendToBuffer( buffer, bufsize, + "\r\n getTextAttributesInRangeFailed" ); + } + } + } + } + return buffer; +} diff --git a/jdk/src/jdk.accessibility/windows/native/toolscommon/AccessInfo.h b/jdk/src/jdk.accessibility/windows/native/toolscommon/AccessInfo.h new file mode 100644 index 00000000000..a749ebc9784 --- /dev/null +++ b/jdk/src/jdk.accessibility/windows/native/toolscommon/AccessInfo.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +typedef void (WINAPI * LogStringCallbackFP) (const char * lpString); +extern LogStringCallbackFP g_LogStringCallback; + +#define LINE_BUFSIZE 1024 +#define LARGE_BUFSIZE 5120 +#define HUGE_BUFSIZE 20480 + +/* + * returns formatted date and time + */ +char *getTimeAndDate(); + +/* + * displays a message in a dialog and writes the message to a logfile + */ +void displayAndLog(HWND hDlg, int nIDDlgItem, FILE *logfile, char *msg, ...); + +/* + * writes a text string to a logfile + */ +void logString(FILE *logfile, char *msg, ...); + +/** + * returns accessibility information for an AccessibleContext + */ +char *getAccessibleInfo(long vmID, AccessibleContext ac, char *buffer, int bufsize); + +/** + * returns accessibility information at the specified coordinates in an AccessibleContext + */ +char *getAccessibleInfo(long vmID, AccessibleContext ac, int x, int y, char *buffer, int bufsize); From 08c1fe55c0fdf99fb6dc309e213839e4d0f3798e Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sun, 22 Nov 2015 17:27:33 +0300 Subject: [PATCH 134/260] 8135100: Behavior of null arguments not specified in javax.sound.sampled.spi The specification change was reviewed by Florian Bomers also Reviewed-by: amenkov --- .../com/sun/media/sound/AiffFileWriter.java | 9 +- .../com/sun/media/sound/AlawCodec.java | 4 +- .../com/sun/media/sound/AuFileWriter.java | 9 +- .../sound/AudioFloatFormatConverter.java | 6 +- .../sound/DirectAudioDeviceProvider.java | 5 +- .../com/sun/media/sound/PCMtoPCMCodec.java | 4 +- .../sun/media/sound/PortMixerProvider.java | 7 +- .../com/sun/media/sound/UlawCodec.java | 5 +- .../com/sun/media/sound/WaveFileWriter.java | 9 +- .../javax/sound/sampled/AudioSystem.java | 123 +++--- .../sound/sampled/spi/AudioFileReader.java | 6 + .../sound/sampled/spi/AudioFileWriter.java | 14 +- .../sampled/spi/FormatConversionProvider.java | 25 +- .../sound/sampled/spi/MixerProvider.java | 16 +- .../AudioFileReader}/AudioFileClose.java | 0 .../AudioFileReader/ExpectedNPEOnNull.java | 120 ++++++ .../AudioFileReader}/ReadersExceptions.java | 0 .../RepeatedFormatReader.java | 0 .../AudioFileWriter}/AlawEncoderSync.java | 0 .../AudioFileWriter/ExpectedNPEOnNull.java | 310 +++++++++++++++ .../AudioFileWriter}/WriterCloseInput.java | 0 .../ExpectedNPEOnNull.java | 356 ++++++++++++++++++ .../spi/MixerProvider/ExpectedNPEOnNull.java | 88 +++++ 23 files changed, 1040 insertions(+), 76 deletions(-) rename jdk/test/javax/sound/sampled/{FileReader => spi/AudioFileReader}/AudioFileClose.java (100%) create mode 100644 jdk/test/javax/sound/sampled/spi/AudioFileReader/ExpectedNPEOnNull.java rename jdk/test/javax/sound/sampled/{FileReader => spi/AudioFileReader}/ReadersExceptions.java (100%) rename jdk/test/javax/sound/sampled/{FileReader => spi/AudioFileReader}/RepeatedFormatReader.java (100%) rename jdk/test/javax/sound/sampled/{FileWriter => spi/AudioFileWriter}/AlawEncoderSync.java (100%) create mode 100644 jdk/test/javax/sound/sampled/spi/AudioFileWriter/ExpectedNPEOnNull.java rename jdk/test/javax/sound/sampled/{FileWriter => spi/AudioFileWriter}/WriterCloseInput.java (100%) create mode 100644 jdk/test/javax/sound/sampled/spi/FormatConversionProvider/ExpectedNPEOnNull.java create mode 100644 jdk/test/javax/sound/sampled/spi/MixerProvider/ExpectedNPEOnNull.java diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java index b31871f3bb5..5e9e3c45cce 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.RandomAccessFile; import java.io.SequenceInputStream; +import java.util.Objects; import javax.sound.sampled.AudioFileFormat; import javax.sound.sampled.AudioInputStream; @@ -84,6 +85,9 @@ public final class AiffFileWriter extends SunFileWriter { public int write(AudioInputStream stream, AudioFileFormat.Type fileType, OutputStream out) throws IOException { + Objects.requireNonNull(stream); + Objects.requireNonNull(fileType); + Objects.requireNonNull(out); //$$fb the following check must come first ! Otherwise // the next frame length check may throw an IOException and @@ -103,6 +107,9 @@ public final class AiffFileWriter extends SunFileWriter { public int write(AudioInputStream stream, AudioFileFormat.Type fileType, File out) throws IOException { + Objects.requireNonNull(stream); + Objects.requireNonNull(fileType); + Objects.requireNonNull(out); // throws IllegalArgumentException if not supported AiffFileFormat aiffFileFormat = (AiffFileFormat)getAudioFileFormat(fileType, stream); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java index fbe63f6ff16..fcc0e709f2b 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package com.sun.media.sound; import java.io.IOException; +import java.util.Objects; import java.util.Vector; import javax.sound.sampled.AudioFormat; @@ -119,6 +120,7 @@ public final class AlawCodec extends SunCodec { /** */ public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat){ + Objects.requireNonNull(sourceFormat); if( (targetEncoding.equals( AudioFormat.Encoding.PCM_SIGNED ) && sourceFormat.getEncoding().equals( AudioFormat.Encoding.ALAW)) || (targetEncoding.equals( AudioFormat.Encoding.ALAW) && sourceFormat.getEncoding().equals( AudioFormat.Encoding.PCM_SIGNED)) ) { return getOutputFormats( sourceFormat ); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AuFileWriter.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AuFileWriter.java index 3020c348953..1c2ccf5b74c 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AuFileWriter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AuFileWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.RandomAccessFile; import java.io.SequenceInputStream; +import java.util.Objects; import javax.sound.sampled.AudioFileFormat; import javax.sound.sampled.AudioInputStream; @@ -83,6 +84,9 @@ public final class AuFileWriter extends SunFileWriter { public int write(AudioInputStream stream, AudioFileFormat.Type fileType, OutputStream out) throws IOException { + Objects.requireNonNull(stream); + Objects.requireNonNull(fileType); + Objects.requireNonNull(out); // we must know the total data length to calculate the file length //$$fb 2001-07-13: fix for bug 4351296: do not throw an exception @@ -100,6 +104,9 @@ public final class AuFileWriter extends SunFileWriter { public int write(AudioInputStream stream, AudioFileFormat.Type fileType, File out) throws IOException { + Objects.requireNonNull(stream); + Objects.requireNonNull(fileType); + Objects.requireNonNull(out); // throws IllegalArgumentException if not supported AuFileFormat auFileFormat = (AuFileFormat)getAudioFileFormat(fileType, stream); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java index a161fc5db42..a1e522afb40 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AudioFloatFormatConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Objects; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; @@ -538,6 +539,7 @@ public final class AudioFloatFormatConverter extends FormatConversionProvider { public AudioFormat[] getTargetFormats(Encoding targetEncoding, AudioFormat sourceFormat) { + Objects.requireNonNull(targetEncoding); if (AudioFloatConverter.getConverter(sourceFormat) == null) return new AudioFormat[0]; int channels = sourceFormat.getChannels(); @@ -592,6 +594,7 @@ public final class AudioFloatFormatConverter extends FormatConversionProvider { public boolean isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat) { + Objects.requireNonNull(targetFormat); if (AudioFloatConverter.getConverter(sourceFormat) == null) return false; if (AudioFloatConverter.getConverter(targetFormat) == null) @@ -605,6 +608,7 @@ public final class AudioFloatFormatConverter extends FormatConversionProvider { public boolean isConversionSupported(Encoding targetEncoding, AudioFormat sourceFormat) { + Objects.requireNonNull(targetEncoding); if (AudioFloatConverter.getConverter(sourceFormat) == null) return false; for (int i = 0; i < formats.length; i++) { diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDeviceProvider.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDeviceProvider.java index c306dc78c66..274571917ea 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDeviceProvider.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDeviceProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -121,7 +121,8 @@ public final class DirectAudioDeviceProvider extends MixerProvider { } } } - throw new IllegalArgumentException("Mixer " + info.toString() + " not supported by this provider."); + throw new IllegalArgumentException( + String.format("Mixer %s not supported by this provider", info)); } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/PCMtoPCMCodec.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/PCMtoPCMCodec.java index dbed920e6fa..6ef8268f34c 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/PCMtoPCMCodec.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/PCMtoPCMCodec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package com.sun.media.sound; import java.io.IOException; +import java.util.Objects; import java.util.Vector; import javax.sound.sampled.AudioFormat; @@ -87,6 +88,7 @@ public final class PCMtoPCMCodec extends SunCodec { /** */ public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat){ + Objects.requireNonNull(targetEncoding); // filter out targetEncoding from the old getOutputFormats( sourceFormat ) method diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/PortMixerProvider.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/PortMixerProvider.java index a8ef40f8a0f..ce7f3596a48 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/PortMixerProvider.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/PortMixerProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,7 +101,6 @@ public final class PortMixerProvider extends MixerProvider { } } - public Mixer getMixer(Mixer.Info info) { synchronized (PortMixerProvider.class) { for (int i = 0; i < infos.length; i++) { @@ -110,8 +109,8 @@ public final class PortMixerProvider extends MixerProvider { } } } - throw new IllegalArgumentException("Mixer " + info.toString() - + " not supported by this provider."); + throw new IllegalArgumentException( + String.format("Mixer %s not supported by this provider", info)); } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/UlawCodec.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/UlawCodec.java index 5dde45b734b..dc088ee459c 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/UlawCodec.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/UlawCodec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ package com.sun.media.sound; import java.io.IOException; +import java.util.Objects; import java.util.Vector; import javax.sound.sampled.AudioFormat; @@ -106,6 +107,8 @@ public final class UlawCodec extends SunCodec { /** */ public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat){ + Objects.requireNonNull(targetEncoding); + Objects.requireNonNull(sourceFormat); if( (AudioFormat.Encoding.PCM_SIGNED.equals(targetEncoding) && AudioFormat.Encoding.ULAW.equals(sourceFormat.getEncoding())) || diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveFileWriter.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveFileWriter.java index b9becd23d5a..199364c94f4 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveFileWriter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveFileWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.RandomAccessFile; import java.io.SequenceInputStream; +import java.util.Objects; import javax.sound.sampled.AudioFileFormat; import javax.sound.sampled.AudioInputStream; @@ -106,6 +107,9 @@ public final class WaveFileWriter extends SunFileWriter { public int write(AudioInputStream stream, AudioFileFormat.Type fileType, OutputStream out) throws IOException { + Objects.requireNonNull(stream); + Objects.requireNonNull(fileType); + Objects.requireNonNull(out); //$$fb the following check must come first ! Otherwise // the next frame length check may throw an IOException and @@ -127,6 +131,9 @@ public final class WaveFileWriter extends SunFileWriter { public int write(AudioInputStream stream, AudioFileFormat.Type fileType, File out) throws IOException { + Objects.requireNonNull(stream); + Objects.requireNonNull(fileType); + Objects.requireNonNull(out); // throws IllegalArgumentException if not supported WaveFileFormat waveFileFormat = (WaveFileFormat)getAudioFileFormat(fileType, stream); diff --git a/jdk/src/java.desktop/share/classes/javax/sound/sampled/AudioSystem.java b/jdk/src/java.desktop/share/classes/javax/sound/sampled/AudioSystem.java index bb5e72666ba..2a6d98dd158 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/sampled/AudioSystem.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/sampled/AudioSystem.java @@ -33,6 +33,7 @@ import java.net.URL; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Properties; import java.util.Set; import java.util.Vector; @@ -191,50 +192,21 @@ public class AudioSystem { * mixer installed on the system * @see #getMixerInfo */ - public static Mixer getMixer(Mixer.Info info) { - - Mixer mixer = null; - List providers = getMixerProviders(); - - for(int i = 0; i < providers.size(); i++ ) { - + public static Mixer getMixer(final Mixer.Info info) { + for (final MixerProvider provider : getMixerProviders()) { try { - return providers.get(i).getMixer(info); - - } catch (IllegalArgumentException e) { - } catch (NullPointerException e) { - // $$jb 08.20.99: If the strings in the info object aren't - // set, then Netscape (using jdk1.1.5) tends to throw - // NPE's when doing some string manipulation. This is - // probably not the best fix, but is solves the problem - // of the NPE in Netscape using local classes - // $$jb 11.01.99: Replacing this patch. + return provider.getMixer(info); + } catch (IllegalArgumentException | NullPointerException ignored) { + // The MixerProvider.getMixer(null) should return default Mixer, + // This behaviour was assumed from the beginning, but strictly + // specified only in the jdk9. Since the jdk1.1.5 we skipped + // NPE for some reason and therefore skipped some + // implementations of MixerProviders, which throw NPE. To keep + // support of such implementations, we still ignore NPE. } } - - //$$fb if looking for default mixer, and not found yet, add a round of looking - if (info == null) { - for(int i = 0; i < providers.size(); i++ ) { - try { - MixerProvider provider = providers.get(i); - Mixer.Info[] infos = provider.getMixerInfo(); - // start from 0 to last device (do not reverse this order) - for (int ii = 0; ii < infos.length; ii++) { - try { - return provider.getMixer(infos[ii]); - } catch (IllegalArgumentException e) { - // this is not a good default device :) - } - } - } catch (IllegalArgumentException e) { - } catch (NullPointerException e) { - } - } - } - - - throw new IllegalArgumentException("Mixer not supported: " - + (info!=null?info.toString():"null")); + throw new IllegalArgumentException( + String.format("Mixer not supported: %s", info)); } //$$fb 2002-11-26: fix for 4757930: DOC: AudioSystem.getTarget/SourceLineInfo() is ambiguous @@ -696,8 +668,10 @@ public class AudioSystem { * array of length 0 is returned. Otherwise, the array will have a * length of at least 1, representing {@code sourceEncoding} * (no conversion). + * @throws NullPointerException if {@code sourceEncoding} is {@code null} */ public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat.Encoding sourceEncoding) { + Objects.requireNonNull(sourceEncoding); List codecs = getFormatConversionProviders(); Vector encodings = new Vector<>(); @@ -730,9 +704,10 @@ public class AudioSystem { * array of length 0 is returned. Otherwise, the array will have a * length of at least 1, representing the encoding of * {@code sourceFormat} (no conversion). + * @throws NullPointerException if {@code sourceFormat} is {@code null} */ public static AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat) { - + Objects.requireNonNull(sourceFormat); List codecs = getFormatConversionProviders(); Vector encodings = new Vector<>(); @@ -769,9 +744,12 @@ public class AudioSystem { * @param sourceFormat the audio format before conversion * @return {@code true} if the conversion is supported, otherwise * {@code false} + * @throws NullPointerException if {@code targetEncoding} or + * {@code sourceFormat} are {@code null} */ public static boolean isConversionSupported(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) { - + Objects.requireNonNull(targetEncoding); + Objects.requireNonNull(sourceFormat); List codecs = getFormatConversionProviders(); @@ -792,6 +770,8 @@ public class AudioSystem { * @param sourceStream the stream to be converted * @return an audio input stream of the indicated encoding * @throws IllegalArgumentException if the conversion is not supported + * @throws NullPointerException if {@code targetEncoding} or + * {@code sourceStream} are {@code null} * @see #getTargetEncodings(AudioFormat.Encoding) * @see #getTargetEncodings(AudioFormat) * @see #isConversionSupported(AudioFormat.Encoding, AudioFormat) @@ -799,6 +779,8 @@ public class AudioSystem { */ public static AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding, AudioInputStream sourceStream) { + Objects.requireNonNull(targetEncoding); + Objects.requireNonNull(sourceStream); List codecs = getFormatConversionProviders(); @@ -821,8 +803,12 @@ public class AudioSystem { * @param sourceFormat the audio format before conversion * @return array of formats. If no formats of the specified encoding are * supported, an array of length 0 is returned. + * @throws NullPointerException if {@code targetEncoding} or + * {@code sourceFormat} are {@code null} */ public static AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) { + Objects.requireNonNull(targetEncoding); + Objects.requireNonNull(sourceFormat); List codecs = getFormatConversionProviders(); Vector formats = new Vector<>(); @@ -860,8 +846,12 @@ public class AudioSystem { * @param sourceFormat the audio format before conversion * @return {@code true} if the conversion is supported, otherwise * {@code false} + * @throws NullPointerException if {@code targetFormat} or + * {@code sourceFormat} are {@code null} */ public static boolean isConversionSupported(AudioFormat targetFormat, AudioFormat sourceFormat) { + Objects.requireNonNull(targetFormat); + Objects.requireNonNull(sourceFormat); List codecs = getFormatConversionProviders(); @@ -882,6 +872,8 @@ public class AudioSystem { * @param sourceStream the stream to be converted * @return an audio input stream of the indicated format * @throws IllegalArgumentException if the conversion is not supported + * @throws NullPointerException if {@code targetFormat} or + * {@code sourceStream} are {@code null} * @see #getTargetEncodings(AudioFormat) * @see #getTargetFormats(AudioFormat.Encoding, AudioFormat) * @see #isConversionSupported(AudioFormat, AudioFormat) @@ -889,7 +881,6 @@ public class AudioSystem { */ public static AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream sourceStream) { - if (sourceStream.getFormat().matches(targetFormat)) { return sourceStream; } @@ -924,11 +915,13 @@ public class AudioSystem { * @throws UnsupportedAudioFileException if the stream does not point to * valid audio file data recognized by the system * @throws IOException if an input/output exception occurs + * @throws NullPointerException if {@code stream} is {@code null} * @see InputStream#markSupported * @see InputStream#mark */ public static AudioFileFormat getAudioFileFormat(InputStream stream) - throws UnsupportedAudioFileException, IOException { + throws UnsupportedAudioFileException, IOException { + Objects.requireNonNull(stream); List providers = getAudioFileReaders(); AudioFileFormat format = null; @@ -961,9 +954,11 @@ public class AudioSystem { * @throws UnsupportedAudioFileException if the URL does not point to valid * audio file data recognized by the system * @throws IOException if an input/output exception occurs + * @throws NullPointerException if {@code url} is {@code null} */ public static AudioFileFormat getAudioFileFormat(URL url) - throws UnsupportedAudioFileException, IOException { + throws UnsupportedAudioFileException, IOException { + Objects.requireNonNull(url); List providers = getAudioFileReaders(); AudioFileFormat format = null; @@ -996,9 +991,11 @@ public class AudioSystem { * @throws UnsupportedAudioFileException if the {@code File} does not point * to valid audio file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code file} is {@code null} */ public static AudioFileFormat getAudioFileFormat(File file) - throws UnsupportedAudioFileException, IOException { + throws UnsupportedAudioFileException, IOException { + Objects.requireNonNull(file); List providers = getAudioFileReaders(); AudioFileFormat format = null; @@ -1037,11 +1034,13 @@ public class AudioSystem { * @throws UnsupportedAudioFileException if the stream does not point to * valid audio file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code stream} is {@code null} * @see InputStream#markSupported * @see InputStream#mark */ public static AudioInputStream getAudioInputStream(InputStream stream) - throws UnsupportedAudioFileException, IOException { + throws UnsupportedAudioFileException, IOException { + Objects.requireNonNull(stream); List providers = getAudioFileReaders(); AudioInputStream audioStream = null; @@ -1074,9 +1073,11 @@ public class AudioSystem { * @throws UnsupportedAudioFileException if the URL does not point to valid * audio file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code url} is {@code null} */ public static AudioInputStream getAudioInputStream(URL url) - throws UnsupportedAudioFileException, IOException { + throws UnsupportedAudioFileException, IOException { + Objects.requireNonNull(url); List providers = getAudioFileReaders(); AudioInputStream audioStream = null; @@ -1109,9 +1110,11 @@ public class AudioSystem { * @throws UnsupportedAudioFileException if the {@code File} does not point * to valid audio file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code file} is {@code null} */ public static AudioInputStream getAudioInputStream(File file) - throws UnsupportedAudioFileException, IOException { + throws UnsupportedAudioFileException, IOException { + Objects.requireNonNull(file); List providers = getAudioFileReaders(); AudioInputStream audioStream = null; @@ -1163,9 +1166,10 @@ public class AudioSystem { * @param fileType the file type for which write capabilities are queried * @return {@code true} if the file type is supported, otherwise * {@code false} + * @throws NullPointerException if {@code fileType} is {@code null} */ public static boolean isFileTypeSupported(AudioFileFormat.Type fileType) { - + Objects.requireNonNull(fileType); List providers = getAudioFileWriters(); for(int i=0; i < providers.size(); i++) { @@ -1185,8 +1189,10 @@ public class AudioSystem { * support is queried * @return array of file types. If no file types are supported, an array of * length 0 is returned. + * @throws NullPointerException if {@code stream} is {@code null} */ public static AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream) { + Objects.requireNonNull(stream); List providers = getAudioFileWriters(); Set returnTypesSet = new HashSet<>(); @@ -1210,10 +1216,13 @@ public class AudioSystem { * @param stream the stream for which file-writing support is queried * @return {@code true} if the file type is supported for this audio input * stream, otherwise {@code false} + * @throws NullPointerException if {@code fileType} or {@code stream} are + * {@code null} */ public static boolean isFileTypeSupported(AudioFileFormat.Type fileType, AudioInputStream stream) { - + Objects.requireNonNull(fileType); + Objects.requireNonNull(stream); List providers = getAudioFileWriters(); for(int i=0; i < providers.size(); i++) { @@ -1241,11 +1250,16 @@ public class AudioSystem { * @throws IOException if an input/output exception occurs * @throws IllegalArgumentException if the file type is not supported by the * system + * @throws NullPointerException if {@code stream} or {@code fileType} or + * {@code out} are {@code null} * @see #isFileTypeSupported * @see #getAudioFileTypes */ public static int write(AudioInputStream stream, AudioFileFormat.Type fileType, OutputStream out) throws IOException { + Objects.requireNonNull(stream); + Objects.requireNonNull(fileType); + Objects.requireNonNull(out); List providers = getAudioFileWriters(); int bytesWritten = 0; @@ -1281,11 +1295,16 @@ public class AudioSystem { * @throws IOException if an I/O exception occurs * @throws IllegalArgumentException if the file type is not supported by the * system + * @throws NullPointerException if {@code stream} or {@code fileType} or + * {@code out} are {@code null} * @see #isFileTypeSupported * @see #getAudioFileTypes */ public static int write(AudioInputStream stream, AudioFileFormat.Type fileType, File out) throws IOException { + Objects.requireNonNull(stream); + Objects.requireNonNull(fileType); + Objects.requireNonNull(out); List providers = getAudioFileWriters(); int bytesWritten = 0; diff --git a/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileReader.java b/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileReader.java index 7df8f998bc9..f130dba477f 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileReader.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileReader.java @@ -60,6 +60,7 @@ public abstract class AudioFileReader { * @throws UnsupportedAudioFileException if the stream does not point to * valid audio file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code stream} is {@code null} * @see InputStream#markSupported * @see InputStream#mark */ @@ -77,6 +78,7 @@ public abstract class AudioFileReader { * @throws UnsupportedAudioFileException if the URL does not point to valid * audio file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code url} is {@code null} */ public abstract AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException; @@ -92,6 +94,7 @@ public abstract class AudioFileReader { * @throws UnsupportedAudioFileException if the {@code File} does not point * to valid audio file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code file} is {@code null} */ public abstract AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException; @@ -112,6 +115,7 @@ public abstract class AudioFileReader { * @throws UnsupportedAudioFileException if the stream does not point to * valid audio file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code stream} is {@code null} * @see InputStream#markSupported * @see InputStream#mark */ @@ -129,6 +133,7 @@ public abstract class AudioFileReader { * @throws UnsupportedAudioFileException if the URL does not point to valid * audio file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code url} is {@code null} */ public abstract AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException; @@ -144,6 +149,7 @@ public abstract class AudioFileReader { * @throws UnsupportedAudioFileException if the {@code File} does not point * to valid audio file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code file} is {@code null} */ public abstract AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException; diff --git a/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileWriter.java b/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileWriter.java index 03a44bbc084..7ce970b2508 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileWriter.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ package javax.sound.sampled.spi; import java.io.File; import java.io.IOException; import java.io.OutputStream; +import java.util.Objects; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; @@ -60,8 +61,10 @@ public abstract class AudioFileWriter { * @param fileType the file type for which write capabilities are queried * @return {@code true} if the file type is supported, otherwise * {@code false} + * @throws NullPointerException if {@code fileType} is {@code null} */ public boolean isFileTypeSupported(Type fileType) { + Objects.requireNonNull(fileType); Type types[] = getAudioFileTypes(); @@ -81,6 +84,7 @@ public abstract class AudioFileWriter { * is queried * @return array of file types. If no file types are supported, an array of * length 0 is returned. + * @throws NullPointerException if {@code stream} is {@code null} */ public abstract Type[] getAudioFileTypes(AudioInputStream stream); @@ -92,9 +96,11 @@ public abstract class AudioFileWriter { * @param stream for which file writing support is queried * @return {@code true} if the file type is supported for this audio input * stream, otherwise {@code false} + * @throws NullPointerException if {@code fileType} or {@code stream} are + * {@code null} */ public boolean isFileTypeSupported(Type fileType, AudioInputStream stream) { - + Objects.requireNonNull(fileType); Type types[] = getAudioFileTypes( stream ); for(int i=0; i * The full set of the mixer info objects that represent the mixers * supported by this {@code MixerProvider} may be obtained through the * {@code getMixerInfo} method. Use the {@code isMixerSupported} method to * test whether this {@code MixerProvider} supports a particular mixer. * - * @param info an info object that describes the desired mixer + * @param info an info object that describes the desired mixer, or + * {@code null} for the default mixer * @return mixer instance * @throws IllegalArgumentException if the info object specified does not - * match the info object for a mixer supported by this MixerProvider + * match the info object for a mixer supported by this + * {@code MixerProvider}, or if this {@code MixerProvider} does not + * have default mixer, but default mixer has been requested * @see #getMixerInfo() * @see #isMixerSupported(Mixer.Info) */ diff --git a/jdk/test/javax/sound/sampled/FileReader/AudioFileClose.java b/jdk/test/javax/sound/sampled/spi/AudioFileReader/AudioFileClose.java similarity index 100% rename from jdk/test/javax/sound/sampled/FileReader/AudioFileClose.java rename to jdk/test/javax/sound/sampled/spi/AudioFileReader/AudioFileClose.java diff --git a/jdk/test/javax/sound/sampled/spi/AudioFileReader/ExpectedNPEOnNull.java b/jdk/test/javax/sound/sampled/spi/AudioFileReader/ExpectedNPEOnNull.java new file mode 100644 index 00000000000..c0a89c926c1 --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/AudioFileReader/ExpectedNPEOnNull.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.io.InputStream; +import java.net.URL; + +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.spi.AudioFileReader; + +import static java.util.ServiceLoader.load; + +/** + * @test + * @bug 8135100 + * @author Sergey Bylokhov + */ +public final class ExpectedNPEOnNull { + + public static void main(final String[] args) throws Exception { + testAS(); + testAFR(); + } + + /** + * Tests the part of AudioSystem API, which implemented via AudioFileReader. + */ + private static void testAS() throws Exception { + + try { + AudioSystem.getAudioFileFormat((InputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + try { + AudioSystem.getAudioFileFormat((URL) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + try { + AudioSystem.getAudioFileFormat((File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + try { + AudioSystem.getAudioInputStream((InputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + try { + AudioSystem.getAudioInputStream((URL) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + try { + AudioSystem.getAudioInputStream((File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + + /** + * Tests the AudioFileReader API directly. + */ + private static void testAFR() throws Exception { + + for (final AudioFileReader afr : load(AudioFileReader.class)) { + try { + afr.getAudioFileFormat((InputStream) null); + throw new RuntimeException("NPE is expected: " + afr); + } catch (final NullPointerException ignored) { + } + try { + afr.getAudioFileFormat((URL) null); + throw new RuntimeException("NPE is expected: " + afr); + } catch (final NullPointerException ignored) { + } + try { + afr.getAudioFileFormat((File) null); + throw new RuntimeException("NPE is expected: " + afr); + } catch (final NullPointerException ignored) { + } + try { + afr.getAudioInputStream((InputStream) null); + throw new RuntimeException("NPE is expected: " + afr); + } catch (final NullPointerException ignored) { + } + try { + afr.getAudioInputStream((URL) null); + throw new RuntimeException("NPE is expected: " + afr); + } catch (final NullPointerException ignored) { + } + try { + afr.getAudioInputStream((File) null); + throw new RuntimeException("NPE is expected: " + afr); + } catch (final NullPointerException ignored) { + } + } + } +} diff --git a/jdk/test/javax/sound/sampled/FileReader/ReadersExceptions.java b/jdk/test/javax/sound/sampled/spi/AudioFileReader/ReadersExceptions.java similarity index 100% rename from jdk/test/javax/sound/sampled/FileReader/ReadersExceptions.java rename to jdk/test/javax/sound/sampled/spi/AudioFileReader/ReadersExceptions.java diff --git a/jdk/test/javax/sound/sampled/FileReader/RepeatedFormatReader.java b/jdk/test/javax/sound/sampled/spi/AudioFileReader/RepeatedFormatReader.java similarity index 100% rename from jdk/test/javax/sound/sampled/FileReader/RepeatedFormatReader.java rename to jdk/test/javax/sound/sampled/spi/AudioFileReader/RepeatedFormatReader.java diff --git a/jdk/test/javax/sound/sampled/FileWriter/AlawEncoderSync.java b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/AlawEncoderSync.java similarity index 100% rename from jdk/test/javax/sound/sampled/FileWriter/AlawEncoderSync.java rename to jdk/test/javax/sound/sampled/spi/AudioFileWriter/AlawEncoderSync.java diff --git a/jdk/test/javax/sound/sampled/spi/AudioFileWriter/ExpectedNPEOnNull.java b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/ExpectedNPEOnNull.java new file mode 100644 index 00000000000..1e128444235 --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/ExpectedNPEOnNull.java @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.spi.AudioFileWriter; + +import static java.util.ServiceLoader.load; +import static javax.sound.sampled.AudioFileFormat.Type; +import static javax.sound.sampled.AudioFormat.*; + +/** + * @test + * @bug 8135100 + * @author Sergey Bylokhov + */ +public final class ExpectedNPEOnNull { + + /** + * We will try to use all encoding, in this case all our providers will be + * covered by supported/unsupported encoding. + */ + private static final Encoding[] encodings = {Encoding.PCM_SIGNED, + Encoding.PCM_UNSIGNED, + Encoding.PCM_FLOAT, + Encoding.ULAW, Encoding.ALAW, + new Encoding("test")}; + + /** + * We will try to use all types, in this case all our providers will be + * covered by supported/unsupported types. + */ + private static final Type[] types = {Type.WAVE, Type.AU, Type.AIFF, + Type.AIFC, Type.SND, + new Type("MIDI", "mid"), + new Type("test", "test")}; + + /** + * We will try to use all supported AudioInputStream, in this case all our + * providers will be covered by supported/unsupported streams. + */ + private static final List aiss = new ArrayList<>(); + + static { + for (final Encoding encoding : encodings) { + for (final Type type : types) { + aiss.add(getAIS(type, encoding)); + } + } + } + + public static void main(final String[] args) throws Exception { + testAS(); + for (final AudioFileWriter afw : load(AudioFileWriter.class)) { + testAFW(afw); + } + testAFW(customAFW); + } + + /** + * Tests the part of AudioSystem API, which implemented via AudioFileWriter. + */ + private static void testAS() throws Exception { + + // AudioSystem#getAudioFileTypes(AudioInputStream) + try { + AudioSystem.getAudioFileTypes(null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + + // AudioSystem#isFileTypeSupported(Type) + try { + AudioSystem.isFileTypeSupported(null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + + // AudioSystem#isFileTypeSupported(Type, AudioInputStream) + for (final Type type : types) { + try { + AudioSystem.isFileTypeSupported(type, null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final AudioInputStream stream : aiss) { + try { + AudioSystem.isFileTypeSupported(null, stream); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + + // AudioSystem#write(AudioInputStream, Type, OutputStream) + for (final Type type : types) { + try { + AudioSystem.write(null, type, new NullOutputStream()); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final AudioInputStream stream : aiss) { + try { + AudioSystem.write(stream, null, new NullOutputStream()); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final Type type : types) { + for (final AudioInputStream stream : aiss) { + try { + AudioSystem.write(stream, type, (OutputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + } + + // AudioSystem#write(AudioInputStream, Type, File) + for (final Type type : types) { + try { + AudioSystem.write(null, type, new File("test.sound")); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + + for (final AudioInputStream stream : aiss) { + try { + AudioSystem.write(stream, null, new File("test.sound")); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final AudioInputStream stream : aiss) { + for (final Type type : types) { + try { + AudioSystem.write(stream, type, (File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + } + } + + /** + * Tests the AudioFileWriter API directly. + */ + private static void testAFW(final AudioFileWriter afw) throws Exception { + + // AudioFileWriter#isFileTypeSupported(Type) + try { + afw.isFileTypeSupported(null); + throw new RuntimeException("NPE is expected: " + afw); + } catch (final NullPointerException ignored) { + } + + // AudioFileWriter#getAudioFileTypes(AudioInputStream) + try { + afw.getAudioFileTypes(null); + throw new RuntimeException("NPE is expected: " + afw); + } catch (final NullPointerException ignored) { + } + + // AudioFileWriter#isFileTypeSupported(Type, AudioInputStream) + for (final Type type : types) { + try { + afw.isFileTypeSupported(type, null); + throw new RuntimeException("NPE is expected: " + afw); + } catch (final NullPointerException ignored) { + } + } + for (final AudioInputStream stream : aiss) { + try { + afw.isFileTypeSupported(null, stream); + throw new RuntimeException("NPE is expected: " + afw); + } catch (final NullPointerException ignored) { + } + } + + // AudioFileWriter#write(AudioInputStream, Type, OutputStream) + for (final Type type : types) { + try { + afw.write(null, type, new NullOutputStream()); + throw new RuntimeException("NPE is expected: " + afw); + } catch (final NullPointerException ignored) { + } + } + for (final AudioInputStream stream : aiss) { + try { + afw.write(stream, null, new NullOutputStream()); + throw new RuntimeException("NPE is expected: " + afw); + } catch (final NullPointerException ignored) { + } + } + for (final AudioInputStream stream : aiss) { + for (final Type type : types) { + try { + afw.write(stream, type, (OutputStream) null); + throw new RuntimeException("NPE is expected: " + afw); + } catch (final NullPointerException ignored) { + } + } + } + + // AudioFileWriter#write(AudioInputStream, Type, File) + for (final Type type : types) { + try { + afw.write(null, type, new File("test.sound")); + throw new RuntimeException("NPE is expected: " + afw); + } catch (final NullPointerException ignored) { + } + } + for (final AudioInputStream stream : aiss) { + try { + afw.write(stream, null, new File("test.sound")); + throw new RuntimeException("NPE is expected: " + afw); + } catch (final NullPointerException ignored) { + } + } + for (final AudioInputStream stream : aiss) { + for (final Type type : types) { + try { + afw.write(stream, type, (File) null); + throw new RuntimeException("NPE is expected: " + afw); + } catch (final NullPointerException ignored) { + } + } + } + } + + /** + * Tests some default implementation of AudioFileWriter API, using the + * custom {@code AudioFileWriter}, which support nothing. + */ + static final AudioFileWriter customAFW = new AudioFileWriter() { + @Override + public Type[] getAudioFileTypes() { + return new Type[0]; + } + + @Override + public Type[] getAudioFileTypes(final AudioInputStream stream) { + Objects.requireNonNull(stream); + return new Type[0]; + } + + @Override + public int write(AudioInputStream stream, Type fileType, + OutputStream out) { + Objects.requireNonNull(stream); + Objects.requireNonNull(fileType); + Objects.requireNonNull(out); + return 0; + } + + @Override + public int write(AudioInputStream stream, Type fileType, File out) { + Objects.requireNonNull(stream); + Objects.requireNonNull(fileType); + Objects.requireNonNull(out); + return 0; + } + }; + + private static AudioInputStream getAIS(final Type type, Encoding encoding) { + AudioFormat af = new AudioFormat(encoding, 44100.0f, 16, 2, 1, 1, true); + AudioFileFormat aif = new AudioFileFormat(type, af, 0); + ByteArrayInputStream bais = new ByteArrayInputStream(new byte[1024]); + return new AudioInputStream(bais, aif.getFormat(), 0); + } + + private static final class NullOutputStream extends OutputStream { + + @Override + public void write(final int b) { + //do nothing + } + } +} diff --git a/jdk/test/javax/sound/sampled/FileWriter/WriterCloseInput.java b/jdk/test/javax/sound/sampled/spi/AudioFileWriter/WriterCloseInput.java similarity index 100% rename from jdk/test/javax/sound/sampled/FileWriter/WriterCloseInput.java rename to jdk/test/javax/sound/sampled/spi/AudioFileWriter/WriterCloseInput.java diff --git a/jdk/test/javax/sound/sampled/spi/FormatConversionProvider/ExpectedNPEOnNull.java b/jdk/test/javax/sound/sampled/spi/FormatConversionProvider/ExpectedNPEOnNull.java new file mode 100644 index 00000000000..ce7125c7320 --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/FormatConversionProvider/ExpectedNPEOnNull.java @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFormat.Encoding; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.spi.FormatConversionProvider; + +import static java.util.ServiceLoader.load; +import static javax.sound.sampled.AudioFileFormat.*; + +/** + * @test + * @bug 8135100 + * @author Sergey Bylokhov + */ +public final class ExpectedNPEOnNull { + + /** + * We will try to use all encoding, in this case all our providers will be + * covered by supported/unsupported encoding. + */ + private static final Encoding[] encodings = {Encoding.PCM_SIGNED, + Encoding.PCM_UNSIGNED, + Encoding.PCM_FLOAT, + Encoding.ULAW, Encoding.ALAW, + new Encoding("test")}; + + /** + * We will try to use all types, in this case all our providers will be + * covered by supported/unsupported types. + */ + private static final Type[] types = {Type.WAVE, Type.AU, Type.AIFF, + Type.AIFC, Type.SND, + new Type("MIDI", "mid"), + new Type("test", "test")}; + + /** + * We will try to use all supported AudioInputStream, in this case all our + * providers will be covered by supported/unsupported streams. + */ + private static final List aiss = new ArrayList<>(); + + static { + for (final Encoding encoding : encodings) { + for (final Type type : types) { + aiss.add(getAIS(type, encoding)); + } + } + } + + public static void main(final String[] args) throws Exception { + testAS(); + for (final FormatConversionProvider fcp : load( + FormatConversionProvider.class)) { + testFCP(fcp); + } + testFCP(customFCP); + } + + /** + * Tests the part of AudioSystem API, which implemented via + * FormatConversionProvider. + */ + private static void testAS() throws Exception { + + // AudioSystem#getAudioInputStream(Encoding, AudioInputStream) + for (final Encoding encoding : encodings) { + try { + AudioSystem.getAudioInputStream(encoding, null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final AudioInputStream stream : aiss) { + try { + AudioSystem.getAudioInputStream((Encoding) null, stream); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + // AudioSystem#getAudioInputStream(AudioFormat, AudioInputStream) + for (final AudioInputStream stream : aiss) { + try { + AudioSystem.getAudioInputStream((AudioFormat) null, stream); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final Encoding encoding : encodings) { + try { + AudioSystem.getAudioInputStream(getAFF(encoding), null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + + // AudioSystem#getTargetEncodings(AudioFormat) + try { + AudioSystem.getTargetEncodings((AudioFormat) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + + // AudioSystem#getTargetEncodings(AudioFormat.Encoding) + try { + AudioSystem.getTargetEncodings((Encoding) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + + // AudioSystem#getTargetFormats(AudioFormat.Encoding, AudioFormat) + for (final Encoding encoding : encodings) { + try { + AudioSystem.getTargetFormats(null, getAFF(encoding)); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final Encoding encoding : encodings) { + try { + AudioSystem.getTargetFormats(encoding, null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + + // AudioSystem#isConversionSupported(AudioFormat, AudioFormat) + for (final Encoding encoding : encodings) { + try { + AudioSystem.isConversionSupported((AudioFormat) null, + getAFF(encoding)); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final Encoding encoding : encodings) { + try { + AudioSystem.isConversionSupported(getAFF(encoding), null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + + // AudioSystem#isConversionSupported(AudioFormat.Encoding, AudioFormat) + for (final Encoding encoding : encodings) { + try { + AudioSystem.isConversionSupported((Encoding) null, + getAFF(encoding)); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final Encoding encoding : encodings) { + try { + AudioSystem.isConversionSupported(encoding, null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + } + + /** + * Tests the FormatConversionProvider API directly. + */ + private static void testFCP(FormatConversionProvider fcp) throws Exception { + + // FormatConversionProvider#isSourceEncodingSupported(Encoding) + try { + fcp.isSourceEncodingSupported(null); + throw new RuntimeException("NPE is expected: " + fcp); + } catch (final NullPointerException ignored) { + } + + // FormatConversionProvider#isTargetEncodingSupported(Encoding) + try { + fcp.isTargetEncodingSupported(null); + throw new RuntimeException("NPE is expected: " + fcp); + } catch (final NullPointerException ignored) { + } + + // FormatConversionProvider#getTargetEncodings() + try { + fcp.getTargetEncodings(null); + throw new RuntimeException("NPE is expected: " + fcp); + } catch (final NullPointerException ignored) { + } + + // FormatConversionProvider#isConversionSupported(Encoding, AudioFormat) + for (final Encoding encoding : encodings) { + try { + fcp.isConversionSupported((Encoding) null, getAFF(encoding)); + throw new RuntimeException("NPE is expected: " + fcp); + } catch (final NullPointerException ignored) { + } + } + for (final Encoding encoding : encodings) { + try { + fcp.isConversionSupported(encoding, null); + throw new RuntimeException("NPE is expected: " + fcp); + } catch (final NullPointerException ignored) { + } + } + + // FormatConversionProvider#getTargetFormats(Encoding, AudioFormat) + for (final Encoding encoding : encodings) { + try { + fcp.getTargetFormats(null, getAFF(encoding)); + throw new RuntimeException("NPE is expected: " + fcp); + } catch (final NullPointerException ignored) { + } + } + for (final Encoding encoding : encodings) { + try { + fcp.getTargetFormats(encoding, null); + throw new RuntimeException("NPE is expected: " + fcp); + } catch (final NullPointerException ignored) { + } + } + + // FormatConversionProvider#isConversionSupported(AudioFormat, + // AudioFormat) + for (final Encoding encoding : encodings) { + try { + fcp.isConversionSupported((AudioFormat) null, getAFF(encoding)); + throw new RuntimeException("NPE is expected: " + fcp); + } catch (final NullPointerException ignored) { + } + } + for (final Encoding encoding : encodings) { + try { + fcp.isConversionSupported(getAFF(encoding), null); + throw new RuntimeException("NPE is expected: " + fcp); + } catch (final NullPointerException ignored) { + } + } + + // FormatConversionProvider#getAudioInputStream(Encoding, + // AudioInputStream) + for (final AudioInputStream stream : aiss) { + try { + fcp.getAudioInputStream((Encoding) null, stream); + throw new RuntimeException("NPE is expected: " + fcp); + } catch (final NullPointerException ignored) { + } + } + for (final Encoding encoding : encodings) { + try { + fcp.getAudioInputStream(encoding, null); + throw new RuntimeException("NPE is expected: " + fcp); + } catch (final NullPointerException ignored) { + } + } + + // FormatConversionProvider#getAudioInputStream(AudioFormat, + // AudioInputStream) + for (final AudioInputStream stream : aiss) { + try { + fcp.getAudioInputStream((AudioFormat) null, stream); + throw new RuntimeException("NPE is expected: " + fcp); + } catch (final NullPointerException ignored) { + } + } + for (final Encoding encoding : encodings) { + try { + fcp.getAudioInputStream(getAFF(encoding), null); + throw new RuntimeException("NPE is expected: " + fcp); + } catch (final NullPointerException ignored) { + } + } + } + + /** + * Tests some default implementation of FormatConversionProvider API, using + * the custom {@code FormatConversionProvider}, which support nothing. + */ + static FormatConversionProvider customFCP = new FormatConversionProvider() { + + @Override + public Encoding[] getSourceEncodings() { + return new Encoding[0]; + } + + @Override + public Encoding[] getTargetEncodings() { + return new Encoding[0]; + } + + @Override + public Encoding[] getTargetEncodings(AudioFormat sourceFormat) { + Objects.requireNonNull(sourceFormat); + return new Encoding[0]; + } + + @Override + public AudioFormat[] getTargetFormats(Encoding enc, AudioFormat frmt) { + Objects.requireNonNull(enc); + Objects.requireNonNull(frmt); + return new AudioFormat[0]; + } + + @Override + public AudioInputStream getAudioInputStream(Encoding encoding, + AudioInputStream stream) { + Objects.requireNonNull(encoding); + Objects.requireNonNull(stream); + return null; + } + + @Override + public AudioInputStream getAudioInputStream(AudioFormat format, + AudioInputStream stream) { + Objects.requireNonNull(format); + Objects.requireNonNull(stream); + return null; + } + }; + + private static AudioFormat getAFF(final Encoding encoding) { + return new AudioFormat(encoding, 44100.0f, 16, 2, 1, 1, true); + } + + private static AudioInputStream getAIS(final Type type, Encoding encoding) { + AudioFormat af = new AudioFormat(encoding, 44100.0f, 16, 2, 1, 1, true); + AudioFileFormat aif = new AudioFileFormat(type, af, 0); + ByteArrayInputStream bais = new ByteArrayInputStream(new byte[1024]); + return new AudioInputStream(bais, aif.getFormat(), 0); + } +} diff --git a/jdk/test/javax/sound/sampled/spi/MixerProvider/ExpectedNPEOnNull.java b/jdk/test/javax/sound/sampled/spi/MixerProvider/ExpectedNPEOnNull.java new file mode 100644 index 00000000000..8f88472bd2c --- /dev/null +++ b/jdk/test/javax/sound/sampled/spi/MixerProvider/ExpectedNPEOnNull.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.spi.MixerProvider; + +import static java.util.ServiceLoader.load; + +/** + * @test + * @bug 8135100 + * @author Sergey Bylokhov + */ +public final class ExpectedNPEOnNull { + + public static void main(final String[] args) throws Exception { + testAS(); + for (final MixerProvider mp : load(MixerProvider.class)) { + testMP(mp); + } + testMP(customMP); + } + + /** + * Tests the part of AudioSystem API, which implemented via MixerProvider. + */ + private static void testAS() { + try { + AudioSystem.getMixer(null); // null should be accepted + } catch (final SecurityException | IllegalArgumentException ignored) { + // skip the specified exceptions only + } + } + + /** + * Tests the MixerProvider API directly. + */ + private static void testMP(MixerProvider mp) { + try { + mp.isMixerSupported(null); + throw new RuntimeException("NPE is expected: " + mp); + } catch (final NullPointerException ignored) { + + } + try { + mp.getMixer(null); // null should be accepted + } catch (SecurityException | IllegalArgumentException e) { + // skip the specified exceptions only + } + } + + /** + * Tests some default implementation of MixerProvider API, using the + * custom {@code MixerProvider}, which support nothing. + */ + static final MixerProvider customMP = new MixerProvider() { + @Override + public Mixer.Info[] getMixerInfo() { + return new Mixer.Info[0]; + } + + @Override + public Mixer getMixer(Mixer.Info info) { + return null; + } + }; +} From dad26e258cae0bbeab893b90b6eb552065f8da30 Mon Sep 17 00:00:00 2001 From: Amy Lu Date: Mon, 23 Nov 2015 16:14:33 +0800 Subject: [PATCH 135/260] 8143583: Several tests don't work with latest jtreg due to non-existing files in @build Reviewed-by: alanb, sla --- jdk/test/com/sun/jdi/DoubleAgentTest.java | 2 +- jdk/test/com/sun/jdi/SuspendNoFlagTest.java | 2 +- .../com/sun/management/HotSpotDiagnosticMXBean/DumpHeap.java | 4 ++-- jdk/test/sun/tools/jmap/BasicJMapTest.java | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/jdk/test/com/sun/jdi/DoubleAgentTest.java b/jdk/test/com/sun/jdi/DoubleAgentTest.java index 91babd72e26..be3b8d8ffdc 100644 --- a/jdk/test/com/sun/jdi/DoubleAgentTest.java +++ b/jdk/test/com/sun/jdi/DoubleAgentTest.java @@ -31,7 +31,7 @@ import jdk.testlibrary.Utils; * * @library /lib/testlibrary * @modules java.management - * @build jdk.testlibarary.* + * @build jdk.testlibrary.* * @build DoubleAgentTest Exit0 * @run driver DoubleAgentTest */ diff --git a/jdk/test/com/sun/jdi/SuspendNoFlagTest.java b/jdk/test/com/sun/jdi/SuspendNoFlagTest.java index 8f91db2bac5..346dcca8923 100644 --- a/jdk/test/com/sun/jdi/SuspendNoFlagTest.java +++ b/jdk/test/com/sun/jdi/SuspendNoFlagTest.java @@ -29,7 +29,7 @@ import jdk.testlibrary.ProcessTools; * @summary Test for JDWP: -agentlib:jdwp=suspend=n hanging * @library /lib/testlibrary * @modules java.management - * @build jdk.testlibarary.* + * @build jdk.testlibrary.* * @compile -g HelloWorld.java * @run driver SuspendNoFlagTest */ diff --git a/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/DumpHeap.java b/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/DumpHeap.java index 1a64ae0d0a5..8a2c224f461 100644 --- a/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/DumpHeap.java +++ b/jdk/test/com/sun/management/HotSpotDiagnosticMXBean/DumpHeap.java @@ -41,9 +41,9 @@ import com.sun.management.HotSpotDiagnosticMXBean; * @library /test/lib/share/classes * @build jdk.testlibrary.* * @build jdk.test.lib.hprof.* - * @build jdk.test.lib.hprof.module.* + * @build jdk.test.lib.hprof.model.* * @build jdk.test.lib.hprof.parser.* - * @build jdk.test.lib.hprof.utils.* + * @build jdk.test.lib.hprof.util.* * @run main DumpHeap */ public class DumpHeap { diff --git a/jdk/test/sun/tools/jmap/BasicJMapTest.java b/jdk/test/sun/tools/jmap/BasicJMapTest.java index 03efac77cf0..1ddb903a099 100644 --- a/jdk/test/sun/tools/jmap/BasicJMapTest.java +++ b/jdk/test/sun/tools/jmap/BasicJMapTest.java @@ -42,9 +42,9 @@ import jdk.testlibrary.ProcessTools; * @modules java.management * @build jdk.testlibrary.* * @build jdk.test.lib.hprof.* - * @build jdk.test.lib.hprof.module.* + * @build jdk.test.lib.hprof.model.* * @build jdk.test.lib.hprof.parser.* - * @build jdk.test.lib.hprof.utils.* + * @build jdk.test.lib.hprof.util.* * @run main/timeout=240 BasicJMapTest */ public class BasicJMapTest { From 2952cd0bde5f9d6220323bcbc5526272d7565e81 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Mon, 23 Nov 2015 11:06:14 +0100 Subject: [PATCH 136/260] 8138952: C1: Distinguish between PPC32 and PPC64 Reviewed-by: twisti, goetz, vlivanov --- .../cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp | 7 +++++-- .../src/cpu/sparc/vm/c1_MacroAssembler_sparc.hpp | 5 ++++- hotspot/src/cpu/x86/vm/c1_MacroAssembler_x86.hpp | 5 ++++- hotspot/src/share/vm/c1/c1_Compilation.hpp | 4 ++-- hotspot/src/share/vm/c1/c1_LIR.cpp | 16 ++++++++-------- hotspot/src/share/vm/c1/c1_LIR.hpp | 16 +++++++++------- hotspot/src/share/vm/c1/c1_LIRAssembler.cpp | 13 +++++++------ hotspot/src/share/vm/c1/c1_LIRAssembler.hpp | 4 ++-- hotspot/src/share/vm/c1/c1_LinearScan.cpp | 4 ++-- hotspot/src/share/vm/c1/c1_Runtime1.cpp | 6 +++--- hotspot/src/share/vm/runtime/sharedRuntime.cpp | 2 +- hotspot/src/share/vm/runtime/sharedRuntime.hpp | 2 +- 12 files changed, 48 insertions(+), 36 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp index 5ee1e9b8d46..fe41973b106 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 1999, 2015, 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. * * This code is free software; you can redistribute it and/or modify it @@ -105,4 +105,7 @@ void zero_memory(Register addr, Register len, Register t1); void invalidate_registers(bool inv_r0, bool inv_r19, bool inv_r2, bool inv_r3, bool inv_r4, bool inv_r5) PRODUCT_RETURN; + // 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); } + #endif // CPU_AARCH64_VM_C1_MACROASSEMBLER_AARCH64_HPP diff --git a/hotspot/src/cpu/sparc/vm/c1_MacroAssembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/c1_MacroAssembler_sparc.hpp index c0178e5e0f8..492ca678d89 100644 --- a/hotspot/src/cpu/sparc/vm/c1_MacroAssembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c1_MacroAssembler_sparc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,4 +88,7 @@ void invalidate_registers(bool iregisters, bool lregisters, bool oregisters, Register preserve1 = noreg, Register preserve2 = noreg); + // 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); } + #endif // CPU_SPARC_VM_C1_MACROASSEMBLER_SPARC_HPP diff --git a/hotspot/src/cpu/x86/vm/c1_MacroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/c1_MacroAssembler_x86.hpp index c53937c78a0..5695dad2251 100644 --- a/hotspot/src/cpu/x86/vm/c1_MacroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c1_MacroAssembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,4 +117,7 @@ void invalidate_registers(bool inv_rax, bool inv_rbx, bool inv_rcx, bool inv_rdx, bool inv_rsi, bool inv_rdi) PRODUCT_RETURN; + // 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); } + #endif // CPU_X86_VM_C1_MACROASSEMBLER_X86_HPP diff --git a/hotspot/src/share/vm/c1/c1_Compilation.hpp b/hotspot/src/share/vm/c1/c1_Compilation.hpp index a20ea9f8def..66e277d263e 100644 --- a/hotspot/src/share/vm/c1/c1_Compilation.hpp +++ b/hotspot/src/share/vm/c1/c1_Compilation.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -192,7 +192,7 @@ class Compilation: public StackObj { const char* bailout_msg() const { return _bailout_msg; } static int desired_max_code_buffer_size() { -#ifndef PPC +#ifndef PPC32 return (int) NMethodSizeLimit; // default 256K or 512K #else // conditional branches on PPC are restricted to 16 bit signed diff --git a/hotspot/src/share/vm/c1/c1_LIR.cpp b/hotspot/src/share/vm/c1/c1_LIR.cpp index 0e967babd3e..44f7364ec5f 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.cpp +++ b/hotspot/src/share/vm/c1/c1_LIR.cpp @@ -55,7 +55,7 @@ XMMRegister LIR_OprDesc::as_xmm_double_reg() const { #endif // X86 -#if defined(SPARC) || defined(PPC) +#if defined(SPARC) || defined(PPC32) FloatRegister LIR_OprDesc::as_float_reg() const { return FrameMap::nr2floatreg(fpu_regnr()); @@ -67,7 +67,7 @@ FloatRegister LIR_OprDesc::as_double_reg() const { #endif -#if defined(ARM) || defined (AARCH64) +#if defined(ARM) || defined(AARCH64) || defined(PPC64) FloatRegister LIR_OprDesc::as_float_reg() const { return as_FloatRegister(fpu_regnr()); @@ -207,17 +207,17 @@ void LIR_OprDesc::validate_type() const { size_field() == double_size, "must match"); break; case T_FLOAT: - // FP return values can be also in CPU registers on ARM and PPC (softfp ABI) + // FP return values can be also in CPU registers on ARM and PPC32 (softfp ABI) assert((kindfield == fpu_register || kindfield == stack_value ARM_ONLY(|| kindfield == cpu_register) - PPC_ONLY(|| kindfield == cpu_register) ) && + PPC32_ONLY(|| kindfield == cpu_register) ) && size_field() == single_size, "must match"); break; case T_DOUBLE: - // FP return values can be also in CPU registers on ARM and PPC (softfp ABI) + // FP return values can be also in CPU registers on ARM and PPC32 (softfp ABI) assert((kindfield == fpu_register || kindfield == stack_value ARM_ONLY(|| kindfield == cpu_register) - PPC_ONLY(|| kindfield == cpu_register) ) && + PPC32_ONLY(|| kindfield == cpu_register) ) && size_field() == double_size, "must match"); break; case T_BOOLEAN: @@ -558,7 +558,7 @@ void LIR_OpVisitState::visit(LIR_Op* op) { assert(opConvert->_info == NULL, "must be"); if (opConvert->_opr->is_valid()) do_input(opConvert->_opr); if (opConvert->_result->is_valid()) do_output(opConvert->_result); -#ifdef PPC +#ifdef PPC32 if (opConvert->_tmp1->is_valid()) do_temp(opConvert->_tmp1); if (opConvert->_tmp2->is_valid()) do_temp(opConvert->_tmp2); #endif @@ -1953,7 +1953,7 @@ void LIR_OpConvert::print_instr(outputStream* out) const { print_bytecode(out, bytecode()); in_opr()->print(out); out->print(" "); result_opr()->print(out); out->print(" "); -#ifdef PPC +#ifdef PPC32 if(tmp1()->is_valid()) { tmp1()->print(out); out->print(" "); tmp2()->print(out); out->print(" "); diff --git a/hotspot/src/share/vm/c1/c1_LIR.hpp b/hotspot/src/share/vm/c1/c1_LIR.hpp index 7b203182885..14651e14078 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.hpp +++ b/hotspot/src/share/vm/c1/c1_LIR.hpp @@ -648,12 +648,14 @@ class LIR_OprFact: public AllStatic { LIR_OprDesc::double_size | LIR_OprDesc::is_xmm_mask); } #endif // X86 -#ifdef PPC +#if defined(PPC) static LIR_Opr double_fpu(int reg) { return (LIR_Opr)(intptr_t)((reg << LIR_OprDesc::reg1_shift) | (reg << LIR_OprDesc::reg2_shift) | LIR_OprDesc::double_type | LIR_OprDesc::fpu_register | LIR_OprDesc::double_size); } +#endif +#ifdef PPC32 static LIR_Opr single_softfp(int reg) { return (LIR_Opr)((reg << LIR_OprDesc::reg1_shift) | LIR_OprDesc::float_type | LIR_OprDesc::cpu_register | @@ -663,7 +665,7 @@ class LIR_OprFact: public AllStatic { LIR_OprDesc::double_type | LIR_OprDesc::cpu_register | LIR_OprDesc::double_size); } -#endif // PPC +#endif // PPC32 static LIR_Opr virtual_register(int index, BasicType type) { LIR_Opr res; @@ -1475,7 +1477,7 @@ class LIR_OpConvert: public LIR_Op1 { private: Bytecodes::Code _bytecode; ConversionStub* _stub; -#ifdef PPC +#ifdef PPC32 LIR_Opr _tmp1; LIR_Opr _tmp2; #endif @@ -1484,13 +1486,13 @@ class LIR_OpConvert: public LIR_Op1 { LIR_OpConvert(Bytecodes::Code code, LIR_Opr opr, LIR_Opr result, ConversionStub* stub) : LIR_Op1(lir_convert, opr, result) , _stub(stub) -#ifdef PPC +#ifdef PPC32 , _tmp1(LIR_OprDesc::illegalOpr()) , _tmp2(LIR_OprDesc::illegalOpr()) #endif , _bytecode(code) {} -#ifdef PPC +#ifdef PPC32 LIR_OpConvert(Bytecodes::Code code, LIR_Opr opr, LIR_Opr result, ConversionStub* stub ,LIR_Opr tmp1, LIR_Opr tmp2) : LIR_Op1(lir_convert, opr, result) @@ -1502,7 +1504,7 @@ class LIR_OpConvert: public LIR_Op1 { Bytecodes::Code bytecode() const { return _bytecode; } ConversionStub* stub() const { return _stub; } -#ifdef PPC +#ifdef PPC32 LIR_Opr tmp1() const { return _tmp1; } LIR_Opr tmp2() const { return _tmp2; } #endif @@ -2142,7 +2144,7 @@ class LIR_List: public CompilationResourceObj { void safepoint(LIR_Opr tmp, CodeEmitInfo* info) { append(new LIR_Op1(lir_safepoint, tmp, info)); } -#ifdef PPC +#ifdef PPC32 void convert(Bytecodes::Code code, LIR_Opr left, LIR_Opr dst, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_OpConvert(code, left, dst, NULL, tmp1, tmp2)); } #endif void convert(Bytecodes::Code code, LIR_Opr left, LIR_Opr dst, ConversionStub* stub = NULL/*, bool is_32bit = false*/) { append(new LIR_OpConvert(code, left, dst, stub)); } diff --git a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp index ae9c1b85c8e..c3638147e13 100644 --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -413,13 +413,14 @@ void LIR_Assembler::record_non_safepoint_debug_info() { } -void LIR_Assembler::add_debug_info_for_null_check_here(CodeEmitInfo* cinfo) { - add_debug_info_for_null_check(code_offset(), cinfo); +ImplicitNullCheckStub* LIR_Assembler::add_debug_info_for_null_check_here(CodeEmitInfo* cinfo) { + return add_debug_info_for_null_check(code_offset(), cinfo); } -void LIR_Assembler::add_debug_info_for_null_check(int pc_offset, CodeEmitInfo* cinfo) { +ImplicitNullCheckStub* LIR_Assembler::add_debug_info_for_null_check(int pc_offset, CodeEmitInfo* cinfo) { ImplicitNullCheckStub* stub = new ImplicitNullCheckStub(pc_offset, cinfo); append_code_stub(stub); + return stub; } void LIR_Assembler::add_debug_info_for_div0_here(CodeEmitInfo* info) { @@ -557,10 +558,10 @@ void LIR_Assembler::emit_op1(LIR_Op1* op) { case lir_null_check: if (GenerateCompilerNullChecks) { - add_debug_info_for_null_check_here(op->info()); + ImplicitNullCheckStub* stub = add_debug_info_for_null_check_here(op->info()); if (op->in_opr()->is_single_cpu()) { - _masm->null_check(op->in_opr()->as_register()); + _masm->null_check(op->in_opr()->as_register(), stub->entry()); } else { Unimplemented(); } diff --git a/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp b/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp index e8bc40eba93..8c2c97ece41 100644 --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp @@ -99,8 +99,8 @@ class LIR_Assembler: public CompilationResourceObj { void add_debug_info_for_branch(CodeEmitInfo* info); void add_debug_info_for_div0(int pc_offset, CodeEmitInfo* cinfo); void add_debug_info_for_div0_here(CodeEmitInfo* info); - void add_debug_info_for_null_check(int pc_offset, CodeEmitInfo* cinfo); - void add_debug_info_for_null_check_here(CodeEmitInfo* info); + ImplicitNullCheckStub* add_debug_info_for_null_check(int pc_offset, CodeEmitInfo* cinfo); + ImplicitNullCheckStub* add_debug_info_for_null_check_here(CodeEmitInfo* info); void set_24bit_FPU(); void reset_FPU(); diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.cpp b/hotspot/src/share/vm/c1/c1_LinearScan.cpp index c5682ceabcf..d87862707cb 100644 --- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp +++ b/hotspot/src/share/vm/c1/c1_LinearScan.cpp @@ -2087,7 +2087,7 @@ LIR_Opr LinearScan::calc_operand_for_interval(const Interval* interval) { #ifdef _LP64 return LIR_OprFact::double_cpu(assigned_reg, assigned_reg); #else -#if defined(SPARC) || defined(PPC) +#if defined(SPARC) || defined(PPC32) return LIR_OprFact::double_cpu(assigned_regHi, assigned_reg); #else return LIR_OprFact::double_cpu(assigned_reg, assigned_regHi); @@ -2728,7 +2728,7 @@ int LinearScan::append_scope_value_for_operand(LIR_Opr opr, GrowableArrayfpu_regnrHi() == opr->fpu_regnrLo() + 1, "assumed in calculation (only fpu_regnrLo is used)"); #endif -#ifdef PPC +#ifdef PPC32 assert(opr->fpu_regnrLo() == opr->fpu_regnrHi(), "assumed in calculation (only fpu_regnrHi is used)"); #endif diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index 70f7d5f9041..cf6099d0d65 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -210,7 +210,7 @@ void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) { case fpu2long_stub_id: case unwind_exception_id: case counter_overflow_id: -#if defined(SPARC) || defined(PPC) +#if defined(SPARC) || defined(PPC32) case handle_exception_nofpu_id: // Unused on sparc #endif break; @@ -1097,7 +1097,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i ShouldNotReachHere(); } -#if defined(SPARC) || defined(PPC) +#if defined(SPARC) || defined(PPC32) if (load_klass_or_mirror_patch_id || stub_id == Runtime1::load_appendix_patching_id) { // Update the location in the nmethod with the proper @@ -1195,7 +1195,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i relocInfo::change_reloc_info_for_address(&iter2, (address) instr_pc2, relocInfo::none, rtype); #endif -#ifdef PPC +#ifdef PPC32 { address instr_pc2 = instr_pc + NativeMovConstReg::lo_offset; RelocIterator iter2(nm, instr_pc2, instr_pc2 + 1); relocInfo::change_reloc_info_for_address(&iter2, (address) instr_pc2, diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index 2a78970f4b8..68440ee89cf 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -386,7 +386,7 @@ double SharedRuntime::dabs(double f) { #endif -#if defined(__SOFTFP__) || defined(PPC32) +#if defined(__SOFTFP__) || defined(PPC) double SharedRuntime::dsqrt(double f) { return sqrt(f); } diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.hpp b/hotspot/src/share/vm/runtime/sharedRuntime.hpp index 1938c9dbb23..acf822f6eb1 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp @@ -141,7 +141,7 @@ class SharedRuntime: AllStatic { static double dabs(double f); #endif -#if defined(__SOFTFP__) || defined(PPC32) +#if defined(__SOFTFP__) || defined(PPC) static double dsqrt(double f); #endif From 4e828a68b5846a2f669b1355489d437c14a4d28c Mon Sep 17 00:00:00 2001 From: Vikrant Agarwal Date: Mon, 23 Nov 2015 14:44:41 +0300 Subject: [PATCH 137/260] 7146533: [TEST BUG] [macosx] skip java/awt/xembed/server/RunTestXEmbed.java for Mac OS X Reviewed-by: alexsch, serb --- jdk/test/java/awt/xembed/server/RunTestXEmbed.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/jdk/test/java/awt/xembed/server/RunTestXEmbed.java b/jdk/test/java/awt/xembed/server/RunTestXEmbed.java index 58f8ecfce3f..04bb05dc04f 100644 --- a/jdk/test/java/awt/xembed/server/RunTestXEmbed.java +++ b/jdk/test/java/awt/xembed/server/RunTestXEmbed.java @@ -23,9 +23,12 @@ /** * @test - * @bug 4931668 + * @bug 4931668 7146533 * @summary Tests XEmbed server/client functionality * @author Denis Mikhalkin: area=awt.xembed + * @requires (!(os.family=="mac") & !(os.family=="windows")) + * @library /lib/testlibrary + * @build jdk.testlibrary.Platform * @modules java.desktop/sun.awt * @compile JavaClient.java TesterClient.java TestXEmbedServer.java * @run main/timeout=6000 RunTestXEmbed @@ -93,7 +96,7 @@ public class RunTestXEmbed extends TestXEmbedServer { } public static void main(String[] args) throws Throwable { - if (System.getProperty("os.name").toLowerCase().startsWith("win")) { + if (Platform.isWindows() || Platform.isOSX()) { return; } From f22e763e60282213fda27a7171f5aaf0a23bff7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 23 Nov 2015 15:26:10 +0100 Subject: [PATCH 138/260] 8141407: Wrong evaluation of a != a when a = NaN Reviewed-by: sundar, attila --- .../internal/runtime/ScriptRuntime.java | 4 +- nashorn/test/script/basic/JDK-8141407.js | 62 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 nashorn/test/script/basic/JDK-8141407.js diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java index 23e595b8b2b..2d47d78ee34 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java @@ -756,7 +756,9 @@ public final class ScriptRuntime { /** ECMA 11.9.3 The Abstract Equality Comparison Algorithm */ private static boolean equals(final Object x, final Object y) { - if (x == y) { + // We want to keep this method small so we skip reference equality check for numbers + // as NaN should return false when compared to itself (JDK-8043608). + if (x == y && !(x instanceof Number)) { return true; } if (x instanceof ScriptObject && y instanceof ScriptObject) { diff --git a/nashorn/test/script/basic/JDK-8141407.js b/nashorn/test/script/basic/JDK-8141407.js new file mode 100644 index 00000000000..b801bfdaf78 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8141407.js @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8141407: Wrong evaluation of a != a when a = NaN + * + * @test + * @run + */ + +function expectNotEqualToSelf(a) { + Assert.assertFalse(a == a); + Assert.assertFalse(a === a); + Assert.assertTrue(a != a); + Assert.assertTrue(a !== a); +} + +// In previous versions of Nashorn this failed only on the second assignment, +// because only then the property slot was widened to object. +var a = NaN; +expectNotEqualToSelf(a); +a = {}; +a = NaN; +expectNotEqualToSelf(a); + +// We do have to do value-based rather than reference-based comparison for +// java.lang.Double since that class is used to represent primitive numbers +// in JavaScript. +var b = new java.lang.Double(NaN); +expectNotEqualToSelf(b); +b = {}; +b = new java.lang.Double(NaN); +expectNotEqualToSelf(b); + +// Although float is not used internally by Nashorn, java.lang.Float +// is handled like a primitive number in most of Nashorn, so for consistency +// we treat it like java.lang.Double. +var c = new java.lang.Float(NaN); +expectNotEqualToSelf(c); +c = {}; +c = new java.lang.Float(NaN); +expectNotEqualToSelf(c); From bcdeeca8008f72527bd307ea4971f1226c860339 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 23 Nov 2015 08:11:25 -0800 Subject: [PATCH 139/260] 8143813: Problem list PKCS8Test.java Reviewed-by: mullan --- jdk/test/ProblemList.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index cb33d6e7eae..d68562e043e 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -217,6 +217,9 @@ java/rmi/activation/Activatable/extLoadedImpl/ext.sh generic-all # jdk_security +# 8143377 +sun/security/pkcs/pkcs8/PKCS8Test.java solaris-all + # 7157786 sun/security/pkcs11/ec/TestKeyFactory.java generic-all From c51be36580091964d874e17c4a039f75d2046258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 23 Nov 2015 17:52:04 +0100 Subject: [PATCH 140/260] 8143821: Wrong test name in JDK-8143304 Reviewed-by: attila, sundar --- nashorn/test/script/basic/{JDK-8059934.js => JDK-8143304.js} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename nashorn/test/script/basic/{JDK-8059934.js => JDK-8143304.js} (95%) diff --git a/nashorn/test/script/basic/JDK-8059934.js b/nashorn/test/script/basic/JDK-8143304.js similarity index 95% rename from nashorn/test/script/basic/JDK-8059934.js rename to nashorn/test/script/basic/JDK-8143304.js index 42643b7dc3e..621077c3ca3 100644 --- a/nashorn/test/script/basic/JDK-8059934.js +++ b/nashorn/test/script/basic/JDK-8143304.js @@ -22,7 +22,7 @@ */ /** - * JDK-8059934: Random failures when script size exceeds token limits + * JDK-8143304: Random failures when script size exceeds token limits * * @test * @run From 301586f46277e6f6b1d0c14561ce72ee8d87d949 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 23 Nov 2015 09:58:44 -0800 Subject: [PATCH 141/260] 8143177: Integrate harfbuzz opentype layout engine per JEP 258 Reviewed-by: srl, vadim, serb --- jdk/make/lib/Awt2dLibraries.gmk | 32 +- jdk/make/mapfiles/libfontmanager/mapfile-vers | 1 + .../libfontmanager/mapfile-vers.openjdk | 1 + .../macosx/classes/sun/font/CFont.java | 7 + .../share/classes/sun/font/Font2D.java | 6 + .../share/classes/sun/font/GlyphLayout.java | 6 +- .../classes/sun/font/SunLayoutEngine.java | 49 +- .../share/classes/sun/font/TrueTypeFont.java | 1 + .../share/native/libfontmanager/HBShaper.c | 313 + .../harfbuzz/hb-atomic-private.hh | 164 + .../native/libfontmanager/harfbuzz/hb-blob.cc | 479 ++ .../native/libfontmanager/harfbuzz/hb-blob.h | 126 + .../harfbuzz/hb-buffer-deserialize-json.hh | 643 +++ .../harfbuzz/hb-buffer-deserialize-text.hh | 571 ++ .../harfbuzz/hb-buffer-private.hh | 220 + .../harfbuzz/hb-buffer-serialize.cc | 418 ++ .../libfontmanager/harfbuzz/hb-buffer.cc | 1701 ++++++ .../libfontmanager/harfbuzz/hb-buffer.h | 378 ++ .../harfbuzz/hb-cache-private.hh | 74 + .../libfontmanager/harfbuzz/hb-common.cc | 593 ++ .../libfontmanager/harfbuzz/hb-common.h | 354 ++ .../libfontmanager/harfbuzz/hb-coretext.cc | 1219 ++++ .../libfontmanager/harfbuzz/hb-coretext.h | 60 + .../libfontmanager/harfbuzz/hb-deprecated.h | 51 + .../harfbuzz/hb-face-private.hh | 107 + .../native/libfontmanager/harfbuzz/hb-face.cc | 481 ++ .../native/libfontmanager/harfbuzz/hb-face.h | 117 + .../harfbuzz/hb-fallback-shape.cc | 141 + .../harfbuzz/hb-font-private.hh | 415 ++ .../native/libfontmanager/harfbuzz/hb-font.cc | 1266 +++++ .../native/libfontmanager/harfbuzz/hb-font.h | 512 ++ .../native/libfontmanager/harfbuzz/hb-ft.cc | 650 +++ .../native/libfontmanager/harfbuzz/hb-ft.h | 126 + .../harfbuzz/hb-mutex-private.hh | 141 + .../harfbuzz/hb-object-private.hh | 202 + .../harfbuzz/hb-open-file-private.hh | 268 + .../harfbuzz/hb-open-type-private.hh | 1046 ++++ .../harfbuzz/hb-ot-cmap-table.hh | 528 ++ .../libfontmanager/harfbuzz/hb-ot-font.cc | 434 ++ .../libfontmanager/harfbuzz/hb-ot-font.h | 45 + .../harfbuzz/hb-ot-glyf-table.hh | 104 + .../harfbuzz/hb-ot-head-table.hh | 152 + .../harfbuzz/hb-ot-hhea-table.hh | 103 + .../harfbuzz/hb-ot-hmtx-table.hh | 104 + .../harfbuzz/hb-ot-layout-common-private.hh | 1224 ++++ .../harfbuzz/hb-ot-layout-gdef-table.hh | 443 ++ .../harfbuzz/hb-ot-layout-gpos-table.hh | 1643 ++++++ .../harfbuzz/hb-ot-layout-gsub-table.hh | 1342 +++++ .../harfbuzz/hb-ot-layout-gsubgpos-private.hh | 2286 ++++++++ .../harfbuzz/hb-ot-layout-jstf-table.hh | 234 + .../harfbuzz/hb-ot-layout-private.hh | 507 ++ .../libfontmanager/harfbuzz/hb-ot-layout.cc | 1058 ++++ .../libfontmanager/harfbuzz/hb-ot-layout.h | 302 + .../harfbuzz/hb-ot-map-private.hh | 248 + .../libfontmanager/harfbuzz/hb-ot-map.cc | 315 + .../harfbuzz/hb-ot-maxp-table.hh | 72 + .../harfbuzz/hb-ot-name-table.hh | 136 + .../hb-ot-shape-complex-arabic-fallback.hh | 354 ++ .../hb-ot-shape-complex-arabic-private.hh | 50 + .../hb-ot-shape-complex-arabic-table.hh | 383 ++ .../hb-ot-shape-complex-arabic-win1256.hh | 323 ++ .../harfbuzz/hb-ot-shape-complex-arabic.cc | 389 ++ .../harfbuzz/hb-ot-shape-complex-default.cc | 44 + .../harfbuzz/hb-ot-shape-complex-hangul.cc | 423 ++ .../harfbuzz/hb-ot-shape-complex-hebrew.cc | 172 + .../hb-ot-shape-complex-indic-machine.hh | 1762 ++++++ .../hb-ot-shape-complex-indic-private.hh | 180 + .../hb-ot-shape-complex-indic-table.cc | 956 ++++ .../harfbuzz/hb-ot-shape-complex-indic.cc | 1843 ++++++ .../hb-ot-shape-complex-myanmar-machine.hh | 400 ++ .../harfbuzz/hb-ot-shape-complex-myanmar.cc | 532 ++ .../harfbuzz/hb-ot-shape-complex-private.hh | 355 ++ .../harfbuzz/hb-ot-shape-complex-thai.cc | 381 ++ .../harfbuzz/hb-ot-shape-complex-tibetan.cc | 61 + .../hb-ot-shape-complex-use-machine.hh | 548 ++ .../hb-ot-shape-complex-use-private.hh | 97 + .../harfbuzz/hb-ot-shape-complex-use-table.cc | 696 +++ .../harfbuzz/hb-ot-shape-complex-use.cc | 585 ++ .../harfbuzz/hb-ot-shape-fallback-private.hh | 49 + .../harfbuzz/hb-ot-shape-fallback.cc | 484 ++ .../harfbuzz/hb-ot-shape-normalize-private.hh | 69 + .../harfbuzz/hb-ot-shape-normalize.cc | 416 ++ .../harfbuzz/hb-ot-shape-private.hh | 104 + .../libfontmanager/harfbuzz/hb-ot-shape.cc | 892 +++ .../libfontmanager/harfbuzz/hb-ot-shape.h | 53 + .../libfontmanager/harfbuzz/hb-ot-tag.cc | 931 +++ .../libfontmanager/harfbuzz/hb-ot-tag.h | 59 + .../native/libfontmanager/harfbuzz/hb-ot.h | 43 + .../libfontmanager/harfbuzz/hb-private.hh | 953 ++++ .../libfontmanager/harfbuzz/hb-set-private.hh | 402 ++ .../native/libfontmanager/harfbuzz/hb-set.cc | 471 ++ .../native/libfontmanager/harfbuzz/hb-set.h | 157 + .../harfbuzz/hb-shape-plan-private.hh | 62 + .../libfontmanager/harfbuzz/hb-shape-plan.cc | 500 ++ .../libfontmanager/harfbuzz/hb-shape-plan.h | 89 + .../libfontmanager/harfbuzz/hb-shape.cc | 406 ++ .../native/libfontmanager/harfbuzz/hb-shape.h | 78 + .../harfbuzz/hb-shaper-impl-private.hh | 43 + .../libfontmanager/harfbuzz/hb-shaper-list.hh | 55 + .../harfbuzz/hb-shaper-private.hh | 108 + .../libfontmanager/harfbuzz/hb-shaper.cc | 111 + .../native/libfontmanager/harfbuzz/hb-ucdn.cc | 237 + .../libfontmanager/harfbuzz/hb-ucdn/ucdn.c | 281 + .../libfontmanager/harfbuzz/hb-ucdn/ucdn.h | 364 ++ .../harfbuzz/hb-ucdn/unicodedata_db.h | 5062 +++++++++++++++++ .../harfbuzz/hb-unicode-private.hh | 317 ++ .../libfontmanager/harfbuzz/hb-unicode.cc | 563 ++ .../libfontmanager/harfbuzz/hb-unicode.h | 470 ++ .../libfontmanager/harfbuzz/hb-utf-private.hh | 278 + .../libfontmanager/harfbuzz/hb-version.h | 66 + .../libfontmanager/harfbuzz/hb-warning.cc | 39 + .../share/native/libfontmanager/harfbuzz/hb.h | 47 + .../native/libfontmanager/hb-jdk-font.cc | 365 ++ .../share/native/libfontmanager/hb-jdk.h | 74 + .../native/libfontmanager/scriptMapping.c | 92 + .../native/libfontmanager/scriptMapping.h | 33 + .../awt/font/TextLayout/TestLayoutVsICU.java | 889 +++ .../TextLayout/TestLayoutVsICU_jdkbase.xml | 1827 ++++++ 118 files changed, 52287 insertions(+), 5 deletions(-) create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-atomic-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-deserialize-json.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-deserialize-text.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-serialize.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-cache-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-common.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-common.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-coretext.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-coretext.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-deprecated.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-fallback-shape.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ft.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ft.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-mutex-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-object-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-file-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-type-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-cmap-table.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-font.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-font.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-glyf-table.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-head-table.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-hhea-table.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-hmtx-table.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-common-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gdef-table.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gpos-table.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gsub-table.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gsubgpos-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-jstf-table.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-map-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-map.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-maxp-table.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-name-table.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-arabic-fallback.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-arabic-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-arabic-table.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-arabic-win1256.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-arabic.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-default.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-hangul.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-hebrew.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-indic-machine.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-indic-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-indic-table.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-indic.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-myanmar-machine.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-myanmar.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-thai.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-tibetan.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-use-machine.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-use-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-use-table.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-complex-use.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-fallback-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-fallback.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-normalize-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-normalize.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-shape.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-tag.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-tag.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-set-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-set.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-set.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shape-plan-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shape-plan.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shape-plan.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shape.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shape.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shaper-impl-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shaper-list.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shaper-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-shaper.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ucdn.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ucdn/ucdn.c create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ucdn/ucdn.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ucdn/unicodedata_db.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-unicode-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-unicode.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-unicode.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-utf-private.hh create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-version.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-warning.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/hb-jdk-font.cc create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/hb-jdk.h create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/scriptMapping.c create mode 100644 jdk/src/java.desktop/share/native/libfontmanager/scriptMapping.h create mode 100644 jdk/test/java/awt/font/TextLayout/TestLayoutVsICU.java create mode 100644 jdk/test/java/awt/font/TextLayout/TestLayoutVsICU_jdkbase.xml diff --git a/jdk/make/lib/Awt2dLibraries.gmk b/jdk/make/lib/Awt2dLibraries.gmk index 21e61c5c679..bc4a95064a3 100644 --- a/jdk/make/lib/Awt2dLibraries.gmk +++ b/jdk/make/lib/Awt2dLibraries.gmk @@ -602,6 +602,34 @@ LIBFONTMANAGER_CFLAGS := \ $(LIBJAVA_HEADER_FLAGS) \ # +#### Begin harfbuzz configuration + +HARFBUZZ_CFLAGS := -DHAVE_OT -DHAVE_FALLBACK -DHAVE_UCDN + +ifneq ($(OPENJDK_TARGET_OS), windows) + HARFBUZZ_CFLAGS += -DGETPAGESIZE -DHAVE_MPROTECT -DHAVE_PTHREAD \ + -DHAVE_SYSCONF -DHAVE_SYS_MMAN_H -DHAVE_UNISTD_H +endif +ifneq (, $(findstring $(OPENJDK_TARGET_OS), linux macosx)) + HARFBUZZ_CFLAGS += -DHAVE_INTEL_ATOMIC_PRIMITIVES +endif +ifeq ($(OPENJDK_TARGET_OS), solaris) + HARFBUZZ_CFLAGS += -DHAVE_SOLARIS_ATOMIC_OPS +endif +ifeq ($(OPENJDK_TARGET_OS), macosx) + HARFBUZZ_CFLAGS += -DHAVE_CORETEXT +endif +ifneq ($(OPENJDK_TARGET_OS), macosx) + LIBFONTMANAGER_EXCLUDE_FILES += harfbuzz/hb-coretext.cc +endif +ifndef OPENJDK + LIBFONTMANAGER_EXCLUDE_FILES += harfbuzz/hb-ft.cc +endif + +LIBFONTMANAGER_CFLAGS += $(HARFBUZZ_CFLAGS) + +#### End harfbuzz configuration + ifndef OPENJDK LIBFONTMANAGER_CFLAGS += -I$(JDK_TOPDIR)/src/closed/java.desktop/share/native/libt2k BUILD_LIBFONTMANAGER_MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libfontmanager/mapfile-vers @@ -648,11 +676,11 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBFONTMANAGER, \ OPTIMIZATION := $(LIBFONTMANAGER_OPTIMIZATION), \ CFLAGS_windows = -DCC_NOEX, \ DISABLED_WARNINGS_gcc := sign-compare int-to-pointer-cast reorder \ - delete-non-virtual-dtor type-limits, \ + delete-non-virtual-dtor type-limits missing-field-initializers, \ DISABLED_WARNINGS_clang := unused-value incompatible-pointer-types \ tautological-constant-out-of-range-compare int-to-pointer-cast, \ DISABLED_WARNINGS_solstudio := truncwarn, \ - DISABLED_WARNINGS_microsoft := 4267 4244 4018 4090 4996 4146, \ + DISABLED_WARNINGS_microsoft := 4267 4244 4018 4090 4996 4146 4334, \ WARNINGS_AS_ERRORS_gcc := false, \ WARNINGS_AS_ERRORS_solstudio := false, \ MAPFILE := $(BUILD_LIBFONTMANAGER_MAPFILE), \ diff --git a/jdk/make/mapfiles/libfontmanager/mapfile-vers b/jdk/make/mapfiles/libfontmanager/mapfile-vers index 2a83f292644..f2acff6aa6d 100644 --- a/jdk/make/mapfiles/libfontmanager/mapfile-vers +++ b/jdk/make/mapfiles/libfontmanager/mapfile-vers @@ -41,6 +41,7 @@ SUNWprivate_1.1 { Java_sun_font_StrikeCache_freeLongMemory; Java_sun_font_SunLayoutEngine_initGVIDs; Java_sun_font_SunLayoutEngine_nativeLayout; + Java_sun_font_SunLayoutEngine_shape; Java_sun_font_X11TextRenderer_doDrawGlyphList; Java_sun_java2d_loops_DrawGlyphListAA_DrawGlyphListAA; Java_sun_java2d_loops_DrawGlyphListLCD_DrawGlyphListLCD; diff --git a/jdk/make/mapfiles/libfontmanager/mapfile-vers.openjdk b/jdk/make/mapfiles/libfontmanager/mapfile-vers.openjdk index b20344eaaab..21ecea99119 100644 --- a/jdk/make/mapfiles/libfontmanager/mapfile-vers.openjdk +++ b/jdk/make/mapfiles/libfontmanager/mapfile-vers.openjdk @@ -43,6 +43,7 @@ SUNWprivate_1.1 { Java_sun_font_StrikeCache_freeLongMemory; Java_sun_font_SunLayoutEngine_initGVIDs; Java_sun_font_SunLayoutEngine_nativeLayout; + Java_sun_font_SunLayoutEngine_shape; Java_sun_font_X11TextRenderer_doDrawGlyphList; Java_sun_java2d_loops_DrawGlyphListAA_DrawGlyphListAA; Java_sun_java2d_loops_DrawGlyphListLCD_DrawGlyphListLCD; diff --git a/jdk/src/java.desktop/macosx/classes/sun/font/CFont.java b/jdk/src/java.desktop/macosx/classes/sun/font/CFont.java index a25e1784811..dcc4b5793eb 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/font/CFont.java +++ b/jdk/src/java.desktop/macosx/classes/sun/font/CFont.java @@ -198,6 +198,13 @@ public final class CFont extends PhysicalFont implements FontSubstitution { return nativeFontPtr; } + private native long getCGFontPtrNative(long ptr); + + // This digs the CGFont out of the AWTFont. + protected synchronized long getPlatformNativeFontPtr() { + return getCGFontPtrNative(getNativeFontPtr()); + } + static native void getCascadeList(long nativeFontPtr, ArrayList listOfString); private CompositeFont createCompositeFont() { diff --git a/jdk/src/java.desktop/share/classes/sun/font/Font2D.java b/jdk/src/java.desktop/share/classes/sun/font/Font2D.java index 7e7edc3e8cc..84fc658447f 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/Font2D.java +++ b/jdk/src/java.desktop/share/classes/sun/font/Font2D.java @@ -472,6 +472,12 @@ public abstract class Font2D { return 0L; } + /* Used only on OS X. + */ + protected long getPlatformNativeFontPtr() { + return 0L; + } + /* for layout code */ protected long getUnitsPerEm() { return 2048; diff --git a/jdk/src/java.desktop/share/classes/sun/font/GlyphLayout.java b/jdk/src/java.desktop/share/classes/sun/font/GlyphLayout.java index 143795e7b6a..0363f0f43fa 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/GlyphLayout.java +++ b/jdk/src/java.desktop/share/classes/sun/font/GlyphLayout.java @@ -96,6 +96,7 @@ public final class GlyphLayout { private Point2D.Float _pt; private FontStrikeDesc _sd; private float[] _mat; + private float ptSize; private int _typo_flags; private int _offset; @@ -172,7 +173,7 @@ public final class GlyphLayout { * If the GVData does not have room for the glyphs, throws an IndexOutOfBoundsException and * leave pt and the gvdata unchanged. */ - public void layout(FontStrikeDesc sd, float[] mat, int gmask, + public void layout(FontStrikeDesc sd, float[] mat, float ptSize, int gmask, int baseIndex, TextRecord text, int typo_flags, Point2D.Float pt, GVData data); } @@ -386,6 +387,7 @@ public final class GlyphLayout { _mat[2] = (float)txinfo.gtx.getShearX(); _mat[3] = (float)txinfo.gtx.getScaleY(); _pt.setLocation(txinfo.delta); + ptSize = font.getSize2D(); int lim = offset + count; @@ -682,7 +684,7 @@ public final class GlyphLayout { void layout() { _textRecord.start = start; _textRecord.limit = limit; - engine.layout(_sd, _mat, gmask, start - _offset, _textRecord, + engine.layout(_sd, _mat, ptSize, gmask, start - _offset, _textRecord, _typo_flags | eflags, _pt, _gvdata); } } diff --git a/jdk/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java b/jdk/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java index a62b1e5fe21..c7ab758c9a4 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java +++ b/jdk/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java @@ -103,9 +103,20 @@ import java.util.Locale; * */ public final class SunLayoutEngine implements LayoutEngine, LayoutEngineFactory { private static native void initGVIDs(); + private static final boolean useICU; static { FontManagerNativeLibrary.load(); initGVIDs(); + String le = java.security.AccessController.doPrivileged( + new sun.security.action. + GetPropertyAction("sun.font.layoutengine", "")); + useICU = le.equals("icu"); + String verbose = java.security.AccessController.doPrivileged( + new sun.security.action. + GetPropertyAction("sun.font.layoutengine.verbose", "")); + if ("true".equalsIgnoreCase(verbose)) { + System.out.println("Using " + (useICU ? "icu." : "harfbuzz.")); + } } private LayoutEngineKey key; @@ -150,21 +161,57 @@ public final class SunLayoutEngine implements LayoutEngine, LayoutEngineFactory this.key = key; } - public void layout(FontStrikeDesc desc, float[] mat, int gmask, + private boolean isAAT(Font2D font) { + if (font instanceof TrueTypeFont) { + TrueTypeFont ttf = (TrueTypeFont)font; + return ttf.getDirectoryEntry(TrueTypeFont.morxTag) != null || + ttf.getDirectoryEntry(TrueTypeFont.mortTag) != null; + } else if (font instanceof PhysicalFont) { + PhysicalFont pf = (PhysicalFont)font; + return pf.getTableBytes(TrueTypeFont.morxTag) != null || + pf.getTableBytes(TrueTypeFont.mortTag) != null; + } + return false; + } + + public void layout(FontStrikeDesc desc, float[] mat, float ptSize, int gmask, int baseIndex, TextRecord tr, int typo_flags, Point2D.Float pt, GVData data) { Font2D font = key.font(); FontStrike strike = font.getStrike(desc); long layoutTables = font.getLayoutTableCache(); + if (useICU) { nativeLayout(font, strike, mat, gmask, baseIndex, tr.text, tr.start, tr.limit, tr.min, tr.max, key.script(), key.lang(), typo_flags, pt, data, font.getUnitsPerEm(), layoutTables); + } else { + long pNativeFont = font.getPlatformNativeFontPtr(); // used on OSX + // pScaler probably not needed long term. + long pScaler = 0L; + if (font instanceof FileFont) { + pScaler = ((FileFont)font).getScaler().nativeScaler; + } + shape(font, strike, ptSize, mat, pScaler, pNativeFont, isAAT(font), + tr.text, data, key.script(), + tr.start, tr.limit, baseIndex, pt, + typo_flags, gmask); + } } + /* Native method to invoke ICU layout engine */ private static native void nativeLayout(Font2D font, FontStrike strike, float[] mat, int gmask, int baseIndex, char[] chars, int offset, int limit, int min, int max, int script, int lang, int typo_flags, Point2D.Float pt, GVData data, long upem, long layoutTables); + + + /* Native method to invoke harfbuzz layout engine */ + private static native boolean + shape(Font2D font, FontStrike strike, float ptSize, float[] mat, + long pscaler, long pNativeFont, boolean aat, + char[] chars, GVData data, + int script, int offset, int limit, + int baseIndex, Point2D.Float pt, int typo_flags, int slot); } diff --git a/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java b/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java index f3bb84529da..c4893b6dd60 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java +++ b/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java @@ -83,6 +83,7 @@ public class TrueTypeFont extends FileFont { public static final int GPOSTag = 0x47504F53; // 'GPOS' public static final int GSUBTag = 0x47535542; // 'GSUB' public static final int mortTag = 0x6D6F7274; // 'mort' + public static final int morxTag = 0x6D6F7278; // 'morx' /* -- Tags for non-standard tables */ public static final int fdscTag = 0x66647363; // 'fdsc' - gxFont descriptor diff --git a/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c b/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c new file mode 100644 index 00000000000..422575cb165 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include "hb.h" +#include "hb-jdk.h" +#include "hb-ot.h" +#ifdef MACOSX +#include "hb-coretext.h" +#endif +#include "scriptMapping.h" + +static jclass gvdClass = 0; +static const char* gvdClassName = "sun/font/GlyphLayout$GVData"; +static jfieldID gvdCountFID = 0; +static jfieldID gvdFlagsFID = 0; +static jfieldID gvdGlyphsFID = 0; +static jfieldID gvdPositionsFID = 0; +static jfieldID gvdIndicesFID = 0; +static int jniInited = 0; + +static void getFloat(JNIEnv* env, jobject pt, jfloat *x, jfloat *y) { + *x = (*env)->GetFloatField(env, pt, sunFontIDs.xFID); + *y = (*env)->GetFloatField(env, pt, sunFontIDs.yFID); +} + +static void putFloat(JNIEnv* env, jobject pt, jfloat x, jfloat y) { + (*env)->SetFloatField(env, pt, sunFontIDs.xFID, x); + (*env)->SetFloatField(env, pt, sunFontIDs.yFID, y); +} + +static int init_JNI_IDs(JNIEnv *env) { + if (jniInited) { + return jniInited; + } + CHECK_NULL_RETURN(gvdClass = (*env)->FindClass(env, gvdClassName), 0); + CHECK_NULL_RETURN(gvdClass = (jclass)(*env)->NewGlobalRef(env, gvdClass), 0); + CHECK_NULL_RETURN(gvdCountFID = (*env)->GetFieldID(env, gvdClass, "_count", "I"), 0); + CHECK_NULL_RETURN(gvdFlagsFID = (*env)->GetFieldID(env, gvdClass, "_flags", "I"), 0); + CHECK_NULL_RETURN(gvdGlyphsFID = (*env)->GetFieldID(env, gvdClass, "_glyphs", "[I"), 0); + CHECK_NULL_RETURN(gvdPositionsFID = (*env)->GetFieldID(env, gvdClass, "_positions", "[F"), 0); + CHECK_NULL_RETURN(gvdIndicesFID = (*env)->GetFieldID(env, gvdClass, "_indices", "[I"), 0); + jniInited = 1; + return jniInited; +} + +// gmask is the composite font slot mask +// baseindex is to be added to the character (code point) index. +int storeGVData(JNIEnv* env, + jobject gvdata, jint slot, jint baseIndex, jobject startPt, + int glyphCount, hb_glyph_info_t *glyphInfo, + hb_glyph_position_t *glyphPos, hb_direction_t direction) { + + int i; + float x=0, y=0; + float startX, startY; + float scale = 1.0f/64.0f; + unsigned int* glyphs; + float* positions; + + if (!init_JNI_IDs(env)) { + return 0; + } + + int initialCount = (*env)->GetIntField(env, gvdata, gvdCountFID); + jarray glyphArray = + (jarray)(*env)->GetObjectField(env, gvdata, gvdGlyphsFID); + jarray posArray = + (jarray)(*env)->GetObjectField(env, gvdata, gvdPositionsFID); + + if (glyphArray == NULL || posArray == NULL) + { + JNU_ThrowArrayIndexOutOfBoundsException(env, ""); + return 0; + } + + // The Java code catches the IIOBE and expands the storage + // and re-invokes layout. I suppose this is expected to be rare + // because at least in a single threaded case there should be + // re-use of the same container, but it is a little wasteful/distateful. + int glyphArrayLen = (*env)->GetArrayLength(env, glyphArray); + int posArrayLen = (*env)->GetArrayLength(env, posArray); + int maxGlyphs = glyphCount + initialCount; + if ((maxGlyphs > glyphArrayLen) || + (maxGlyphs * 2 + 2 > posArrayLen)) + { + JNU_ThrowArrayIndexOutOfBoundsException(env, ""); + return 0; + } + + getFloat(env, startPt, &startX, &startY); + + glyphs = + (unsigned int*)(*env)->GetPrimitiveArrayCritical(env, glyphArray, NULL); + positions = (jfloat*)(*env)->GetPrimitiveArrayCritical(env, posArray, NULL); + for (i = 0; i < glyphCount; i++) { + int storei = i + initialCount; + int index = glyphInfo[i].codepoint | slot; + if (iReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0); + (*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, 0); + putFloat(env, startPt,positions[(storeadv*2)],positions[(storeadv*2)+1] ); + jarray inxArray = + (jarray)(*env)->GetObjectField(env, gvdata, gvdIndicesFID); + unsigned int* indices = + (unsigned int*)(*env)->GetPrimitiveArrayCritical(env, inxArray, NULL); + int prevCluster = -1; + for (i = 0; i < glyphCount; i++) { + int cluster = glyphInfo[i].cluster; + if (direction == HB_DIRECTION_LTR) { + // I need to understand what hb does when processing a substring + // I expected the cluster index to be from the start of the text + // to process. + // Instead it appears to be from the start of the whole thing. + indices[i+initialCount] = cluster; + } else { + indices[i+initialCount] = baseIndex + glyphCount -1 -i; + } + } + (*env)->ReleasePrimitiveArrayCritical(env, inxArray, indices, 0); + (*env)->SetIntField(env, gvdata, gvdCountFID, initialCount+glyphCount); + return initialCount+glyphCount; +} + +static float euclidianDistance(float a, float b) +{ + float root; + if (a < 0) { + a = -a; + } + + if (b < 0) { + b = -b; + } + + if (a == 0) { + return b; + } + + if (b == 0) { + return a; + } + + /* Do an initial approximation, in root */ + root = a > b ? a + (b / 2) : b + (a / 2); + + /* An unrolled Newton-Raphson iteration sequence */ + root = (root + (a * (a / root)) + (b * (b / root)) + 1) / 2; + root = (root + (a * (a / root)) + (b * (b / root)) + 1) / 2; + root = (root + (a * (a / root)) + (b * (b / root)) + 1) / 2; + + return root; +} + +JDKFontInfo* + createJDKFontInfo(JNIEnv *env, + jobject font2D, + jobject fontStrike, + jfloat ptSize, + jlong pScaler, + jlong pNativeFont, + jfloatArray matrix, + jboolean aat) { + + + JDKFontInfo *fi = (JDKFontInfo*)malloc(sizeof(JDKFontInfo)); + if (!fi) { + return NULL; + } + fi->env = env; // this is valid only for the life of this JNI call. + fi->font2D = font2D; + fi->fontStrike = fontStrike; + fi->nativeFont = pNativeFont; + fi->aat = aat; + (*env)->GetFloatArrayRegion(env, matrix, 0, 4, fi->matrix); + fi->ptSize = ptSize; + fi->xPtSize = euclidianDistance(fi->matrix[0], fi->matrix[1]); + fi->yPtSize = euclidianDistance(fi->matrix[2], fi->matrix[3]); + + return fi; +} + + +#define TYPO_RTL 0x80000000 + +JNIEXPORT jboolean JNICALL Java_sun_font_SunLayoutEngine_shape + (JNIEnv *env, jclass cls, + jobject font2D, + jobject fontStrike, + jfloat ptSize, + jfloatArray matrix, + jlong pScaler, + jlong pNativeFont, + jboolean aat, + jcharArray text, + jobject gvdata, + jint script, + jint offset, + jint limit, + jint baseIndex, + jobject startPt, + jint flags, + jint slot) { + + hb_buffer_t *buffer; + hb_font_t* hbfont; + jchar *chars; + jsize len; + int glyphCount; + hb_glyph_info_t *glyphInfo; + hb_glyph_position_t *glyphPos; + hb_direction_t direction = HB_DIRECTION_LTR; + hb_feature_t *features = NULL; + int featureCount = 0; + + int i; + unsigned int buflen; + + JDKFontInfo *jdkFontInfo = + createJDKFontInfo(env, font2D, fontStrike, ptSize, + pScaler, pNativeFont, matrix, aat); + if (!jdkFontInfo) { + return JNI_FALSE; + } + jdkFontInfo->env = env; // this is valid only for the life of this JNI call. + jdkFontInfo->font2D = font2D; + jdkFontInfo->fontStrike = fontStrike; + + hbfont = hb_jdk_font_create(jdkFontInfo, NULL); + + buffer = hb_buffer_create(); + hb_buffer_set_script(buffer, getHBScriptCode(script)); + hb_buffer_set_language(buffer, + hb_ot_tag_to_language(HB_OT_TAG_DEFAULT_LANGUAGE)); + if ((flags & TYPO_RTL) != 0) { + direction = HB_DIRECTION_RTL; + } + hb_buffer_set_direction(buffer, direction); + + chars = (*env)->GetCharArrayElements(env, text, NULL); + len = (*env)->GetArrayLength(env, text); + + hb_buffer_add_utf16(buffer, chars, len, offset, limit-offset); + + hb_shape_full(hbfont, buffer, features, featureCount, 0); + glyphCount = hb_buffer_get_length(buffer); + glyphInfo = hb_buffer_get_glyph_infos(buffer, 0); + glyphPos = hb_buffer_get_glyph_positions(buffer, &buflen); + for (i = 0; i < glyphCount; i++) { + int index = glyphInfo[i].codepoint; + int xadv = (glyphPos[i].x_advance); + int yadv = (glyphPos[i].y_advance); + } + // On "input" HB assigns a cluster index to each character in UTF-16. + // On output where a sequence of characters have been mapped to + // a glyph they are all mapped to the cluster index of the first character. + // The next cluster index will be that of the first character in the + // next cluster. So cluster indexes may 'skip' on output. + // This can also happen if there are supplementary code-points + // such that two UTF-16 characters are needed to make one codepoint. + // In RTL text you need to count down. + // So the following code tries to build the reverse map as expected + // by calling code. + + storeGVData(env, gvdata, slot, baseIndex, startPt, + glyphCount, glyphInfo, glyphPos, direction); + + hb_buffer_destroy (buffer); + hb_font_destroy(hbfont); + free((void*)jdkFontInfo); + if (features != NULL) free(features); + + return JNI_TRUE; +} + diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-atomic-private.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-atomic-private.hh new file mode 100644 index 00000000000..778e30bc2e8 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-atomic-private.hh @@ -0,0 +1,164 @@ +/* + * Copyright © 2007 Chris Wilson + * Copyright © 2009,2010 Red Hat, Inc. + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Contributor(s): + * Chris Wilson + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_ATOMIC_PRIVATE_HH +#define HB_ATOMIC_PRIVATE_HH + +#include "hb-private.hh" + + +/* atomic_int */ + +/* We need external help for these */ + +#if defined(hb_atomic_int_impl_add) \ + && defined(hb_atomic_ptr_impl_get) \ + && defined(hb_atomic_ptr_impl_cmpexch) + +/* Defined externally, i.e. in config.h; must have typedef'ed hb_atomic_int_impl_t as well. */ + + +#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__)) + +#include + +/* MinGW has a convoluted history of supporting MemoryBarrier + * properly. As such, define a function to wrap the whole + * thing. */ +static inline void _HBMemoryBarrier (void) { +#if !defined(MemoryBarrier) + long dummy = 0; + InterlockedExchange (&dummy, 1); +#else + MemoryBarrier (); +#endif +} + +typedef LONG hb_atomic_int_impl_t; +#define HB_ATOMIC_INT_IMPL_INIT(V) (V) +#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd (&(AI), (V)) + +#define hb_atomic_ptr_impl_get(P) (_HBMemoryBarrier (), (void *) *(P)) +#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O)) + + +#elif !defined(HB_NO_MT) && defined(__APPLE__) + +#include +#ifdef __MAC_OS_X_MIN_REQUIRED +#include +#elif defined(__IPHONE_OS_MIN_REQUIRED) +#include +#endif + + +typedef int32_t hb_atomic_int_impl_t; +#define HB_ATOMIC_INT_IMPL_INIT(V) (V) +#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), &(AI)) - (V)) + +#define hb_atomic_ptr_impl_get(P) (OSMemoryBarrier (), (void *) *(P)) +#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100) +#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P)) +#else +#if __ppc64__ || __x86_64__ || __aarch64__ +#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P)) +#else +#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P)) +#endif +#endif + + +#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES) + +typedef int hb_atomic_int_impl_t; +#define HB_ATOMIC_INT_IMPL_INIT(V) (V) +#define hb_atomic_int_impl_add(AI, V) __sync_fetch_and_add (&(AI), (V)) + +#define hb_atomic_ptr_impl_get(P) (void *) (__sync_synchronize (), *(P)) +#define hb_atomic_ptr_impl_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N)) + + +#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS) + +#include +#include + +typedef unsigned int hb_atomic_int_impl_t; +#define HB_ATOMIC_INT_IMPL_INIT(V) (V) +#define hb_atomic_int_impl_add(AI, V) ( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V)) + +#define hb_atomic_ptr_impl_get(P) ( ({__machine_rw_barrier ();}), (void *) *(P)) +#define hb_atomic_ptr_impl_cmpexch(P,O,N) ( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false) + + +#elif !defined(HB_NO_MT) + +#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */ + +typedef volatile int hb_atomic_int_impl_t; +#define HB_ATOMIC_INT_IMPL_INIT(V) (V) +#define hb_atomic_int_impl_add(AI, V) (((AI) += (V)) - (V)) + +#define hb_atomic_ptr_impl_get(P) ((void *) *(P)) +#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false) + + +#else /* HB_NO_MT */ + +typedef int hb_atomic_int_impl_t; +#define HB_ATOMIC_INT_IMPL_INIT(V) (V) +#define hb_atomic_int_impl_add(AI, V) (((AI) += (V)) - (V)) + +#define hb_atomic_ptr_impl_get(P) ((void *) *(P)) +#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false) + + +#endif + + +#define HB_ATOMIC_INT_INIT(V) {HB_ATOMIC_INT_IMPL_INIT(V)} + +struct hb_atomic_int_t +{ + hb_atomic_int_impl_t v; + + inline void set_unsafe (int v_) { v = v_; } + inline int get_unsafe (void) const { return v; } + inline int inc (void) { return hb_atomic_int_impl_add (const_cast (v), 1); } + inline int dec (void) { return hb_atomic_int_impl_add (const_cast (v), -1); } +}; + + +#define hb_atomic_ptr_get(P) hb_atomic_ptr_impl_get(P) +#define hb_atomic_ptr_cmpexch(P,O,N) hb_atomic_ptr_impl_cmpexch((P),(O),(N)) + + +#endif /* HB_ATOMIC_PRIVATE_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.cc b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.cc new file mode 100644 index 00000000000..40aa17f306c --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.cc @@ -0,0 +1,479 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +/* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 199309L +#endif + +#include "hb-private.hh" + +#include "hb-object-private.hh" + +#ifdef HAVE_SYS_MMAN_H +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#include +#endif /* HAVE_SYS_MMAN_H */ + +#include +#include + + + +#ifndef HB_DEBUG_BLOB +#define HB_DEBUG_BLOB (HB_DEBUG+0) +#endif + + +struct hb_blob_t { + hb_object_header_t header; + ASSERT_POD (); + + bool immutable; + + const char *data; + unsigned int length; + hb_memory_mode_t mode; + + void *user_data; + hb_destroy_func_t destroy; +}; + + +static bool _try_writable (hb_blob_t *blob); + +static void +_hb_blob_destroy_user_data (hb_blob_t *blob) +{ + if (blob->destroy) { + blob->destroy (blob->user_data); + blob->user_data = NULL; + blob->destroy = NULL; + } +} + +/** + * hb_blob_create: (skip) + * @data: Pointer to blob data. + * @length: Length of @data in bytes. + * @mode: Memory mode for @data. + * @user_data: Data parameter to pass to @destroy. + * @destroy: Callback to call when @data is not needed anymore. + * + * Creates a new "blob" object wrapping @data. The @mode parameter is used + * to negotiate ownership and lifecycle of @data. + * + * Return value: New blob, or the empty blob if something failed or if @length is + * zero. Destroy with hb_blob_destroy(). + * + * Since: 0.9.2 + **/ +hb_blob_t * +hb_blob_create (const char *data, + unsigned int length, + hb_memory_mode_t mode, + void *user_data, + hb_destroy_func_t destroy) +{ + hb_blob_t *blob; + + if (!length || + length >= 1u << 31 || + data + length < data /* overflows */ || + !(blob = hb_object_create ())) { + if (destroy) + destroy (user_data); + return hb_blob_get_empty (); + } + + blob->data = data; + blob->length = length; + blob->mode = mode; + + blob->user_data = user_data; + blob->destroy = destroy; + + if (blob->mode == HB_MEMORY_MODE_DUPLICATE) { + blob->mode = HB_MEMORY_MODE_READONLY; + if (!_try_writable (blob)) { + hb_blob_destroy (blob); + return hb_blob_get_empty (); + } + } + + return blob; +} + +/** + * hb_blob_create_sub_blob: + * @parent: Parent blob. + * @offset: Start offset of sub-blob within @parent, in bytes. + * @length: Length of sub-blob. + * + * Returns a blob that represents a range of bytes in @parent. The new + * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it + * will never modify data in the parent blob. The parent data is not + * expected to be modified, and will result in undefined behavior if it + * is. + * + * Makes @parent immutable. + * + * Return value: New blob, or the empty blob if something failed or if + * @length is zero or @offset is beyond the end of @parent's data. Destroy + * with hb_blob_destroy(). + * + * Since: 0.9.2 + **/ +hb_blob_t * +hb_blob_create_sub_blob (hb_blob_t *parent, + unsigned int offset, + unsigned int length) +{ + hb_blob_t *blob; + + if (!length || offset >= parent->length) + return hb_blob_get_empty (); + + hb_blob_make_immutable (parent); + + blob = hb_blob_create (parent->data + offset, + MIN (length, parent->length - offset), + HB_MEMORY_MODE_READONLY, + hb_blob_reference (parent), + (hb_destroy_func_t) hb_blob_destroy); + + return blob; +} + +/** + * hb_blob_get_empty: + * + * Returns the singleton empty blob. + * + * See TODO:link object types for more information. + * + * Return value: (transfer full): the empty blob. + * + * Since: 0.9.2 + **/ +hb_blob_t * +hb_blob_get_empty (void) +{ + static const hb_blob_t _hb_blob_nil = { + HB_OBJECT_HEADER_STATIC, + + true, /* immutable */ + + NULL, /* data */ + 0, /* length */ + HB_MEMORY_MODE_READONLY, /* mode */ + + NULL, /* user_data */ + NULL /* destroy */ + }; + + return const_cast (&_hb_blob_nil); +} + +/** + * hb_blob_reference: (skip) + * @blob: a blob. + * + * Increases the reference count on @blob. + * + * See TODO:link object types for more information. + * + * Return value: @blob. + * + * Since: 0.9.2 + **/ +hb_blob_t * +hb_blob_reference (hb_blob_t *blob) +{ + return hb_object_reference (blob); +} + +/** + * hb_blob_destroy: (skip) + * @blob: a blob. + * + * Descreases the reference count on @blob, and if it reaches zero, destroys + * @blob, freeing all memory, possibly calling the destroy-callback the blob + * was created for if it has not been called already. + * + * See TODO:link object types for more information. + * + * Since: 0.9.2 + **/ +void +hb_blob_destroy (hb_blob_t *blob) +{ + if (!hb_object_destroy (blob)) return; + + _hb_blob_destroy_user_data (blob); + + free (blob); +} + +/** + * hb_blob_set_user_data: (skip) + * @blob: a blob. + * @key: key for data to set. + * @data: data to set. + * @destroy: callback to call when @data is not needed anymore. + * @replace: whether to replace an existing data with the same key. + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_blob_set_user_data (hb_blob_t *blob, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (blob, key, data, destroy, replace); +} + +/** + * hb_blob_get_user_data: (skip) + * @blob: a blob. + * @key: key for data to get. + * + * + * + * Return value: (transfer none): + * + * Since: 0.9.2 + **/ +void * +hb_blob_get_user_data (hb_blob_t *blob, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (blob, key); +} + + +/** + * hb_blob_make_immutable: + * @blob: a blob. + * + * + * + * Since: 0.9.2 + **/ +void +hb_blob_make_immutable (hb_blob_t *blob) +{ + if (hb_object_is_inert (blob)) + return; + + blob->immutable = true; +} + +/** + * hb_blob_is_immutable: + * @blob: a blob. + * + * + * + * Return value: TODO + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_blob_is_immutable (hb_blob_t *blob) +{ + return blob->immutable; +} + + +/** + * hb_blob_get_length: + * @blob: a blob. + * + * + * + * Return value: the length of blob data in bytes. + * + * Since: 0.9.2 + **/ +unsigned int +hb_blob_get_length (hb_blob_t *blob) +{ + return blob->length; +} + +/** + * hb_blob_get_data: + * @blob: a blob. + * @length: (out): + * + * + * + * Returns: (transfer none) (array length=length): + * + * Since: 0.9.2 + **/ +const char * +hb_blob_get_data (hb_blob_t *blob, unsigned int *length) +{ + if (length) + *length = blob->length; + + return blob->data; +} + +/** + * hb_blob_get_data_writable: + * @blob: a blob. + * @length: (out): output length of the writable data. + * + * Tries to make blob data writable (possibly copying it) and + * return pointer to data. + * + * Fails if blob has been made immutable, or if memory allocation + * fails. + * + * Returns: (transfer none) (array length=length): Writable blob data, + * or %NULL if failed. + * + * Since: 0.9.2 + **/ +char * +hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length) +{ + if (!_try_writable (blob)) { + if (length) + *length = 0; + + return NULL; + } + + if (length) + *length = blob->length; + + return const_cast (blob->data); +} + + +static hb_bool_t +_try_make_writable_inplace_unix (hb_blob_t *blob) +{ +#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT) + uintptr_t pagesize = -1, mask, length; + const char *addr; + +#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE) + pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE); +#elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) + pagesize = (uintptr_t) sysconf (_SC_PAGESIZE); +#elif defined(HAVE_GETPAGESIZE) + pagesize = (uintptr_t) getpagesize (); +#endif + + if ((uintptr_t) -1L == pagesize) { + DEBUG_MSG_FUNC (BLOB, blob, "failed to get pagesize: %s", strerror (errno)); + return false; + } + DEBUG_MSG_FUNC (BLOB, blob, "pagesize is %lu", (unsigned long) pagesize); + + mask = ~(pagesize-1); + addr = (const char *) (((uintptr_t) blob->data) & mask); + length = (const char *) (((uintptr_t) blob->data + blob->length + pagesize-1) & mask) - addr; + DEBUG_MSG_FUNC (BLOB, blob, + "calling mprotect on [%p..%p] (%lu bytes)", + addr, addr+length, (unsigned long) length); + if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) { + DEBUG_MSG_FUNC (BLOB, blob, "mprotect failed: %s", strerror (errno)); + return false; + } + + blob->mode = HB_MEMORY_MODE_WRITABLE; + + DEBUG_MSG_FUNC (BLOB, blob, + "successfully made [%p..%p] (%lu bytes) writable\n", + addr, addr+length, (unsigned long) length); + return true; +#else + return false; +#endif +} + +static bool +_try_writable_inplace (hb_blob_t *blob) +{ + DEBUG_MSG_FUNC (BLOB, blob, "making writable inplace\n"); + + if (_try_make_writable_inplace_unix (blob)) + return true; + + DEBUG_MSG_FUNC (BLOB, blob, "making writable -> FAILED\n"); + + /* Failed to make writable inplace, mark that */ + blob->mode = HB_MEMORY_MODE_READONLY; + return false; +} + +static bool +_try_writable (hb_blob_t *blob) +{ + if (blob->immutable) + return false; + + if (blob->mode == HB_MEMORY_MODE_WRITABLE) + return true; + + if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && _try_writable_inplace (blob)) + return true; + + if (blob->mode == HB_MEMORY_MODE_WRITABLE) + return true; + + + DEBUG_MSG_FUNC (BLOB, blob, "current data is -> %p\n", blob->data); + + char *new_data; + + new_data = (char *) malloc (blob->length); + if (unlikely (!new_data)) + return false; + + DEBUG_MSG_FUNC (BLOB, blob, "dupped successfully -> %p\n", blob->data); + + memcpy (new_data, blob->data, blob->length); + _hb_blob_destroy_user_data (blob); + blob->mode = HB_MEMORY_MODE_WRITABLE; + blob->data = new_data; + blob->user_data = new_data; + blob->destroy = free; + + return true; +} diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.h b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.h new file mode 100644 index 00000000000..6559ca2f407 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-blob.h @@ -0,0 +1,126 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#ifndef HB_H_IN +#error "Include instead." +#endif + +#ifndef HB_BLOB_H +#define HB_BLOB_H + +#include "hb-common.h" + +HB_BEGIN_DECLS + + +/* + * Note re various memory-modes: + * + * - In no case shall the HarfBuzz client modify memory + * that is passed to HarfBuzz in a blob. If there is + * any such possibility, MODE_DUPLICATE should be used + * such that HarfBuzz makes a copy immediately, + * + * - Use MODE_READONLY otherse, unless you really really + * really know what you are doing, + * + * - MODE_WRITABLE is appropriate if you really made a + * copy of data solely for the purpose of passing to + * HarfBuzz and doing that just once (no reuse!), + * + * - If the font is mmap()ed, it's ok to use + * READONLY_MAY_MAKE_WRITABLE, however, using that mode + * correctly is very tricky. Use MODE_READONLY instead. + */ +typedef enum { + HB_MEMORY_MODE_DUPLICATE, + HB_MEMORY_MODE_READONLY, + HB_MEMORY_MODE_WRITABLE, + HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE +} hb_memory_mode_t; + +typedef struct hb_blob_t hb_blob_t; + +hb_blob_t * +hb_blob_create (const char *data, + unsigned int length, + hb_memory_mode_t mode, + void *user_data, + hb_destroy_func_t destroy); + +/* Always creates with MEMORY_MODE_READONLY. + * Even if the parent blob is writable, we don't + * want the user of the sub-blob to be able to + * modify the parent data as that data may be + * shared among multiple sub-blobs. + */ +hb_blob_t * +hb_blob_create_sub_blob (hb_blob_t *parent, + unsigned int offset, + unsigned int length); + +hb_blob_t * +hb_blob_get_empty (void); + +hb_blob_t * +hb_blob_reference (hb_blob_t *blob); + +void +hb_blob_destroy (hb_blob_t *blob); + +hb_bool_t +hb_blob_set_user_data (hb_blob_t *blob, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + + +void * +hb_blob_get_user_data (hb_blob_t *blob, + hb_user_data_key_t *key); + + +void +hb_blob_make_immutable (hb_blob_t *blob); + +hb_bool_t +hb_blob_is_immutable (hb_blob_t *blob); + + +unsigned int +hb_blob_get_length (hb_blob_t *blob); + +const char * +hb_blob_get_data (hb_blob_t *blob, unsigned int *length); + +char * +hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length); + + +HB_END_DECLS + +#endif /* HB_BLOB_H */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-deserialize-json.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-deserialize-json.hh new file mode 100644 index 00000000000..5d4387149ac --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-deserialize-json.hh @@ -0,0 +1,643 @@ + +#line 1 "hb-buffer-deserialize-json.rl" +/* + * Copyright © 2013 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_BUFFER_DESERIALIZE_JSON_HH +#define HB_BUFFER_DESERIALIZE_JSON_HH + +#include "hb-private.hh" + + +#line 36 "hb-buffer-deserialize-json.hh" +static const unsigned char _deserialize_json_trans_keys[] = { + 0u, 0u, 9u, 123u, 9u, 34u, 97u, 103u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, + 48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, + 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, + 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, + 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, + 65u, 122u, 34u, 122u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 123u, 0u, 0u, 0 +}; + +static const char _deserialize_json_key_spans[] = { + 0, 115, 26, 7, 2, 1, 50, 49, + 10, 117, 117, 117, 1, 50, 49, 10, + 117, 117, 1, 1, 50, 49, 117, 117, + 2, 1, 50, 49, 10, 117, 117, 1, + 50, 49, 10, 117, 117, 1, 50, 49, + 58, 89, 117, 117, 85, 115, 0 +}; + +static const short _deserialize_json_index_offsets[] = { + 0, 0, 116, 143, 151, 154, 156, 207, + 257, 268, 386, 504, 622, 624, 675, 725, + 736, 854, 972, 974, 976, 1027, 1077, 1195, + 1313, 1316, 1318, 1369, 1419, 1430, 1548, 1666, + 1668, 1719, 1769, 1780, 1898, 2016, 2018, 2069, + 2119, 2178, 2268, 2386, 2504, 2590, 2706 +}; + +static const char _deserialize_json_indicies[] = { + 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 1, 3, 3, 3, + 3, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 1, 4, 1, + 5, 1, 6, 7, 1, 1, 8, 1, + 9, 10, 1, 11, 1, 11, 11, 11, + 11, 11, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 11, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 12, 1, + 12, 12, 12, 12, 12, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 12, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 13, 1, 1, 14, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 1, 16, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 1, 18, 18, 18, + 18, 18, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 18, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 19, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 20, 1, 21, 21, 21, 21, 21, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 21, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 22, + 1, 18, 18, 18, 18, 18, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 18, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 19, 1, 1, 1, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 20, 1, 23, + 1, 23, 23, 23, 23, 23, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 23, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 24, 1, 24, 24, 24, 24, + 24, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 24, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 25, 1, 1, 26, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 1, 28, 29, + 29, 29, 29, 29, 29, 29, 29, 29, + 1, 30, 30, 30, 30, 30, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 30, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 31, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 32, 1, 30, + 30, 30, 30, 30, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 30, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 31, 1, 1, 1, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 32, 1, 33, 1, 34, + 1, 34, 34, 34, 34, 34, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 34, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 35, 1, 35, 35, 35, 35, + 35, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 35, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 36, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 1, 38, 38, + 38, 38, 38, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 38, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 39, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 40, 1, 38, 38, 38, 38, + 38, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 38, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 39, + 1, 1, 1, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 40, 1, 42, 43, 1, 44, 1, 44, + 44, 44, 44, 44, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 44, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 45, 1, 45, 45, 45, 45, 45, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 45, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 46, 1, + 1, 47, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 1, 49, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 1, 51, + 51, 51, 51, 51, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 51, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 52, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 53, 1, 51, 51, 51, + 51, 51, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 51, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 52, 1, 1, 1, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 53, 1, 54, 1, 54, 54, 54, + 54, 54, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 54, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 55, 1, + 55, 55, 55, 55, 55, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 55, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 56, 1, 1, 57, + 58, 58, 58, 58, 58, 58, 58, 58, + 58, 1, 59, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 1, 61, 61, 61, + 61, 61, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 61, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 62, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 63, 1, 61, 61, 61, 61, 61, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 61, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 62, 1, + 1, 1, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 63, + 1, 64, 1, 64, 64, 64, 64, 64, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 64, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 65, 1, 65, 65, + 65, 65, 65, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 65, 1, 66, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 67, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 1, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 1, 1, 1, 1, 1, 1, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 1, 70, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 71, 71, + 1, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 1, 1, 1, 1, 1, + 1, 1, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 1, 1, 1, 1, + 71, 1, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 1, 72, 72, 72, + 72, 72, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 72, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 73, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 74, 1, 72, 72, 72, 72, 72, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 72, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 73, 1, + 1, 1, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 74, + 1, 76, 76, 76, 76, 76, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 76, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 77, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 78, 1, 0, + 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 0 +}; + +static const char _deserialize_json_trans_targs[] = { + 1, 0, 2, 2, 3, 4, 18, 24, + 37, 5, 12, 6, 7, 8, 9, 11, + 9, 11, 10, 2, 44, 10, 44, 13, + 14, 15, 16, 17, 16, 17, 10, 2, + 44, 19, 20, 21, 22, 23, 10, 2, + 44, 23, 25, 31, 26, 27, 28, 29, + 30, 29, 30, 10, 2, 44, 32, 33, + 34, 35, 36, 35, 36, 10, 2, 44, + 38, 39, 40, 42, 43, 41, 10, 41, + 10, 2, 44, 43, 44, 45, 46 +}; + +static const char _deserialize_json_trans_actions[] = { + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 2, 2, + 0, 0, 3, 3, 4, 0, 5, 0, + 0, 2, 2, 2, 0, 0, 6, 6, + 7, 0, 0, 0, 2, 2, 8, 8, + 9, 0, 0, 0, 0, 0, 2, 2, + 2, 0, 0, 10, 10, 11, 0, 0, + 2, 2, 2, 0, 0, 12, 12, 13, + 0, 0, 0, 2, 2, 2, 14, 0, + 15, 15, 16, 0, 0, 0, 0 +}; + +static const int deserialize_json_start = 1; +static const int deserialize_json_first_final = 44; +static const int deserialize_json_error = 0; + +static const int deserialize_json_en_main = 1; + + +#line 97 "hb-buffer-deserialize-json.rl" + + +static hb_bool_t +_hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer, + const char *buf, + unsigned int buf_len, + const char **end_ptr, + hb_font_t *font) +{ + const char *p = buf, *pe = buf + buf_len; + + /* Ensure we have positions. */ + (void) hb_buffer_get_glyph_positions (buffer, NULL); + + while (p < pe && ISSPACE (*p)) + p++; + if (p < pe && *p == (buffer->len ? ',' : '[')) + { + *end_ptr = ++p; + } + + const char *tok = NULL; + int cs; + hb_glyph_info_t info = {0}; + hb_glyph_position_t pos = {0}; + +#line 466 "hb-buffer-deserialize-json.hh" + { + cs = deserialize_json_start; + } + +#line 471 "hb-buffer-deserialize-json.hh" + { + int _slen; + int _trans; + const unsigned char *_keys; + const char *_inds; + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _deserialize_json_trans_keys + (cs<<1); + _inds = _deserialize_json_indicies + _deserialize_json_index_offsets[cs]; + + _slen = _deserialize_json_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && + (*p) <= _keys[1] ? + (*p) - _keys[0] : _slen ]; + + cs = _deserialize_json_trans_targs[_trans]; + + if ( _deserialize_json_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _deserialize_json_trans_actions[_trans] ) { + case 1: +#line 38 "hb-buffer-deserialize-json.rl" + { + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); +} + break; + case 5: +#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 2: +#line 51 "hb-buffer-deserialize-json.rl" + { + tok = p; +} + break; + case 14: +#line 55 "hb-buffer-deserialize-json.rl" + { + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} + break; + case 15: +#line 62 "hb-buffer-deserialize-json.rl" + { if (!parse_uint (tok, p, &info.codepoint)) return false; } + break; + case 8: +#line 63 "hb-buffer-deserialize-json.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } + break; + case 10: +#line 64 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.x_offset )) return false; } + break; + case 12: +#line 65 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } + break; + case 3: +#line 66 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } + break; + case 6: +#line 67 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } + break; + case 16: +#line 62 "hb-buffer-deserialize-json.rl" + { if (!parse_uint (tok, p, &info.codepoint)) return false; } +#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 9: +#line 63 "hb-buffer-deserialize-json.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 11: +#line 64 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.x_offset )) return false; } +#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 13: +#line 65 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 4: +#line 66 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 7: +#line 67 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 624 "hb-buffer-deserialize-json.hh" + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + _out: {} + } + +#line 125 "hb-buffer-deserialize-json.rl" + + + *end_ptr = p; + + return p == pe && *(p-1) != ']'; +} + +#endif /* HB_BUFFER_DESERIALIZE_JSON_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-deserialize-text.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-deserialize-text.hh new file mode 100644 index 00000000000..c45442c0274 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-deserialize-text.hh @@ -0,0 +1,571 @@ + +#line 1 "hb-buffer-deserialize-text.rl" +/* + * Copyright © 2013 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH +#define HB_BUFFER_DESERIALIZE_TEXT_HH + +#include "hb-private.hh" + + +#line 36 "hb-buffer-deserialize-text.hh" +static const unsigned char _deserialize_text_trans_keys[] = { + 0u, 0u, 9u, 122u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, + 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, + 9u, 122u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, + 9u, 124u, 9u, 124u, 9u, 124u, 0 +}; + +static const char _deserialize_text_key_spans[] = { + 0, 114, 13, 10, 13, 10, 10, 13, + 10, 1, 13, 10, 14, 116, 116, 0, + 114, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116 +}; + +static const short _deserialize_text_index_offsets[] = { + 0, 0, 115, 129, 140, 154, 165, 176, + 190, 201, 203, 217, 228, 243, 360, 477, + 478, 593, 710, 827, 944, 1061, 1178, 1295, + 1412, 1529, 1646 +}; + +static const char _deserialize_text_indicies[] = { + 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 1, 1, 1, 1, 1, 1, + 1, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 1, 1, 1, 1, 1, + 1, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 1, 5, 1, 1, 6, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 1, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 1, 10, 1, 1, + 11, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 1, 13, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 1, 15, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 1, 17, 1, 1, 18, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 1, 20, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 1, 22, 1, 23, 1, 1, 24, + 25, 25, 25, 25, 25, 25, 25, 25, + 25, 1, 26, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 1, 22, 1, 1, + 1, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 1, 28, 28, 28, 28, + 28, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 28, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 29, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 30, 1, 1, 31, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 32, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 33, + 1, 34, 34, 34, 34, 34, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 34, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 35, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 36, 1, 1, 0, + 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 1, 1, 1, 1, 1, 1, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 1, 28, 28, 28, 28, 28, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 28, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 29, 1, 1, 1, + 1, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 1, 1, 1, 30, 1, + 1, 31, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 32, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 33, 1, 38, + 38, 38, 38, 38, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 38, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 39, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 40, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 41, 1, 42, 42, 42, 42, + 42, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 42, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 43, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 44, + 1, 42, 42, 42, 42, 42, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 42, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 43, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 44, 1, 38, 38, + 38, 38, 38, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 38, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 39, 1, 1, 1, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 40, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 41, 1, 45, 45, 45, 45, 45, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 45, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 46, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 47, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 48, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 49, 1, + 50, 50, 50, 50, 50, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 50, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 51, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 52, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 53, 1, 50, 50, 50, + 50, 50, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 50, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 51, + 1, 1, 1, 1, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 52, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 53, 1, 45, 45, 45, 45, 45, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 45, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 46, 1, 1, 1, + 1, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 1, 1, 1, 1, 1, + 1, 47, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 48, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 49, 1, 28, + 28, 28, 28, 28, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 28, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 29, 1, 55, 55, 1, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, + 1, 1, 1, 30, 1, 1, 31, 55, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 1, 1, 32, 1, 55, 1, 55, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 1, 33, 1, 0 +}; + +static const char _deserialize_text_trans_targs[] = { + 1, 0, 13, 17, 26, 3, 18, 21, + 18, 21, 5, 19, 20, 19, 20, 22, + 25, 8, 9, 12, 9, 12, 10, 11, + 23, 24, 23, 24, 14, 2, 6, 7, + 15, 16, 14, 15, 16, 17, 14, 4, + 15, 16, 14, 15, 16, 14, 2, 7, + 15, 16, 14, 2, 15, 16, 25, 26 +}; + +static const char _deserialize_text_trans_actions[] = { + 0, 0, 1, 1, 1, 2, 2, 2, + 0, 0, 2, 2, 2, 0, 0, 2, + 2, 2, 2, 2, 0, 0, 3, 2, + 2, 2, 0, 0, 4, 5, 5, 5, + 4, 4, 0, 0, 0, 0, 6, 7, + 6, 6, 8, 8, 8, 9, 10, 10, + 9, 9, 11, 12, 11, 11, 0, 0 +}; + +static const char _deserialize_text_eof_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 4, 0, 0, + 0, 4, 6, 8, 8, 6, 9, 11, + 11, 9, 4 +}; + +static const int deserialize_text_start = 1; +static const int deserialize_text_first_final = 13; +static const int deserialize_text_error = 0; + +static const int deserialize_text_en_main = 1; + + +#line 91 "hb-buffer-deserialize-text.rl" + + +static hb_bool_t +_hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer, + const char *buf, + unsigned int buf_len, + const char **end_ptr, + hb_font_t *font) +{ + const char *p = buf, *pe = buf + buf_len; + + /* Ensure we have positions. */ + (void) hb_buffer_get_glyph_positions (buffer, NULL); + + while (p < pe && ISSPACE (*p)) + p++; + if (p < pe && *p == (buffer->len ? '|' : '[')) + { + *end_ptr = ++p; + } + + const char *eof = pe, *tok = NULL; + int cs; + hb_glyph_info_t info = {0}; + hb_glyph_position_t pos = {0}; + +#line 343 "hb-buffer-deserialize-text.hh" + { + cs = deserialize_text_start; + } + +#line 348 "hb-buffer-deserialize-text.hh" + { + int _slen; + int _trans; + const unsigned char *_keys; + const char *_inds; + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _deserialize_text_trans_keys + (cs<<1); + _inds = _deserialize_text_indicies + _deserialize_text_index_offsets[cs]; + + _slen = _deserialize_text_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && + (*p) <= _keys[1] ? + (*p) - _keys[0] : _slen ]; + + cs = _deserialize_text_trans_targs[_trans]; + + if ( _deserialize_text_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _deserialize_text_trans_actions[_trans] ) { + case 2: +#line 51 "hb-buffer-deserialize-text.rl" + { + tok = p; +} + break; + case 5: +#line 55 "hb-buffer-deserialize-text.rl" + { + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} + break; + case 10: +#line 62 "hb-buffer-deserialize-text.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } + break; + case 3: +#line 63 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.x_offset )) return false; } + break; + case 12: +#line 64 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } + break; + case 7: +#line 65 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } + break; + case 1: +#line 38 "hb-buffer-deserialize-text.rl" + { + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); +} +#line 51 "hb-buffer-deserialize-text.rl" + { + tok = p; +} + break; + case 4: +#line 55 "hb-buffer-deserialize-text.rl" + { + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 9: +#line 62 "hb-buffer-deserialize-text.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 11: +#line 64 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 6: +#line 65 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 8: +#line 66 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 480 "hb-buffer-deserialize-text.hh" + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + switch ( _deserialize_text_eof_actions[cs] ) { + case 4: +#line 55 "hb-buffer-deserialize-text.rl" + { + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 9: +#line 62 "hb-buffer-deserialize-text.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 11: +#line 64 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 6: +#line 65 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 8: +#line 66 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 557 "hb-buffer-deserialize-text.hh" + } + } + + _out: {} + } + +#line 119 "hb-buffer-deserialize-text.rl" + + + *end_ptr = p; + + return p == pe && *(p-1) != ']'; +} + +#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-private.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-private.hh new file mode 100644 index 00000000000..8f0f1d6dd72 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-private.hh @@ -0,0 +1,220 @@ +/* + * Copyright © 1998-2004 David Turner and Werner Lemberg + * Copyright © 2004,2007,2009,2010 Red Hat, Inc. + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Owen Taylor, Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_BUFFER_PRIVATE_HH +#define HB_BUFFER_PRIVATE_HH + +#include "hb-private.hh" +#include "hb-object-private.hh" +#include "hb-unicode-private.hh" + + +ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20); +ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)); + + +/* + * hb_buffer_t + */ + +struct hb_buffer_t { + hb_object_header_t header; + ASSERT_POD (); + + /* Information about how the text in the buffer should be treated */ + hb_unicode_funcs_t *unicode; /* Unicode functions */ + hb_buffer_flags_t flags; /* BOT / EOT / etc. */ + hb_buffer_cluster_level_t cluster_level; + hb_codepoint_t replacement; /* U+FFFD or something else. */ + + /* Buffer contents */ + hb_buffer_content_type_t content_type; + hb_segment_properties_t props; /* Script, language, direction */ + + bool in_error; /* Allocation failed */ + bool have_output; /* Whether we have an output buffer going on */ + bool have_positions; /* Whether we have positions */ + + unsigned int idx; /* Cursor into ->info and ->pos arrays */ + unsigned int len; /* Length of ->info and ->pos arrays */ + unsigned int out_len; /* Length of ->out array if have_output */ + + unsigned int allocated; /* Length of allocated arrays */ + hb_glyph_info_t *info; + hb_glyph_info_t *out_info; + hb_glyph_position_t *pos; + + inline hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; } + inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; } + + inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; } + inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; } + + inline hb_glyph_info_t &prev (void) { return out_info[out_len - 1]; } + inline hb_glyph_info_t prev (void) const { return info[out_len - 1]; } + + inline bool has_separate_output (void) const { return info != out_info; } + + unsigned int serial; + + /* These reflect current allocations of the bytes in glyph_info_t's var1 and var2. */ + uint8_t allocated_var_bytes[8]; + const char *allocated_var_owner[8]; + + /* Text before / after the main buffer contents. + * Always in Unicode, and ordered outward. + * Index 0 is for "pre-context", 1 for "post-context". */ + static const unsigned int CONTEXT_LENGTH = 5; + hb_codepoint_t context[2][CONTEXT_LENGTH]; + unsigned int context_len[2]; + + + /* Methods */ + + HB_INTERNAL void reset (void); + HB_INTERNAL void clear (void); + + inline unsigned int backtrack_len (void) const + { return have_output? out_len : idx; } + inline unsigned int lookahead_len (void) const + { return len - idx; } + inline unsigned int next_serial (void) { return serial++; } + + HB_INTERNAL void allocate_var (unsigned int byte_i, unsigned int count, const char *owner); + HB_INTERNAL void deallocate_var (unsigned int byte_i, unsigned int count, const char *owner); + HB_INTERNAL void assert_var (unsigned int byte_i, unsigned int count, const char *owner); + HB_INTERNAL void deallocate_var_all (void); + + HB_INTERNAL void add (hb_codepoint_t codepoint, + unsigned int cluster); + HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info); + + HB_INTERNAL void reverse_range (unsigned int start, unsigned int end); + HB_INTERNAL void reverse (void); + HB_INTERNAL void reverse_clusters (void); + HB_INTERNAL void guess_segment_properties (void); + + HB_INTERNAL void swap_buffers (void); + HB_INTERNAL void remove_output (void); + HB_INTERNAL void clear_output (void); + HB_INTERNAL void clear_positions (void); + + HB_INTERNAL void replace_glyphs (unsigned int num_in, + unsigned int num_out, + const hb_codepoint_t *glyph_data); + + HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index); + /* Makes a copy of the glyph at idx to output and replace glyph_index */ + HB_INTERNAL void output_glyph (hb_codepoint_t glyph_index); + HB_INTERNAL void output_info (const hb_glyph_info_t &glyph_info); + /* Copies glyph at idx to output but doesn't advance idx */ + HB_INTERNAL void copy_glyph (void); + HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */ + /* Copies glyph at idx to output and advance idx. + * If there's no output, just advance idx. */ + inline void + next_glyph (void) + { + if (have_output) + { + if (unlikely (out_info != info || out_len != idx)) { + if (unlikely (!make_room_for (1, 1))) return; + out_info[out_len] = info[idx]; + } + out_len++; + } + + idx++; + } + + /* Advance idx without copying to output. */ + inline void skip_glyph (void) { idx++; } + + inline void reset_masks (hb_mask_t mask) + { + for (unsigned int j = 0; j < len; j++) + info[j].mask = mask; + } + inline void add_masks (hb_mask_t mask) + { + for (unsigned int j = 0; j < len; j++) + info[j].mask |= mask; + } + HB_INTERNAL void set_masks (hb_mask_t value, + hb_mask_t mask, + unsigned int cluster_start, + unsigned int cluster_end); + + HB_INTERNAL void merge_clusters (unsigned int start, + unsigned int end) + { + if (end - start < 2) + return; + merge_clusters_impl (start, end); + } + HB_INTERNAL void merge_clusters_impl (unsigned int start, + unsigned int end); + HB_INTERNAL void merge_out_clusters (unsigned int start, + unsigned int end); + /* Merge clusters for deleting current glyph, and skip it. */ + HB_INTERNAL void delete_glyph (void); + + /* Internal methods */ + HB_INTERNAL bool enlarge (unsigned int size); + + inline bool ensure (unsigned int size) + { return likely (!size || size < allocated) ? true : enlarge (size); } + + inline bool ensure_inplace (unsigned int size) + { return likely (!size || size < allocated); } + + HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out); + HB_INTERNAL bool shift_forward (unsigned int count); + + typedef long scratch_buffer_t; + HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size); + + inline void clear_context (unsigned int side) { context_len[side] = 0; } + + HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *)); +}; + + +#define HB_BUFFER_XALLOCATE_VAR(b, func, var, owner) \ + b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \ + sizeof (b->info[0].var), owner) +#define HB_BUFFER_ALLOCATE_VAR(b, var) \ + HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var (), #var) +#define HB_BUFFER_DEALLOCATE_VAR(b, var) \ + HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var (), #var) +#define HB_BUFFER_ASSERT_VAR(b, var) \ + HB_BUFFER_XALLOCATE_VAR (b, assert_var, var (), #var) + + +#endif /* HB_BUFFER_PRIVATE_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-serialize.cc b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-serialize.cc new file mode 100644 index 00000000000..8da89bd3248 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer-serialize.cc @@ -0,0 +1,418 @@ +/* + * Copyright © 2012,2013 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-buffer-private.hh" + + +static const char *serialize_formats[] = { + "text", + "json", + NULL +}; + +/** + * hb_buffer_serialize_list_formats: + * + * + * + * Return value: (transfer none): + * + * Since: 0.9.2 + **/ +const char ** +hb_buffer_serialize_list_formats (void) +{ + return serialize_formats; +} + +/** + * hb_buffer_serialize_format_from_string: + * @str: + * @len: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_buffer_serialize_format_t +hb_buffer_serialize_format_from_string (const char *str, int len) +{ + /* Upper-case it. */ + return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020u); +} + +/** + * hb_buffer_serialize_format_to_string: + * @format: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +const char * +hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format) +{ + switch (format) + { + case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0]; + case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1]; + default: + case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return NULL; + } +} + +static unsigned int +_hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, + hb_buffer_serialize_flags_t flags) +{ + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); + hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ? + NULL : hb_buffer_get_glyph_positions (buffer, NULL); + + *buf_consumed = 0; + for (unsigned int i = start; i < end; i++) + { + char b[1024]; + char *p = b; + + /* In the following code, we know b is large enough that no overflow can happen. */ + +#define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END + + if (i) + *p++ = ','; + + *p++ = '{'; + + APPEND ("\"g\":"); + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) + { + char g[128]; + hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g)); + *p++ = '"'; + for (char *q = g; *q; q++) { + if (*q == '"') + *p++ = '\\'; + *p++ = *q; + } + *p++ = '"'; + } + else + p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint)); + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { + p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster)); + } + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) + { + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d", + pos[i].x_offset, pos[i].y_offset); + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d", + pos[i].x_advance, pos[i].y_advance); + } + + if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) + { + hb_glyph_extents_t extents; + hb_font_get_glyph_extents(font, info[i].codepoint, &extents); + p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d", + extents.x_bearing, extents.y_bearing)); + p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d", + extents.width, extents.height)); + } + + *p++ = '}'; + + unsigned int l = p - b; + if (buf_size > l) + { + memcpy (buf, b, l); + buf += l; + buf_size -= l; + *buf_consumed += l; + *buf = '\0'; + } else + return i - start; + } + + return end - start; +} + +static unsigned int +_hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, + hb_buffer_serialize_flags_t flags) +{ + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); + hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ? + NULL : hb_buffer_get_glyph_positions (buffer, NULL); + + *buf_consumed = 0; + for (unsigned int i = start; i < end; i++) + { + char b[1024]; + char *p = b; + + /* In the following code, we know b is large enough that no overflow can happen. */ + + if (i) + *p++ = '|'; + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) + { + hb_font_glyph_to_string (font, info[i].codepoint, p, 128); + p += strlen (p); + } + else + p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint)); + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { + p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster)); + } + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) + { + if (pos[i].x_offset || pos[i].y_offset) + p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset)); + + *p++ = '+'; + p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance)); + if (pos[i].y_advance) + p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance)); + } + + if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) + { + hb_glyph_extents_t extents; + hb_font_get_glyph_extents(font, info[i].codepoint, &extents); + p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height)); + } + + unsigned int l = p - b; + if (buf_size > l) + { + memcpy (buf, b, l); + buf += l; + buf_size -= l; + *buf_consumed += l; + *buf = '\0'; + } else + return i - start; + } + + return end - start; +} + +/* Returns number of items, starting at start, that were serialized. */ +/** + * hb_buffer_serialize_glyphs: + * @buffer: a buffer. + * @start: + * @end: + * @buf: (array length=buf_size): + * @buf_size: + * @buf_consumed: (out): + * @font: + * @format: + * @flags: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +unsigned int +hb_buffer_serialize_glyphs (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, /* May be NULL */ + hb_font_t *font, /* May be NULL */ + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags) +{ + assert (start <= end && end <= buffer->len); + + unsigned int sconsumed; + if (!buf_consumed) + buf_consumed = &sconsumed; + *buf_consumed = 0; + + assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || + buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); + + if (unlikely (start == end)) + return 0; + + if (!font) + font = hb_font_get_empty (); + + switch (format) + { + case HB_BUFFER_SERIALIZE_FORMAT_TEXT: + return _hb_buffer_serialize_glyphs_text (buffer, start, end, + buf, buf_size, buf_consumed, + font, flags); + + case HB_BUFFER_SERIALIZE_FORMAT_JSON: + return _hb_buffer_serialize_glyphs_json (buffer, start, end, + buf, buf_size, buf_consumed, + font, flags); + + default: + case HB_BUFFER_SERIALIZE_FORMAT_INVALID: + return 0; + + } +} + + +static hb_bool_t +parse_uint (const char *pp, const char *end, uint32_t *pv) +{ + char buf[32]; + unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); + strncpy (buf, pp, len); + buf[len] = '\0'; + + char *p = buf; + char *pend = p; + uint32_t v; + + errno = 0; + v = strtol (p, &pend, 10); + if (errno || p == pend || pend - p != end - pp) + return false; + + *pv = v; + return true; +} + +static hb_bool_t +parse_int (const char *pp, const char *end, int32_t *pv) +{ + char buf[32]; + unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); + strncpy (buf, pp, len); + buf[len] = '\0'; + + char *p = buf; + char *pend = p; + int32_t v; + + errno = 0; + v = strtol (p, &pend, 10); + if (errno || p == pend || pend - p != end - pp) + return false; + + *pv = v; + return true; +} + +#include "hb-buffer-deserialize-json.hh" +#include "hb-buffer-deserialize-text.hh" + +/** + * hb_buffer_deserialize_glyphs: + * @buffer: a buffer. + * @buf: (array length=buf_len): + * @buf_len: + * @end_ptr: (out): + * @font: + * @format: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, + const char *buf, + int buf_len, /* -1 means nul-terminated */ + const char **end_ptr, /* May be NULL */ + hb_font_t *font, /* May be NULL */ + hb_buffer_serialize_format_t format) +{ + const char *end; + if (!end_ptr) + end_ptr = &end; + *end_ptr = buf; + + assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || + buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); + + if (buf_len == -1) + buf_len = strlen (buf); + + if (!buf_len) + { + *end_ptr = buf; + return false; + } + + hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); + + if (!font) + font = hb_font_get_empty (); + + switch (format) + { + case HB_BUFFER_SERIALIZE_FORMAT_TEXT: + return _hb_buffer_deserialize_glyphs_text (buffer, + buf, buf_len, end_ptr, + font); + + case HB_BUFFER_SERIALIZE_FORMAT_JSON: + return _hb_buffer_deserialize_glyphs_json (buffer, + buf, buf_len, end_ptr, + font); + + default: + case HB_BUFFER_SERIALIZE_FORMAT_INVALID: + return false; + + } +} diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer.cc b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer.cc new file mode 100644 index 00000000000..62177f3e9c8 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer.cc @@ -0,0 +1,1701 @@ +/* + * Copyright © 1998-2004 David Turner and Werner Lemberg + * Copyright © 2004,2007,2009,2010 Red Hat, Inc. + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Owen Taylor, Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-buffer-private.hh" +#include "hb-utf-private.hh" + + +#ifndef HB_DEBUG_BUFFER +#define HB_DEBUG_BUFFER (HB_DEBUG+0) +#endif + + +/** + * Since: 0.9.7 + **/ +hb_bool_t +hb_segment_properties_equal (const hb_segment_properties_t *a, + const hb_segment_properties_t *b) +{ + return a->direction == b->direction && + a->script == b->script && + a->language == b->language && + a->reserved1 == b->reserved1 && + a->reserved2 == b->reserved2; + +} + +/** + * Since: 0.9.7 + **/ +unsigned int +hb_segment_properties_hash (const hb_segment_properties_t *p) +{ + return (unsigned int) p->direction ^ + (unsigned int) p->script ^ + (intptr_t) (p->language); +} + + + +/* Here is how the buffer works internally: + * + * There are two info pointers: info and out_info. They always have + * the same allocated size, but different lengths. + * + * As an optimization, both info and out_info may point to the + * same piece of memory, which is owned by info. This remains the + * case as long as out_len doesn't exceed i at any time. + * In that case, swap_buffers() is no-op and the glyph operations operate + * mostly in-place. + * + * As soon as out_info gets longer than info, out_info is moved over + * to an alternate buffer (which we reuse the pos buffer for!), and its + * current contents (out_len entries) are copied to the new place. + * This should all remain transparent to the user. swap_buffers() then + * switches info and out_info. + */ + + + +/* Internal API */ + +bool +hb_buffer_t::enlarge (unsigned int size) +{ + if (unlikely (in_error)) + return false; + + unsigned int new_allocated = allocated; + hb_glyph_position_t *new_pos = NULL; + hb_glyph_info_t *new_info = NULL; + bool separate_out = out_info != info; + + if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0])))) + goto done; + + while (size >= new_allocated) + new_allocated += (new_allocated >> 1) + 32; + + ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0])); + if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0])))) + goto done; + + new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0])); + new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0])); + +done: + if (unlikely (!new_pos || !new_info)) + in_error = true; + + if (likely (new_pos)) + pos = new_pos; + + if (likely (new_info)) + info = new_info; + + out_info = separate_out ? (hb_glyph_info_t *) pos : info; + if (likely (!in_error)) + allocated = new_allocated; + + return likely (!in_error); +} + +bool +hb_buffer_t::make_room_for (unsigned int num_in, + unsigned int num_out) +{ + if (unlikely (!ensure (out_len + num_out))) return false; + + if (out_info == info && + out_len + num_out > idx + num_in) + { + assert (have_output); + + out_info = (hb_glyph_info_t *) pos; + memcpy (out_info, info, out_len * sizeof (out_info[0])); + } + + return true; +} + +bool +hb_buffer_t::shift_forward (unsigned int count) +{ + assert (have_output); + if (unlikely (!ensure (len + count))) return false; + + memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0])); + len += count; + idx += count; + + return true; +} + +hb_buffer_t::scratch_buffer_t * +hb_buffer_t::get_scratch_buffer (unsigned int *size) +{ + have_output = false; + have_positions = false; + + out_len = 0; + out_info = info; + + assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0); + *size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t); + return (scratch_buffer_t *) (void *) pos; +} + + + +/* HarfBuzz-Internal API */ + +void +hb_buffer_t::reset (void) +{ + if (unlikely (hb_object_is_inert (this))) + return; + + hb_unicode_funcs_destroy (unicode); + unicode = hb_unicode_funcs_get_default (); + flags = HB_BUFFER_FLAG_DEFAULT; + replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; + + clear (); +} + +void +hb_buffer_t::clear (void) +{ + if (unlikely (hb_object_is_inert (this))) + return; + + hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT; + props = default_props; + + content_type = HB_BUFFER_CONTENT_TYPE_INVALID; + in_error = false; + have_output = false; + have_positions = false; + + idx = 0; + len = 0; + out_len = 0; + out_info = info; + + serial = 0; + memset (allocated_var_bytes, 0, sizeof allocated_var_bytes); + memset (allocated_var_owner, 0, sizeof allocated_var_owner); + + memset (context, 0, sizeof context); + memset (context_len, 0, sizeof context_len); +} + +void +hb_buffer_t::add (hb_codepoint_t codepoint, + unsigned int cluster) +{ + hb_glyph_info_t *glyph; + + if (unlikely (!ensure (len + 1))) return; + + glyph = &info[len]; + + memset (glyph, 0, sizeof (*glyph)); + glyph->codepoint = codepoint; + glyph->mask = 1; + glyph->cluster = cluster; + + len++; +} + +void +hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info) +{ + if (unlikely (!ensure (len + 1))) return; + + info[len] = glyph_info; + + len++; +} + + +void +hb_buffer_t::remove_output (void) +{ + if (unlikely (hb_object_is_inert (this))) + return; + + have_output = false; + have_positions = false; + + out_len = 0; + out_info = info; +} + +void +hb_buffer_t::clear_output (void) +{ + if (unlikely (hb_object_is_inert (this))) + return; + + have_output = true; + have_positions = false; + + out_len = 0; + out_info = info; +} + +void +hb_buffer_t::clear_positions (void) +{ + if (unlikely (hb_object_is_inert (this))) + return; + + have_output = false; + have_positions = true; + + out_len = 0; + out_info = info; + + memset (pos, 0, sizeof (pos[0]) * len); +} + +void +hb_buffer_t::swap_buffers (void) +{ + if (unlikely (in_error)) return; + + assert (have_output); + have_output = false; + + if (out_info != info) + { + hb_glyph_info_t *tmp_string; + tmp_string = info; + info = out_info; + out_info = tmp_string; + pos = (hb_glyph_position_t *) out_info; + } + + unsigned int tmp; + tmp = len; + len = out_len; + out_len = tmp; + + idx = 0; +} + + +void +hb_buffer_t::replace_glyphs (unsigned int num_in, + unsigned int num_out, + const uint32_t *glyph_data) +{ + if (unlikely (!make_room_for (num_in, num_out))) return; + + merge_clusters (idx, idx + num_in); + + hb_glyph_info_t orig_info = info[idx]; + hb_glyph_info_t *pinfo = &out_info[out_len]; + for (unsigned int i = 0; i < num_out; i++) + { + *pinfo = orig_info; + pinfo->codepoint = glyph_data[i]; + pinfo++; + } + + idx += num_in; + out_len += num_out; +} + +void +hb_buffer_t::output_glyph (hb_codepoint_t glyph_index) +{ + if (unlikely (!make_room_for (0, 1))) return; + + out_info[out_len] = info[idx]; + out_info[out_len].codepoint = glyph_index; + + out_len++; +} + +void +hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info) +{ + if (unlikely (!make_room_for (0, 1))) return; + + out_info[out_len] = glyph_info; + + out_len++; +} + +void +hb_buffer_t::copy_glyph (void) +{ + if (unlikely (!make_room_for (0, 1))) return; + + out_info[out_len] = info[idx]; + + out_len++; +} + +bool +hb_buffer_t::move_to (unsigned int i) +{ + if (!have_output) + { + assert (i <= len); + idx = i; + return true; + } + + assert (i <= out_len + (len - idx)); + + if (out_len < i) + { + unsigned int count = i - out_len; + if (unlikely (!make_room_for (count, count))) return false; + + memmove (out_info + out_len, info + idx, count * sizeof (out_info[0])); + idx += count; + out_len += count; + } + else if (out_len > i) + { + /* Tricky part: rewinding... */ + unsigned int count = out_len - i; + + if (unlikely (idx < count && !shift_forward (count + 32))) return false; + + assert (idx >= count); + + idx -= count; + out_len -= count; + memmove (info + idx, out_info + out_len, count * sizeof (out_info[0])); + } + + return true; +} + +void +hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index) +{ + if (unlikely (out_info != info || out_len != idx)) { + if (unlikely (!make_room_for (1, 1))) return; + out_info[out_len] = info[idx]; + } + out_info[out_len].codepoint = glyph_index; + + idx++; + out_len++; +} + + +void +hb_buffer_t::set_masks (hb_mask_t value, + hb_mask_t mask, + unsigned int cluster_start, + unsigned int cluster_end) +{ + hb_mask_t not_mask = ~mask; + value &= mask; + + if (!mask) + return; + + if (cluster_start == 0 && cluster_end == (unsigned int)-1) { + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + info[i].mask = (info[i].mask & not_mask) | value; + return; + } + + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end) + info[i].mask = (info[i].mask & not_mask) | value; +} + +void +hb_buffer_t::reverse_range (unsigned int start, + unsigned int end) +{ + unsigned int i, j; + + if (end - start < 2) + return; + + for (i = start, j = end - 1; i < j; i++, j--) { + hb_glyph_info_t t; + + t = info[i]; + info[i] = info[j]; + info[j] = t; + } + + if (have_positions) { + for (i = start, j = end - 1; i < j; i++, j--) { + hb_glyph_position_t t; + + t = pos[i]; + pos[i] = pos[j]; + pos[j] = t; + } + } +} + +void +hb_buffer_t::reverse (void) +{ + if (unlikely (!len)) + return; + + reverse_range (0, len); +} + +void +hb_buffer_t::reverse_clusters (void) +{ + unsigned int i, start, count, last_cluster; + + if (unlikely (!len)) + return; + + reverse (); + + count = len; + start = 0; + last_cluster = info[0].cluster; + for (i = 1; i < count; i++) { + if (last_cluster != info[i].cluster) { + reverse_range (start, i); + start = i; + last_cluster = info[i].cluster; + } + } + reverse_range (start, i); +} + +void +hb_buffer_t::merge_clusters_impl (unsigned int start, + unsigned int end) +{ + if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS) + return; + + unsigned int cluster = info[start].cluster; + + for (unsigned int i = start + 1; i < end; i++) + cluster = MIN (cluster, info[i].cluster); + + /* Extend end */ + while (end < len && info[end - 1].cluster == info[end].cluster) + end++; + + /* Extend start */ + while (idx < start && info[start - 1].cluster == info[start].cluster) + start--; + + /* If we hit the start of buffer, continue in out-buffer. */ + if (idx == start) + for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--) + out_info[i - 1].cluster = cluster; + + for (unsigned int i = start; i < end; i++) + info[i].cluster = cluster; +} +void +hb_buffer_t::merge_out_clusters (unsigned int start, + unsigned int end) +{ + if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS) + return; + + if (unlikely (end - start < 2)) + return; + + unsigned int cluster = out_info[start].cluster; + + for (unsigned int i = start + 1; i < end; i++) + cluster = MIN (cluster, out_info[i].cluster); + + /* Extend start */ + while (start && out_info[start - 1].cluster == out_info[start].cluster) + start--; + + /* Extend end */ + while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster) + end++; + + /* If we hit the end of out-buffer, continue in buffer. */ + if (end == out_len) + for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++) + info[i].cluster = cluster; + + for (unsigned int i = start; i < end; i++) + out_info[i].cluster = cluster; +} +void +hb_buffer_t::delete_glyph () +{ + unsigned int cluster = info[idx].cluster; + if (idx + 1 < len && cluster == info[idx + 1].cluster) + { + /* Cluster survives; do nothing. */ + goto done; + } + + if (out_len) + { + /* Merge cluster backward. */ + if (cluster < out_info[out_len - 1].cluster) + { + unsigned int old_cluster = out_info[out_len - 1].cluster; + for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--) + out_info[i - 1].cluster = cluster; + } + goto done; + } + + if (idx + 1 < len) + { + /* Merge cluster forward. */ + merge_clusters (idx, idx + 2); + goto done; + } + +done: + skip_glyph (); +} + +void +hb_buffer_t::guess_segment_properties (void) +{ + assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || + (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); + + /* If script is set to INVALID, guess from buffer contents */ + if (props.script == HB_SCRIPT_INVALID) { + for (unsigned int i = 0; i < len; i++) { + hb_script_t script = unicode->script (info[i].codepoint); + if (likely (script != HB_SCRIPT_COMMON && + script != HB_SCRIPT_INHERITED && + script != HB_SCRIPT_UNKNOWN)) { + props.script = script; + break; + } + } + } + + /* If direction is set to INVALID, guess from script */ + if (props.direction == HB_DIRECTION_INVALID) { + props.direction = hb_script_get_horizontal_direction (props.script); + } + + /* If language is not set, use default language from locale */ + if (props.language == HB_LANGUAGE_INVALID) { + /* TODO get_default_for_script? using $LANGUAGE */ + props.language = hb_language_get_default (); + } +} + + +static inline void +dump_var_allocation (const hb_buffer_t *buffer) +{ + char buf[80]; + for (unsigned int i = 0; i < 8; i++) + buf[i] = '0' + buffer->allocated_var_bytes[7 - i]; + buf[8] = '\0'; + DEBUG_MSG (BUFFER, buffer, + "Current var allocation: %s", + buf); +} + +void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner) +{ + assert (byte_i < 8 && byte_i + count <= 8); + + if (DEBUG_ENABLED (BUFFER)) + dump_var_allocation (this); + DEBUG_MSG (BUFFER, this, + "Allocating var bytes %d..%d for %s", + byte_i, byte_i + count - 1, owner); + + for (unsigned int i = byte_i; i < byte_i + count; i++) { + assert (!allocated_var_bytes[i]); + allocated_var_bytes[i]++; + allocated_var_owner[i] = owner; + } +} + +void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner) +{ + if (DEBUG_ENABLED (BUFFER)) + dump_var_allocation (this); + + DEBUG_MSG (BUFFER, this, + "Deallocating var bytes %d..%d for %s", + byte_i, byte_i + count - 1, owner); + + assert (byte_i < 8 && byte_i + count <= 8); + for (unsigned int i = byte_i; i < byte_i + count; i++) { + assert (allocated_var_bytes[i]); + assert (0 == strcmp (allocated_var_owner[i], owner)); + allocated_var_bytes[i]--; + } +} + +void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner) +{ + if (DEBUG_ENABLED (BUFFER)) + dump_var_allocation (this); + + DEBUG_MSG (BUFFER, this, + "Asserting var bytes %d..%d for %s", + byte_i, byte_i + count - 1, owner); + + assert (byte_i < 8 && byte_i + count <= 8); + for (unsigned int i = byte_i; i < byte_i + count; i++) { + assert (allocated_var_bytes[i]); + assert (0 == strcmp (allocated_var_owner[i], owner)); + } +} + +void hb_buffer_t::deallocate_var_all (void) +{ + memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes)); + memset (allocated_var_owner, 0, sizeof (allocated_var_owner)); +} + +/* Public API */ + +/** + * hb_buffer_create: (Xconstructor) + * + * + * + * Return value: (transfer full) + * + * Since: 0.9.2 + **/ +hb_buffer_t * +hb_buffer_create (void) +{ + hb_buffer_t *buffer; + + if (!(buffer = hb_object_create ())) + return hb_buffer_get_empty (); + + buffer->reset (); + + return buffer; +} + +/** + * hb_buffer_get_empty: + * + * + * + * Return value: (transfer full): + * + * Since: 0.9.2 + **/ +hb_buffer_t * +hb_buffer_get_empty (void) +{ + static const hb_buffer_t _hb_buffer_nil = { + HB_OBJECT_HEADER_STATIC, + + const_cast (&_hb_unicode_funcs_nil), + HB_BUFFER_FLAG_DEFAULT, + HB_BUFFER_CLUSTER_LEVEL_DEFAULT, + HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT, + + HB_BUFFER_CONTENT_TYPE_INVALID, + HB_SEGMENT_PROPERTIES_DEFAULT, + true, /* in_error */ + true, /* have_output */ + true /* have_positions */ + + /* Zero is good enough for everything else. */ + }; + + return const_cast (&_hb_buffer_nil); +} + +/** + * hb_buffer_reference: (skip) + * @buffer: a buffer. + * + * + * + * Return value: (transfer full): + * + * Since: 0.9.2 + **/ +hb_buffer_t * +hb_buffer_reference (hb_buffer_t *buffer) +{ + return hb_object_reference (buffer); +} + +/** + * hb_buffer_destroy: (skip) + * @buffer: a buffer. + * + * + * + * Since: 0.9.2 + **/ +void +hb_buffer_destroy (hb_buffer_t *buffer) +{ + if (!hb_object_destroy (buffer)) return; + + hb_unicode_funcs_destroy (buffer->unicode); + + free (buffer->info); + free (buffer->pos); + + free (buffer); +} + +/** + * hb_buffer_set_user_data: (skip) + * @buffer: a buffer. + * @key: + * @data: + * @destroy: + * @replace: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_buffer_set_user_data (hb_buffer_t *buffer, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (buffer, key, data, destroy, replace); +} + +/** + * hb_buffer_get_user_data: (skip) + * @buffer: a buffer. + * @key: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +void * +hb_buffer_get_user_data (hb_buffer_t *buffer, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (buffer, key); +} + + +/** + * hb_buffer_set_content_type: + * @buffer: a buffer. + * @content_type: + * + * + * + * Since: 0.9.5 + **/ +void +hb_buffer_set_content_type (hb_buffer_t *buffer, + hb_buffer_content_type_t content_type) +{ + buffer->content_type = content_type; +} + +/** + * hb_buffer_get_content_type: + * @buffer: a buffer. + * + * + * + * Return value: + * + * Since: 0.9.5 + **/ +hb_buffer_content_type_t +hb_buffer_get_content_type (hb_buffer_t *buffer) +{ + return buffer->content_type; +} + + +/** + * hb_buffer_set_unicode_funcs: + * @buffer: a buffer. + * @unicode_funcs: + * + * + * + * Since: 0.9.2 + **/ +void +hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, + hb_unicode_funcs_t *unicode_funcs) +{ + if (unlikely (hb_object_is_inert (buffer))) + return; + + if (!unicode_funcs) + unicode_funcs = hb_unicode_funcs_get_default (); + + + hb_unicode_funcs_reference (unicode_funcs); + hb_unicode_funcs_destroy (buffer->unicode); + buffer->unicode = unicode_funcs; +} + +/** + * hb_buffer_get_unicode_funcs: + * @buffer: a buffer. + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_unicode_funcs_t * +hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) +{ + return buffer->unicode; +} + +/** + * hb_buffer_set_direction: + * @buffer: a buffer. + * @direction: + * + * + * + * Since: 0.9.2 + **/ +void +hb_buffer_set_direction (hb_buffer_t *buffer, + hb_direction_t direction) + +{ + if (unlikely (hb_object_is_inert (buffer))) + return; + + buffer->props.direction = direction; +} + +/** + * hb_buffer_get_direction: + * @buffer: a buffer. + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_direction_t +hb_buffer_get_direction (hb_buffer_t *buffer) +{ + return buffer->props.direction; +} + +/** + * hb_buffer_set_script: + * @buffer: a buffer. + * @script: + * + * + * + * Since: 0.9.2 + **/ +void +hb_buffer_set_script (hb_buffer_t *buffer, + hb_script_t script) +{ + if (unlikely (hb_object_is_inert (buffer))) + return; + + buffer->props.script = script; +} + +/** + * hb_buffer_get_script: + * @buffer: a buffer. + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_script_t +hb_buffer_get_script (hb_buffer_t *buffer) +{ + return buffer->props.script; +} + +/** + * hb_buffer_set_language: + * @buffer: a buffer. + * @language: + * + * + * + * Since: 0.9.2 + **/ +void +hb_buffer_set_language (hb_buffer_t *buffer, + hb_language_t language) +{ + if (unlikely (hb_object_is_inert (buffer))) + return; + + buffer->props.language = language; +} + +/** + * hb_buffer_get_language: + * @buffer: a buffer. + * + * + * + * Return value: (transfer none): + * + * Since: 0.9.2 + **/ +hb_language_t +hb_buffer_get_language (hb_buffer_t *buffer) +{ + return buffer->props.language; +} + +/** + * hb_buffer_set_segment_properties: + * @buffer: a buffer. + * @props: + * + * + * + * Since: 0.9.7 + **/ +void +hb_buffer_set_segment_properties (hb_buffer_t *buffer, + const hb_segment_properties_t *props) +{ + if (unlikely (hb_object_is_inert (buffer))) + return; + + buffer->props = *props; +} + +/** + * hb_buffer_get_segment_properties: + * @buffer: a buffer. + * @props: (out): + * + * + * + * Since: 0.9.7 + **/ +void +hb_buffer_get_segment_properties (hb_buffer_t *buffer, + hb_segment_properties_t *props) +{ + *props = buffer->props; +} + + +/** + * hb_buffer_set_flags: + * @buffer: a buffer. + * @flags: + * + * + * + * Since: 0.9.7 + **/ +void +hb_buffer_set_flags (hb_buffer_t *buffer, + hb_buffer_flags_t flags) +{ + if (unlikely (hb_object_is_inert (buffer))) + return; + + buffer->flags = flags; +} + +/** + * hb_buffer_get_flags: + * @buffer: a buffer. + * + * + * + * Return value: + * + * Since: 0.9.7 + **/ +hb_buffer_flags_t +hb_buffer_get_flags (hb_buffer_t *buffer) +{ + return buffer->flags; +} + +/** + * hb_buffer_set_cluster_level: + * @buffer: a buffer. + * @cluster_level: + * + * + * + * Since: 0.9.42 + **/ +void +hb_buffer_set_cluster_level (hb_buffer_t *buffer, + hb_buffer_cluster_level_t cluster_level) +{ + if (unlikely (hb_object_is_inert (buffer))) + return; + + buffer->cluster_level = cluster_level; +} + +/** + * hb_buffer_get_cluster_level: + * @buffer: a buffer. + * + * + * + * Return value: + * + * Since: 0.9.42 + **/ +hb_buffer_cluster_level_t +hb_buffer_get_cluster_level (hb_buffer_t *buffer) +{ + return buffer->cluster_level; +} + + +/** + * hb_buffer_set_replacement_codepoint: + * @buffer: a buffer. + * @replacement: + * + * + * + * Since: 0.9.31 + **/ +void +hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer, + hb_codepoint_t replacement) +{ + if (unlikely (hb_object_is_inert (buffer))) + return; + + buffer->replacement = replacement; +} + +/** + * hb_buffer_get_replacement_codepoint: + * @buffer: a buffer. + * + * + * + * Return value: + * + * Since: 0.9.31 + **/ +hb_codepoint_t +hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer) +{ + return buffer->replacement; +} + + +/** + * hb_buffer_reset: + * @buffer: a buffer. + * + * + * + * Since: 0.9.2 + **/ +void +hb_buffer_reset (hb_buffer_t *buffer) +{ + buffer->reset (); +} + +/** + * hb_buffer_clear_contents: + * @buffer: a buffer. + * + * + * + * Since: 0.9.11 + **/ +void +hb_buffer_clear_contents (hb_buffer_t *buffer) +{ + buffer->clear (); +} + +/** + * hb_buffer_pre_allocate: + * @buffer: a buffer. + * @size: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) +{ + return buffer->ensure (size); +} + +/** + * hb_buffer_allocation_successful: + * @buffer: a buffer. + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_buffer_allocation_successful (hb_buffer_t *buffer) +{ + return !buffer->in_error; +} + +/** + * hb_buffer_add: + * @buffer: a buffer. + * @codepoint: + * @cluster: + * + * + * + * Since: 0.9.7 + **/ +void +hb_buffer_add (hb_buffer_t *buffer, + hb_codepoint_t codepoint, + unsigned int cluster) +{ + buffer->add (codepoint, cluster); + buffer->clear_context (1); +} + +/** + * hb_buffer_set_length: + * @buffer: a buffer. + * @length: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_buffer_set_length (hb_buffer_t *buffer, + unsigned int length) +{ + if (unlikely (hb_object_is_inert (buffer))) + return length == 0; + + if (!buffer->ensure (length)) + return false; + + /* Wipe the new space */ + if (length > buffer->len) { + memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len)); + if (buffer->have_positions) + memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len)); + } + + buffer->len = length; + + if (!length) + { + buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID; + buffer->clear_context (0); + } + buffer->clear_context (1); + + return true; +} + +/** + * hb_buffer_get_length: + * @buffer: a buffer. + * + * Returns the number of items in the buffer. + * + * Return value: buffer length. + * + * Since: 0.9.2 + **/ +unsigned int +hb_buffer_get_length (hb_buffer_t *buffer) +{ + return buffer->len; +} + +/** + * hb_buffer_get_glyph_infos: + * @buffer: a buffer. + * @length: (out): output array length. + * + * Returns buffer glyph information array. Returned pointer + * is valid as long as buffer contents are not modified. + * + * Return value: (transfer none) (array length=length): buffer glyph information array. + * + * Since: 0.9.2 + **/ +hb_glyph_info_t * +hb_buffer_get_glyph_infos (hb_buffer_t *buffer, + unsigned int *length) +{ + if (length) + *length = buffer->len; + + return (hb_glyph_info_t *) buffer->info; +} + +/** + * hb_buffer_get_glyph_positions: + * @buffer: a buffer. + * @length: (out): output length. + * + * Returns buffer glyph position array. Returned pointer + * is valid as long as buffer contents are not modified. + * + * Return value: (transfer none) (array length=length): buffer glyph position array. + * + * Since: 0.9.2 + **/ +hb_glyph_position_t * +hb_buffer_get_glyph_positions (hb_buffer_t *buffer, + unsigned int *length) +{ + if (!buffer->have_positions) + buffer->clear_positions (); + + if (length) + *length = buffer->len; + + return (hb_glyph_position_t *) buffer->pos; +} + +/** + * hb_buffer_reverse: + * @buffer: a buffer. + * + * Reverses buffer contents. + * + * Since: 0.9.2 + **/ +void +hb_buffer_reverse (hb_buffer_t *buffer) +{ + buffer->reverse (); +} + +/** + * hb_buffer_reverse_range: + * @buffer: a buffer. + * @start: start index. + * @end: end index. + * + * Reverses buffer contents between start to end. + * + * Since: 0.9.41 + **/ +void +hb_buffer_reverse_range (hb_buffer_t *buffer, + unsigned int start, unsigned int end) +{ + buffer->reverse_range (start, end); +} + +/** + * hb_buffer_reverse_clusters: + * @buffer: a buffer. + * + * Reverses buffer clusters. That is, the buffer contents are + * reversed, then each cluster (consecutive items having the + * same cluster number) are reversed again. + * + * Since: 0.9.2 + **/ +void +hb_buffer_reverse_clusters (hb_buffer_t *buffer) +{ + buffer->reverse_clusters (); +} + +/** + * hb_buffer_guess_segment_properties: + * @buffer: a buffer. + * + * Sets unset buffer segment properties based on buffer Unicode + * contents. If buffer is not empty, it must have content type + * %HB_BUFFER_CONTENT_TYPE_UNICODE. + * + * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it + * will be set to the Unicode script of the first character in + * the buffer that has a script other than %HB_SCRIPT_COMMON, + * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN. + * + * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID), + * it will be set to the natural horizontal direction of the + * buffer script as returned by hb_script_get_horizontal_direction(). + * + * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID), + * it will be set to the process's default language as returned by + * hb_language_get_default(). This may change in the future by + * taking buffer script into consideration when choosing a language. + * + * Since: 0.9.7 + **/ +void +hb_buffer_guess_segment_properties (hb_buffer_t *buffer) +{ + buffer->guess_segment_properties (); +} + +template +static inline void +hb_buffer_add_utf (hb_buffer_t *buffer, + const typename utf_t::codepoint_t *text, + int text_length, + unsigned int item_offset, + int item_length) +{ + typedef typename utf_t::codepoint_t T; + const hb_codepoint_t replacement = buffer->replacement; + + assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || + (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); + + if (unlikely (hb_object_is_inert (buffer))) + return; + + if (text_length == -1) + text_length = utf_t::strlen (text); + + if (item_length == -1) + item_length = text_length - item_offset; + + buffer->ensure (buffer->len + item_length * sizeof (T) / 4); + + /* If buffer is empty and pre-context provided, install it. + * This check is written this way, to make sure people can + * provide pre-context in one add_utf() call, then provide + * text in a follow-up call. See: + * + * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13 + */ + if (!buffer->len && item_offset > 0) + { + /* Add pre-context */ + buffer->clear_context (0); + const T *prev = text + item_offset; + const T *start = text; + while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH) + { + hb_codepoint_t u; + prev = utf_t::prev (prev, start, &u, replacement); + buffer->context[0][buffer->context_len[0]++] = u; + } + } + + const T *next = text + item_offset; + const T *end = next + item_length; + while (next < end) + { + hb_codepoint_t u; + const T *old_next = next; + next = utf_t::next (next, end, &u, replacement); + buffer->add (u, old_next - (const T *) text); + } + + /* Add post-context */ + buffer->clear_context (1); + end = text + text_length; + while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH) + { + hb_codepoint_t u; + next = utf_t::next (next, end, &u, replacement); + buffer->context[1][buffer->context_len[1]++] = u; + } + + buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE; +} + +/** + * hb_buffer_add_utf8: + * @buffer: a buffer. + * @text: (array length=text_length) (element-type uint8_t): + * @text_length: + * @item_offset: + * @item_length: + * + * + * + * Since: 0.9.2 + **/ +void +hb_buffer_add_utf8 (hb_buffer_t *buffer, + const char *text, + int text_length, + unsigned int item_offset, + int item_length) +{ + hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length); +} + +/** + * hb_buffer_add_utf16: + * @buffer: a buffer. + * @text: (array length=text_length): + * @text_length: + * @item_offset: + * @item_length: + * + * + * + * Since: 0.9.2 + **/ +void +hb_buffer_add_utf16 (hb_buffer_t *buffer, + const uint16_t *text, + int text_length, + unsigned int item_offset, + int item_length) +{ + hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length); +} + +/** + * hb_buffer_add_utf32: + * @buffer: a buffer. + * @text: (array length=text_length): + * @text_length: + * @item_offset: + * @item_length: + * + * + * + * Since: 0.9.2 + **/ +void +hb_buffer_add_utf32 (hb_buffer_t *buffer, + const uint32_t *text, + int text_length, + unsigned int item_offset, + int item_length) +{ + hb_buffer_add_utf > (buffer, text, text_length, item_offset, item_length); +} + +/** + * hb_buffer_add_latin1: + * @buffer: a buffer. + * @text: (array length=text_length) (element-type uint8_t): + * @text_length: + * @item_offset: + * @item_length: + * + * + * + * Since: 0.9.39 + **/ +void +hb_buffer_add_latin1 (hb_buffer_t *buffer, + const uint8_t *text, + int text_length, + unsigned int item_offset, + int item_length) +{ + hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length); +} + +/** + * hb_buffer_add_codepoints: + * @buffer: a buffer. + * @text: (array length=text_length): + * @text_length: + * @item_offset: + * @item_length: + * + * + * + * Since: 0.9.31 + **/ +void +hb_buffer_add_codepoints (hb_buffer_t *buffer, + const hb_codepoint_t *text, + int text_length, + unsigned int item_offset, + int item_length) +{ + hb_buffer_add_utf > (buffer, text, text_length, item_offset, item_length); +} + + +static int +compare_info_codepoint (const hb_glyph_info_t *pa, + const hb_glyph_info_t *pb) +{ + return (int) pb->codepoint - (int) pa->codepoint; +} + +static inline void +normalize_glyphs_cluster (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + bool backward) +{ + hb_glyph_position_t *pos = buffer->pos; + + /* Total cluster advance */ + hb_position_t total_x_advance = 0, total_y_advance = 0; + for (unsigned int i = start; i < end; i++) + { + total_x_advance += pos[i].x_advance; + total_y_advance += pos[i].y_advance; + } + + hb_position_t x_advance = 0, y_advance = 0; + for (unsigned int i = start; i < end; i++) + { + pos[i].x_offset += x_advance; + pos[i].y_offset += y_advance; + + x_advance += pos[i].x_advance; + y_advance += pos[i].y_advance; + + pos[i].x_advance = 0; + pos[i].y_advance = 0; + } + + if (backward) + { + /* Transfer all cluster advance to the last glyph. */ + pos[end - 1].x_advance = total_x_advance; + pos[end - 1].y_advance = total_y_advance; + + hb_stable_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start); + } else { + /* Transfer all cluster advance to the first glyph. */ + pos[start].x_advance += total_x_advance; + pos[start].y_advance += total_y_advance; + for (unsigned int i = start + 1; i < end; i++) { + pos[i].x_offset -= total_x_advance; + pos[i].y_offset -= total_y_advance; + } + hb_stable_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1); + } +} + +/** + * hb_buffer_normalize_glyphs: + * @buffer: a buffer. + * + * + * + * Since: 0.9.2 + **/ +void +hb_buffer_normalize_glyphs (hb_buffer_t *buffer) +{ + assert (buffer->have_positions); + assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); + + bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); + + unsigned int count = buffer->len; + if (unlikely (!count)) return; + hb_glyph_info_t *info = buffer->info; + + unsigned int start = 0; + unsigned int end; + for (end = start + 1; end < count; end++) + if (info[start].cluster != info[end].cluster) { + normalize_glyphs_cluster (buffer, start, end, backward); + start = end; + } + normalize_glyphs_cluster (buffer, start, end, backward); +} + +void +hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *)) +{ + assert (!have_positions); + for (unsigned int i = start + 1; i < end; i++) + { + unsigned int j = i; + while (j > start && compar (&info[j - 1], &info[i]) > 0) + j--; + if (i == j) + continue; + /* Move item i to occupy place for item j, shift what's in between. */ + merge_clusters (j, i + 1); + { + hb_glyph_info_t t = info[i]; + memmove (&info[j + 1], &info[j], (i - j) * sizeof (hb_glyph_info_t)); + info[j] = t; + } + } +} diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer.h b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer.h new file mode 100644 index 00000000000..5e56da49355 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-buffer.h @@ -0,0 +1,378 @@ +/* + * Copyright © 1998-2004 David Turner and Werner Lemberg + * Copyright © 2004,2007,2009 Red Hat, Inc. + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Owen Taylor, Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_H_IN +#error "Include instead." +#endif + +#ifndef HB_BUFFER_H +#define HB_BUFFER_H + +#include "hb-common.h" +#include "hb-unicode.h" +#include "hb-font.h" + +HB_BEGIN_DECLS + + +typedef struct hb_glyph_info_t { + hb_codepoint_t codepoint; + hb_mask_t mask; + uint32_t cluster; + + /*< private >*/ + hb_var_int_t var1; + hb_var_int_t var2; +} hb_glyph_info_t; + +typedef struct hb_glyph_position_t { + hb_position_t x_advance; + hb_position_t y_advance; + hb_position_t x_offset; + hb_position_t y_offset; + + /*< private >*/ + hb_var_int_t var; +} hb_glyph_position_t; + + +typedef struct hb_segment_properties_t { + hb_direction_t direction; + hb_script_t script; + hb_language_t language; + /*< private >*/ + void *reserved1; + void *reserved2; +} hb_segment_properties_t; + +#define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \ + HB_SCRIPT_INVALID, \ + HB_LANGUAGE_INVALID, \ + NULL, \ + NULL} + +hb_bool_t +hb_segment_properties_equal (const hb_segment_properties_t *a, + const hb_segment_properties_t *b); + +unsigned int +hb_segment_properties_hash (const hb_segment_properties_t *p); + + + +/* + * hb_buffer_t + */ + +typedef struct hb_buffer_t hb_buffer_t; + +hb_buffer_t * +hb_buffer_create (void); + +hb_buffer_t * +hb_buffer_get_empty (void); + +hb_buffer_t * +hb_buffer_reference (hb_buffer_t *buffer); + +void +hb_buffer_destroy (hb_buffer_t *buffer); + +hb_bool_t +hb_buffer_set_user_data (hb_buffer_t *buffer, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + +void * +hb_buffer_get_user_data (hb_buffer_t *buffer, + hb_user_data_key_t *key); + + +typedef enum { + HB_BUFFER_CONTENT_TYPE_INVALID = 0, + HB_BUFFER_CONTENT_TYPE_UNICODE, + HB_BUFFER_CONTENT_TYPE_GLYPHS +} hb_buffer_content_type_t; + +void +hb_buffer_set_content_type (hb_buffer_t *buffer, + hb_buffer_content_type_t content_type); + +hb_buffer_content_type_t +hb_buffer_get_content_type (hb_buffer_t *buffer); + + +void +hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, + hb_unicode_funcs_t *unicode_funcs); + +hb_unicode_funcs_t * +hb_buffer_get_unicode_funcs (hb_buffer_t *buffer); + +void +hb_buffer_set_direction (hb_buffer_t *buffer, + hb_direction_t direction); + +hb_direction_t +hb_buffer_get_direction (hb_buffer_t *buffer); + +void +hb_buffer_set_script (hb_buffer_t *buffer, + hb_script_t script); + +hb_script_t +hb_buffer_get_script (hb_buffer_t *buffer); + +void +hb_buffer_set_language (hb_buffer_t *buffer, + hb_language_t language); + + +hb_language_t +hb_buffer_get_language (hb_buffer_t *buffer); + +void +hb_buffer_set_segment_properties (hb_buffer_t *buffer, + const hb_segment_properties_t *props); + +void +hb_buffer_get_segment_properties (hb_buffer_t *buffer, + hb_segment_properties_t *props); + +void +hb_buffer_guess_segment_properties (hb_buffer_t *buffer); + + +/* + * Since: 0.9.20 + */ +typedef enum { /*< flags >*/ + HB_BUFFER_FLAG_DEFAULT = 0x00000000u, + HB_BUFFER_FLAG_BOT = 0x00000001u, /* Beginning-of-text */ + HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */ + HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u +} hb_buffer_flags_t; + +void +hb_buffer_set_flags (hb_buffer_t *buffer, + hb_buffer_flags_t flags); + +hb_buffer_flags_t +hb_buffer_get_flags (hb_buffer_t *buffer); + +/* + * Since: 0.9.42 + */ +typedef enum { + HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES = 0, + HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS = 1, + HB_BUFFER_CLUSTER_LEVEL_CHARACTERS = 2, + HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES +} hb_buffer_cluster_level_t; + +void +hb_buffer_set_cluster_level (hb_buffer_t *buffer, + hb_buffer_cluster_level_t cluster_level); + +hb_buffer_cluster_level_t +hb_buffer_get_cluster_level (hb_buffer_t *buffer); + +#define HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT 0xFFFDu + +/* Sets codepoint used to replace invalid UTF-8/16/32 entries. + * Default is 0xFFFDu. */ +void +hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer, + hb_codepoint_t replacement); + +hb_codepoint_t +hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer); + + +/* Resets the buffer. Afterwards it's as if it was just created, + * except that it has a larger buffer allocated perhaps... */ +void +hb_buffer_reset (hb_buffer_t *buffer); + +/* Like reset, but does NOT clear unicode_funcs and replacement_codepoint. */ +void +hb_buffer_clear_contents (hb_buffer_t *buffer); + +/* Returns false if allocation failed */ +hb_bool_t +hb_buffer_pre_allocate (hb_buffer_t *buffer, + unsigned int size); + + +/* Returns false if allocation has failed before */ +hb_bool_t +hb_buffer_allocation_successful (hb_buffer_t *buffer); + +void +hb_buffer_reverse (hb_buffer_t *buffer); + +void +hb_buffer_reverse_range (hb_buffer_t *buffer, + unsigned int start, unsigned int end); + +void +hb_buffer_reverse_clusters (hb_buffer_t *buffer); + + +/* Filling the buffer in */ + +void +hb_buffer_add (hb_buffer_t *buffer, + hb_codepoint_t codepoint, + unsigned int cluster); + +void +hb_buffer_add_utf8 (hb_buffer_t *buffer, + const char *text, + int text_length, + unsigned int item_offset, + int item_length); + +void +hb_buffer_add_utf16 (hb_buffer_t *buffer, + const uint16_t *text, + int text_length, + unsigned int item_offset, + int item_length); + +void +hb_buffer_add_utf32 (hb_buffer_t *buffer, + const uint32_t *text, + int text_length, + unsigned int item_offset, + int item_length); + +/* Allows only access to first 256 Unicode codepoints. */ +void +hb_buffer_add_latin1 (hb_buffer_t *buffer, + const uint8_t *text, + int text_length, + unsigned int item_offset, + int item_length); + +/* Like add_utf32 but does NOT check for invalid Unicode codepoints. */ +void +hb_buffer_add_codepoints (hb_buffer_t *buffer, + const hb_codepoint_t *text, + int text_length, + unsigned int item_offset, + int item_length); + + +/* Clears any new items added at the end */ +hb_bool_t +hb_buffer_set_length (hb_buffer_t *buffer, + unsigned int length); + +/* Return value valid as long as buffer not modified */ +unsigned int +hb_buffer_get_length (hb_buffer_t *buffer); + +/* Getting glyphs out of the buffer */ + +/* Return value valid as long as buffer not modified */ +hb_glyph_info_t * +hb_buffer_get_glyph_infos (hb_buffer_t *buffer, + unsigned int *length); + +/* Return value valid as long as buffer not modified */ +hb_glyph_position_t * +hb_buffer_get_glyph_positions (hb_buffer_t *buffer, + unsigned int *length); + + +/* Reorders a glyph buffer to have canonical in-cluster glyph order / position. + * The resulting clusters should behave identical to pre-reordering clusters. + * NOTE: This has nothing to do with Unicode normalization. */ +void +hb_buffer_normalize_glyphs (hb_buffer_t *buffer); + + +/* + * Serialize + */ + +/* + * Since: 0.9.20 + */ +typedef enum { /*< flags >*/ + HB_BUFFER_SERIALIZE_FLAG_DEFAULT = 0x00000000u, + HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS = 0x00000001u, + HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS = 0x00000002u, + HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004u, + HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS = 0x00000008u +} hb_buffer_serialize_flags_t; + +typedef enum { + HB_BUFFER_SERIALIZE_FORMAT_TEXT = HB_TAG('T','E','X','T'), + HB_BUFFER_SERIALIZE_FORMAT_JSON = HB_TAG('J','S','O','N'), + HB_BUFFER_SERIALIZE_FORMAT_INVALID = HB_TAG_NONE +} hb_buffer_serialize_format_t; + +/* len=-1 means str is NUL-terminated. */ +hb_buffer_serialize_format_t +hb_buffer_serialize_format_from_string (const char *str, int len); + +const char * +hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format); + +const char ** +hb_buffer_serialize_list_formats (void); + +/* Returns number of items, starting at start, that were serialized. */ +unsigned int +hb_buffer_serialize_glyphs (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, /* May be NULL */ + hb_font_t *font, /* May be NULL */ + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags); + +hb_bool_t +hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, + const char *buf, + int buf_len, /* -1 means nul-terminated */ + const char **end_ptr, /* May be NULL */ + hb_font_t *font, /* May be NULL */ + hb_buffer_serialize_format_t format); + + +HB_END_DECLS + +#endif /* HB_BUFFER_H */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-cache-private.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-cache-private.hh new file mode 100644 index 00000000000..19b70b7e395 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-cache-private.hh @@ -0,0 +1,74 @@ +/* + * Copyright © 2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_CACHE_PRIVATE_HH +#define HB_CACHE_PRIVATE_HH + +#include "hb-private.hh" + + +/* Implements a lock-free cache for int->int functions. */ + +template +struct hb_cache_t +{ + ASSERT_STATIC (key_bits >= cache_bits); + ASSERT_STATIC (key_bits + value_bits - cache_bits < 8 * sizeof (unsigned int)); + + inline void clear (void) + { + memset (values, 255, sizeof (values)); + } + + inline bool get (unsigned int key, unsigned int *value) + { + unsigned int k = key & ((1<> value_bits) != (key >> cache_bits)) + return false; + *value = v & ((1<> key_bits) || (value >> value_bits))) + return false; /* Overflows */ + unsigned int k = key & ((1<>cache_bits)< hb_cmap_cache_t; +typedef hb_cache_t<16, 24, 8> hb_advance_cache_t; + + +#endif /* HB_CACHE_PRIVATE_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-common.cc b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-common.cc new file mode 100644 index 00000000000..bf5dba8da0c --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-common.cc @@ -0,0 +1,593 @@ +/* + * Copyright © 2009,2010 Red Hat, Inc. + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-private.hh" + +#include "hb-mutex-private.hh" +#include "hb-object-private.hh" + +#include + + +/* hb_options_t */ + +hb_options_union_t _hb_options; + +void +_hb_options_init (void) +{ + hb_options_union_t u; + u.i = 0; + u.opts.initialized = 1; + + char *c = getenv ("HB_OPTIONS"); + u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible"); + + /* This is idempotent and threadsafe. */ + _hb_options = u; +} + + +/* hb_tag_t */ + +/** + * hb_tag_from_string: + * @str: (array length=len) (element-type uint8_t): + * @len: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_tag_t +hb_tag_from_string (const char *str, int len) +{ + char tag[4]; + unsigned int i; + + if (!str || !len || !*str) + return HB_TAG_NONE; + + if (len < 0 || len > 4) + len = 4; + for (i = 0; i < (unsigned) len && str[i]; i++) + tag[i] = str[i]; + for (; i < 4; i++) + tag[i] = ' '; + + return HB_TAG_CHAR4 (tag); +} + +/** + * hb_tag_to_string: + * @tag: + * @buf: (array fixed-size=4): + * + * + * + * Since: 0.9.5 + **/ +void +hb_tag_to_string (hb_tag_t tag, char *buf) +{ + buf[0] = (char) (uint8_t) (tag >> 24); + buf[1] = (char) (uint8_t) (tag >> 16); + buf[2] = (char) (uint8_t) (tag >> 8); + buf[3] = (char) (uint8_t) (tag >> 0); +} + + +/* hb_direction_t */ + +const char direction_strings[][4] = { + "ltr", + "rtl", + "ttb", + "btt" +}; + +/** + * hb_direction_from_string: + * @str: (array length=len) (element-type uint8_t): + * @len: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_direction_t +hb_direction_from_string (const char *str, int len) +{ + if (unlikely (!str || !len || !*str)) + return HB_DIRECTION_INVALID; + + /* Lets match loosely: just match the first letter, such that + * all of "ltr", "left-to-right", etc work! + */ + char c = TOLOWER (str[0]); + for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++) + if (c == direction_strings[i][0]) + return (hb_direction_t) (HB_DIRECTION_LTR + i); + + return HB_DIRECTION_INVALID; +} + +/** + * hb_direction_to_string: + * @direction: + * + * + * + * Return value: (transfer none): + * + * Since: 0.9.2 + **/ +const char * +hb_direction_to_string (hb_direction_t direction) +{ + if (likely ((unsigned int) (direction - HB_DIRECTION_LTR) + < ARRAY_LENGTH (direction_strings))) + return direction_strings[direction - HB_DIRECTION_LTR]; + + return "invalid"; +} + + +/* hb_language_t */ + +struct hb_language_impl_t { + const char s[1]; +}; + +static const char canon_map[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0, + '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, '-', + 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0 +}; + +static bool +lang_equal (hb_language_t v1, + const void *v2) +{ + const unsigned char *p1 = (const unsigned char *) v1; + const unsigned char *p2 = (const unsigned char *) v2; + + while (*p1 && *p1 == canon_map[*p2]) + p1++, p2++; + + return *p1 == canon_map[*p2]; +} + +#if 0 +static unsigned int +lang_hash (const void *key) +{ + const unsigned char *p = key; + unsigned int h = 0; + while (canon_map[*p]) + { + h = (h << 5) - h + canon_map[*p]; + p++; + } + + return h; +} +#endif + + +struct hb_language_item_t { + + struct hb_language_item_t *next; + hb_language_t lang; + + inline bool operator == (const char *s) const { + return lang_equal (lang, s); + } + + inline hb_language_item_t & operator = (const char *s) { + lang = (hb_language_t) strdup (s); + for (unsigned char *p = (unsigned char *) lang; *p; p++) + *p = canon_map[*p]; + + return *this; + } + + void finish (void) { free ((void *) lang); } +}; + + +/* Thread-safe lock-free language list */ + +static hb_language_item_t *langs; + +#ifdef HB_USE_ATEXIT +static +void free_langs (void) +{ + while (langs) { + hb_language_item_t *next = langs->next; + langs->finish (); + free (langs); + langs = next; + } +} +#endif + +static hb_language_item_t * +lang_find_or_insert (const char *key) +{ +retry: + hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs); + + for (hb_language_item_t *lang = first_lang; lang; lang = lang->next) + if (*lang == key) + return lang; + + /* Not found; allocate one. */ + hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t)); + if (unlikely (!lang)) + return NULL; + lang->next = first_lang; + *lang = key; + + if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) { + lang->finish (); + free (lang); + goto retry; + } + +#ifdef HB_USE_ATEXIT + if (!first_lang) + atexit (free_langs); /* First person registers atexit() callback. */ +#endif + + return lang; +} + + +/** + * hb_language_from_string: + * @str: (array length=len) (element-type uint8_t): + * @len: + * + * + * + * Return value: (transfer none): + * + * Since: 0.9.2 + **/ +hb_language_t +hb_language_from_string (const char *str, int len) +{ + if (!str || !len || !*str) + return HB_LANGUAGE_INVALID; + + hb_language_item_t *item = NULL; + if (len >= 0) + { + /* NUL-terminate it. */ + char strbuf[64]; + len = MIN (len, (int) sizeof (strbuf) - 1); + memcpy (strbuf, str, len); + strbuf[len] = '\0'; + item = lang_find_or_insert (strbuf); + } + else + item = lang_find_or_insert (str); + + return likely (item) ? item->lang : HB_LANGUAGE_INVALID; +} + +/** + * hb_language_to_string: + * @language: + * + * + * + * Return value: (transfer none): + * + * Since: 0.9.2 + **/ +const char * +hb_language_to_string (hb_language_t language) +{ + /* This is actually NULL-safe! */ + return language->s; +} + +/** + * hb_language_get_default: + * + * + * + * Return value: (transfer none): + * + * Since: 0.9.2 + **/ +hb_language_t +hb_language_get_default (void) +{ + static hb_language_t default_language = HB_LANGUAGE_INVALID; + + hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language); + if (unlikely (language == HB_LANGUAGE_INVALID)) { + language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1); + (void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language); + } + + return default_language; +} + + +/* hb_script_t */ + +/** + * hb_script_from_iso15924_tag: + * @tag: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_script_t +hb_script_from_iso15924_tag (hb_tag_t tag) +{ + if (unlikely (tag == HB_TAG_NONE)) + return HB_SCRIPT_INVALID; + + /* Be lenient, adjust case (one capital letter followed by three small letters) */ + tag = (tag & 0xDFDFDFDFu) | 0x00202020u; + + switch (tag) { + + /* These graduated from the 'Q' private-area codes, but + * the old code is still aliased by Unicode, and the Qaai + * one in use by ICU. */ + case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED; + case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC; + + /* Script variants from http://unicode.org/iso15924/ */ + case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC; + case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN; + case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN; + case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC; + case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC; + case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC; + } + + /* If it looks right, just use the tag as a script */ + if (((uint32_t) tag & 0xE0E0E0E0u) == 0x40606060u) + return (hb_script_t) tag; + + /* Otherwise, return unknown */ + return HB_SCRIPT_UNKNOWN; +} + +/** + * hb_script_from_string: + * @s: (array length=len) (element-type uint8_t): + * @len: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_script_t +hb_script_from_string (const char *s, int len) +{ + return hb_script_from_iso15924_tag (hb_tag_from_string (s, len)); +} + +/** + * hb_script_to_iso15924_tag: + * @script: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_tag_t +hb_script_to_iso15924_tag (hb_script_t script) +{ + return (hb_tag_t) script; +} + +/** + * hb_script_get_horizontal_direction: + * @script: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_direction_t +hb_script_get_horizontal_direction (hb_script_t script) +{ + /* http://goo.gl/x9ilM */ + switch ((hb_tag_t) script) + { + /* Unicode-1.1 additions */ + case HB_SCRIPT_ARABIC: + case HB_SCRIPT_HEBREW: + + /* Unicode-3.0 additions */ + case HB_SCRIPT_SYRIAC: + case HB_SCRIPT_THAANA: + + /* Unicode-4.0 additions */ + case HB_SCRIPT_CYPRIOT: + + /* Unicode-4.1 additions */ + case HB_SCRIPT_KHAROSHTHI: + + /* Unicode-5.0 additions */ + case HB_SCRIPT_PHOENICIAN: + case HB_SCRIPT_NKO: + + /* Unicode-5.1 additions */ + case HB_SCRIPT_LYDIAN: + + /* Unicode-5.2 additions */ + case HB_SCRIPT_AVESTAN: + case HB_SCRIPT_IMPERIAL_ARAMAIC: + case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: + case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: + case HB_SCRIPT_OLD_SOUTH_ARABIAN: + case HB_SCRIPT_OLD_TURKIC: + case HB_SCRIPT_SAMARITAN: + + /* Unicode-6.0 additions */ + case HB_SCRIPT_MANDAIC: + + /* Unicode-6.1 additions */ + case HB_SCRIPT_MEROITIC_CURSIVE: + case HB_SCRIPT_MEROITIC_HIEROGLYPHS: + + /* Unicode-7.0 additions */ + case HB_SCRIPT_MANICHAEAN: + case HB_SCRIPT_MENDE_KIKAKUI: + case HB_SCRIPT_NABATAEAN: + case HB_SCRIPT_OLD_NORTH_ARABIAN: + case HB_SCRIPT_PALMYRENE: + case HB_SCRIPT_PSALTER_PAHLAVI: + + /* Unicode-8.0 additions */ + case HB_SCRIPT_OLD_HUNGARIAN: + + return HB_DIRECTION_RTL; + } + + return HB_DIRECTION_LTR; +} + + +/* hb_user_data_array_t */ + +bool +hb_user_data_array_t::set (hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + if (!key) + return false; + + if (replace) { + if (!data && !destroy) { + items.remove (key, lock); + return true; + } + } + hb_user_data_item_t item = {key, data, destroy}; + bool ret = !!items.replace_or_insert (item, lock, replace); + + return ret; +} + +void * +hb_user_data_array_t::get (hb_user_data_key_t *key) +{ + hb_user_data_item_t item = {NULL }; + + return items.find (key, &item, lock) ? item.data : NULL; +} + + +/* hb_version */ + +/** + * hb_version: + * @major: (out): Library major version component. + * @minor: (out): Library minor version component. + * @micro: (out): Library micro version component. + * + * Returns library version as three integer components. + * + * Since: 0.9.2 + **/ +void +hb_version (unsigned int *major, + unsigned int *minor, + unsigned int *micro) +{ + *major = HB_VERSION_MAJOR; + *minor = HB_VERSION_MINOR; + *micro = HB_VERSION_MICRO; +} + +/** + * hb_version_string: + * + * Returns library version as a string with three components. + * + * Return value: library version string. + * + * Since: 0.9.2 + **/ +const char * +hb_version_string (void) +{ + return HB_VERSION_STRING; +} + +/** + * hb_version_atleast: + * @major: + * @minor: + * @micro: + * + * + * + * Return value: + * + * Since: 0.9.30 + **/ +hb_bool_t +hb_version_atleast (unsigned int major, + unsigned int minor, + unsigned int micro) +{ + return HB_VERSION_ATLEAST (major, minor, micro); +} diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-common.h b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-common.h new file mode 100644 index 00000000000..1f742a2ef57 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-common.h @@ -0,0 +1,354 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_H_IN +#error "Include instead." +#endif + +#ifndef HB_COMMON_H +#define HB_COMMON_H + +#ifndef HB_BEGIN_DECLS +# ifdef __cplusplus +# define HB_BEGIN_DECLS extern "C" { +# define HB_END_DECLS } +# else /* !__cplusplus */ +# define HB_BEGIN_DECLS +# define HB_END_DECLS +# endif /* !__cplusplus */ +#endif + +#if !defined (HB_DONT_DEFINE_STDINT) + +#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \ + defined (_sgi) || defined (__sun) || defined (sun) || \ + defined (__digital__) || defined (__HP_cc) +# include +#elif defined (_AIX) +# include +/* VS 2010 (_MSC_VER 1600) has stdint.h */ +#elif defined (_MSC_VER) && _MSC_VER < 1600 +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +# include +#endif + +#endif + +HB_BEGIN_DECLS + + +typedef int hb_bool_t; + +typedef uint32_t hb_codepoint_t; +typedef int32_t hb_position_t; +typedef uint32_t hb_mask_t; + +typedef union _hb_var_int_t { + uint32_t u32; + int32_t i32; + uint16_t u16[2]; + int16_t i16[2]; + uint8_t u8[4]; + int8_t i8[4]; +} hb_var_int_t; + + +/* hb_tag_t */ + +typedef uint32_t hb_tag_t; + +#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4)))) +#define HB_UNTAG(tag) ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag)) + +#define HB_TAG_NONE HB_TAG(0,0,0,0) +#define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff) +#define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff) + +/* len=-1 means str is NUL-terminated. */ +hb_tag_t +hb_tag_from_string (const char *str, int len); + +/* buf should have 4 bytes. */ +void +hb_tag_to_string (hb_tag_t tag, char *buf); + + +/* hb_direction_t */ + +typedef enum { + HB_DIRECTION_INVALID = 0, + HB_DIRECTION_LTR = 4, + HB_DIRECTION_RTL, + HB_DIRECTION_TTB, + HB_DIRECTION_BTT +} hb_direction_t; + +/* len=-1 means str is NUL-terminated */ +hb_direction_t +hb_direction_from_string (const char *str, int len); + +const char * +hb_direction_to_string (hb_direction_t direction); + +#define HB_DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) & ~3U) == 4) +/* Direction must be valid for the following */ +#define HB_DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int) (dir)) & ~1U) == 4) +#define HB_DIRECTION_IS_VERTICAL(dir) ((((unsigned int) (dir)) & ~1U) == 6) +#define HB_DIRECTION_IS_FORWARD(dir) ((((unsigned int) (dir)) & ~2U) == 4) +#define HB_DIRECTION_IS_BACKWARD(dir) ((((unsigned int) (dir)) & ~2U) == 5) +#define HB_DIRECTION_REVERSE(dir) ((hb_direction_t) (((unsigned int) (dir)) ^ 1)) + + +/* hb_language_t */ + +typedef const struct hb_language_impl_t *hb_language_t; + +/* len=-1 means str is NUL-terminated */ +hb_language_t +hb_language_from_string (const char *str, int len); + +const char * +hb_language_to_string (hb_language_t language); + +#define HB_LANGUAGE_INVALID ((hb_language_t) NULL) + +hb_language_t +hb_language_get_default (void); + + +/* hb_script_t */ + +/* http://unicode.org/iso15924/ */ +/* http://goo.gl/x9ilM */ +/* Unicode Character Database property: Script (sc) */ +typedef enum +{ + /*1.1*/ HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'), + /*1.1*/ HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'), + /*5.0*/ HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'), + + /*1.1*/ HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'), + /*1.1*/ HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'), + /*1.1*/ HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'), + /*1.1*/ HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'), + /*1.1*/ HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'), + /*1.1*/ HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'), + /*1.1*/ HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'), + /*1.1*/ HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'), + /*1.1*/ HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'), + /*1.1*/ HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'), + /*1.1*/ HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'), + /*1.1*/ HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'), + /*1.1*/ HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'), + /*1.1*/ HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'), + /*1.1*/ HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'), + /*1.1*/ HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'), + /*1.1*/ HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'), + /*1.1*/ HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'), + /*1.1*/ HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'), + /*1.1*/ HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'), + /*1.1*/ HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'), + /*1.1*/ HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'), + + /*2.0*/ HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'), + + /*3.0*/ HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'), + /*3.0*/ HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'), + /*3.0*/ HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG ('C','a','n','s'), + /*3.0*/ HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'), + /*3.0*/ HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'), + /*3.0*/ HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'), + /*3.0*/ HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'), + /*3.0*/ HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'), + /*3.0*/ HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'), + /*3.0*/ HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'), + /*3.0*/ HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'), + /*3.0*/ HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'), + /*3.0*/ HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'), + /*3.0*/ HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'), + + /*3.1*/ HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'), + /*3.1*/ HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'), + /*3.1*/ HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'), + + /*3.2*/ HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'), + /*3.2*/ HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'), + /*3.2*/ HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'), + /*3.2*/ HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'), + + /*4.0*/ HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'), + /*4.0*/ HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'), + /*4.0*/ HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'), + /*4.0*/ HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'), + /*4.0*/ HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'), + /*4.0*/ HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'), + /*4.0*/ HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'), + + /*4.1*/ HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'), + /*4.1*/ HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'), + /*4.1*/ HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'), + /*4.1*/ HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'), + /*4.1*/ HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'), + /*4.1*/ HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'), + /*4.1*/ HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'), + /*4.1*/ HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'), + + /*5.0*/ HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'), + /*5.0*/ HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'), + /*5.0*/ HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'), + /*5.0*/ HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'), + /*5.0*/ HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'), + + /*5.1*/ HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'), + /*5.1*/ HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'), + /*5.1*/ HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'), + /*5.1*/ HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'), + /*5.1*/ HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'), + /*5.1*/ HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'), + /*5.1*/ HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'), + /*5.1*/ HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'), + /*5.1*/ HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'), + /*5.1*/ HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'), + /*5.1*/ HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'), + + /*5.2*/ HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'), + /*5.2*/ HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'), + /*5.2*/ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'), + /*5.2*/ HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'), + /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'), + /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'), + /*5.2*/ HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'), + /*5.2*/ HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'), + /*5.2*/ HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'), + /*5.2*/ HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'), + /*5.2*/ HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'), + /*5.2*/ HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'), + /*5.2*/ HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'), + /*5.2*/ HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'), + /*5.2*/ HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'), + + /*6.0*/ HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'), + /*6.0*/ HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'), + /*6.0*/ HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'), + + /*6.1*/ HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'), + /*6.1*/ HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'), + /*6.1*/ HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'), + /*6.1*/ HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'), + /*6.1*/ HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'), + /*6.1*/ HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), + /*6.1*/ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), + + /* + * Since: 0.9.30 + */ + /*7.0*/ HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'), + /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'), + /*7.0*/ HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'), + /*7.0*/ HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'), + /*7.0*/ HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'), + /*7.0*/ HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'), + /*7.0*/ HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'), + /*7.0*/ HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'), + /*7.0*/ HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'), + /*7.0*/ HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'), + /*7.0*/ HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'), + /*7.0*/ HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'), + /*7.0*/ HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'), + /*7.0*/ HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'), + /*7.0*/ HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'), + /*7.0*/ HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'), + /*7.0*/ HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'), + /*7.0*/ HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'), + /*7.0*/ HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'), + /*7.0*/ HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'), + /*7.0*/ HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'), + /*7.0*/ HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'), + /*7.0*/ HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'), + + /*8.0*/ HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'), + /*8.0*/ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'), + /*8.0*/ HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'), + /*8.0*/ HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'), + /*8.0*/ HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'), + /*8.0*/ HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'), + + /* No script set. */ + HB_SCRIPT_INVALID = HB_TAG_NONE, + + /* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t + * without risking undefined behavior. Include both a signed and unsigned max, + * since technically enums are int, and indeed, hb_script_t ends up being signed. + * See this thread for technicalities: + * + * http://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html + */ + _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX, /*< skip >*/ + _HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/ + +} hb_script_t; + + +/* Script functions */ + +hb_script_t +hb_script_from_iso15924_tag (hb_tag_t tag); + +/* sugar for tag_from_string() then script_from_iso15924_tag */ +/* len=-1 means s is NUL-terminated */ +hb_script_t +hb_script_from_string (const char *s, int len); + +hb_tag_t +hb_script_to_iso15924_tag (hb_script_t script); + +hb_direction_t +hb_script_get_horizontal_direction (hb_script_t script); + + +/* User data */ + +typedef struct hb_user_data_key_t { + /*< private >*/ + char unused; +} hb_user_data_key_t; + +typedef void (*hb_destroy_func_t) (void *user_data); + + +HB_END_DECLS + +#endif /* HB_COMMON_H */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-coretext.cc b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-coretext.cc new file mode 100644 index 00000000000..369b7365c2b --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-coretext.cc @@ -0,0 +1,1219 @@ +/* + * Copyright © 2012,2013 Mozilla Foundation. + * Copyright © 2012,2013 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Mozilla Author(s): Jonathan Kew + * Google Author(s): Behdad Esfahbod + */ + +#define HB_SHAPER coretext +#define hb_coretext_shaper_face_data_t CGFont +#include "hb-shaper-impl-private.hh" + +#include "hb-coretext.h" + + +#ifndef HB_DEBUG_CORETEXT +#define HB_DEBUG_CORETEXT (HB_DEBUG+0) +#endif + + +static void +release_table_data (void *user_data) +{ + CFDataRef cf_data = reinterpret_cast (user_data); + CFRelease(cf_data); +} + +static hb_blob_t * +reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) +{ + CGFontRef cg_font = reinterpret_cast (user_data); + CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag); + if (unlikely (!cf_data)) + return NULL; + + const char *data = reinterpret_cast (CFDataGetBytePtr (cf_data)); + const size_t length = CFDataGetLength (cf_data); + if (!data || !length) + return NULL; + + return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY, + reinterpret_cast (const_cast<__CFData *> (cf_data)), + release_table_data); +} + +hb_face_t * +hb_coretext_face_create (CGFontRef cg_font) +{ + return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease); +} + + +HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face) +HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font) + + +/* + * shaper face data + */ + +static void +release_data (void *info, const void *data, size_t size) +{ + assert (hb_blob_get_length ((hb_blob_t *) info) == size && + hb_blob_get_data ((hb_blob_t *) info, NULL) == data); + + hb_blob_destroy ((hb_blob_t *) info); +} + +hb_coretext_shaper_face_data_t * +_hb_coretext_shaper_face_data_create (hb_face_t *face) +{ + hb_coretext_shaper_face_data_t *data = NULL; + + if (face->destroy == (hb_destroy_func_t) CGFontRelease) + { + data = CGFontRetain ((CGFontRef) face->user_data); + } + else + { + hb_blob_t *blob = hb_face_reference_blob (face); + unsigned int blob_length; + const char *blob_data = hb_blob_get_data (blob, &blob_length); + if (unlikely (!blob_length)) + DEBUG_MSG (CORETEXT, face, "Face has empty blob"); + + CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data); + if (likely (provider)) + { + data = CGFontCreateWithDataProvider (provider); + CGDataProviderRelease (provider); + } + } + + if (unlikely (!data)) { + DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed"); + } + + return data; +} + +void +_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data) +{ + CFRelease (data); +} + +/* + * Since: 0.9.10 + */ +CGFontRef +hb_coretext_face_get_cg_font (hb_face_t *face) +{ + if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL; + hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); + return face_data; +} + + +/* + * shaper font data + */ + +struct hb_coretext_shaper_font_data_t { + CTFontRef ct_font; + CGFloat x_mult, y_mult; /* From CT space to HB space. */ +}; + +hb_coretext_shaper_font_data_t * +_hb_coretext_shaper_font_data_create (hb_font_t *font) +{ + if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL; + + hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t)); + if (unlikely (!data)) + return NULL; + + hb_face_t *face = font->face; + hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); + + /* Choose a CoreText font size and calculate multipliers to convert to HarfBuzz space. */ + /* TODO: use upem instead of 36? */ + CGFloat font_size = 36.; /* Default... */ + /* No idea if the following is even a good idea. */ + if (font->y_ppem) + font_size = font->y_ppem; + + if (font_size < 0) + font_size = -font_size; + data->x_mult = (CGFloat) font->x_scale / font_size; + data->y_mult = (CGFloat) font->y_scale / font_size; + data->ct_font = CTFontCreateWithGraphicsFont (face_data, font_size, NULL, NULL); + if (unlikely (!data->ct_font)) { + DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed"); + free (data); + return NULL; + } + + return data; +} + +void +_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data) +{ + CFRelease (data->ct_font); + free (data); +} + + +/* + * shaper shape_plan data + */ + +struct hb_coretext_shaper_shape_plan_data_t {}; + +hb_coretext_shaper_shape_plan_data_t * +_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, + const hb_feature_t *user_features HB_UNUSED, + unsigned int num_user_features HB_UNUSED) +{ + return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; +} + +void +_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED) +{ +} + +CTFontRef +hb_coretext_font_get_ct_font (hb_font_t *font) +{ + if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL; + hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); + return font_data->ct_font; +} + + +/* + * shaper + */ + +struct feature_record_t { + unsigned int feature; + unsigned int setting; +}; + +struct active_feature_t { + feature_record_t rec; + unsigned int order; + + static int cmp (const active_feature_t *a, const active_feature_t *b) { + return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 : + a->order < b->order ? -1 : a->order > b->order ? 1 : + a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 : + 0; + } + bool operator== (const active_feature_t *f) { + return cmp (this, f) == 0; + } +}; + +struct feature_event_t { + unsigned int index; + bool start; + active_feature_t feature; + + static int cmp (const feature_event_t *a, const feature_event_t *b) { + return a->index < b->index ? -1 : a->index > b->index ? 1 : + a->start < b->start ? -1 : a->start > b->start ? 1 : + active_feature_t::cmp (&a->feature, &b->feature); + } +}; + +struct range_record_t { + CTFontRef font; + unsigned int index_first; /* == start */ + unsigned int index_last; /* == end - 1 */ +}; + + +/* The following enum members are added in OS X 10.8. */ +#define kAltHalfWidthTextSelector 6 +#define kAltProportionalTextSelector 5 +#define kAlternateHorizKanaOffSelector 1 +#define kAlternateHorizKanaOnSelector 0 +#define kAlternateKanaType 34 +#define kAlternateVertKanaOffSelector 3 +#define kAlternateVertKanaOnSelector 2 +#define kCaseSensitiveLayoutOffSelector 1 +#define kCaseSensitiveLayoutOnSelector 0 +#define kCaseSensitiveLayoutType 33 +#define kCaseSensitiveSpacingOffSelector 3 +#define kCaseSensitiveSpacingOnSelector 2 +#define kContextualAlternatesOffSelector 1 +#define kContextualAlternatesOnSelector 0 +#define kContextualAlternatesType 36 +#define kContextualLigaturesOffSelector 19 +#define kContextualLigaturesOnSelector 18 +#define kContextualSwashAlternatesOffSelector 5 +#define kContextualSwashAlternatesOnSelector 4 +#define kDefaultLowerCaseSelector 0 +#define kDefaultUpperCaseSelector 0 +#define kHistoricalLigaturesOffSelector 21 +#define kHistoricalLigaturesOnSelector 20 +#define kHojoCharactersSelector 12 +#define kJIS2004CharactersSelector 11 +#define kLowerCasePetiteCapsSelector 2 +#define kLowerCaseSmallCapsSelector 1 +#define kLowerCaseType 37 +#define kMathematicalGreekOffSelector 11 +#define kMathematicalGreekOnSelector 10 +#define kNLCCharactersSelector 13 +#define kQuarterWidthTextSelector 4 +#define kScientificInferiorsSelector 4 +#define kStylisticAltEightOffSelector 17 +#define kStylisticAltEightOnSelector 16 +#define kStylisticAltEighteenOffSelector 37 +#define kStylisticAltEighteenOnSelector 36 +#define kStylisticAltElevenOffSelector 23 +#define kStylisticAltElevenOnSelector 22 +#define kStylisticAltFifteenOffSelector 31 +#define kStylisticAltFifteenOnSelector 30 +#define kStylisticAltFiveOffSelector 11 +#define kStylisticAltFiveOnSelector 10 +#define kStylisticAltFourOffSelector 9 +#define kStylisticAltFourOnSelector 8 +#define kStylisticAltFourteenOffSelector 29 +#define kStylisticAltFourteenOnSelector 28 +#define kStylisticAltNineOffSelector 19 +#define kStylisticAltNineOnSelector 18 +#define kStylisticAltNineteenOffSelector 39 +#define kStylisticAltNineteenOnSelector 38 +#define kStylisticAltOneOffSelector 3 +#define kStylisticAltOneOnSelector 2 +#define kStylisticAltSevenOffSelector 15 +#define kStylisticAltSevenOnSelector 14 +#define kStylisticAltSeventeenOffSelector 35 +#define kStylisticAltSeventeenOnSelector 34 +#define kStylisticAltSixOffSelector 13 +#define kStylisticAltSixOnSelector 12 +#define kStylisticAltSixteenOffSelector 33 +#define kStylisticAltSixteenOnSelector 32 +#define kStylisticAltTenOffSelector 21 +#define kStylisticAltTenOnSelector 20 +#define kStylisticAltThirteenOffSelector 27 +#define kStylisticAltThirteenOnSelector 26 +#define kStylisticAltThreeOffSelector 7 +#define kStylisticAltThreeOnSelector 6 +#define kStylisticAltTwelveOffSelector 25 +#define kStylisticAltTwelveOnSelector 24 +#define kStylisticAltTwentyOffSelector 41 +#define kStylisticAltTwentyOnSelector 40 +#define kStylisticAltTwoOffSelector 5 +#define kStylisticAltTwoOnSelector 4 +#define kStylisticAlternativesType 35 +#define kSwashAlternatesOffSelector 3 +#define kSwashAlternatesOnSelector 2 +#define kThirdWidthTextSelector 3 +#define kTraditionalNamesCharactersSelector 14 +#define kUpperCasePetiteCapsSelector 2 +#define kUpperCaseSmallCapsSelector 1 +#define kUpperCaseType 38 + +/* Table data courtesy of Apple. */ +static const struct feature_mapping_t { + FourCharCode otFeatureTag; + uint16_t aatFeatureType; + uint16_t selectorToEnable; + uint16_t selectorToDisable; +} feature_mappings[] = { + { 'c2pc', kUpperCaseType, kUpperCasePetiteCapsSelector, kDefaultUpperCaseSelector }, + { 'c2sc', kUpperCaseType, kUpperCaseSmallCapsSelector, kDefaultUpperCaseSelector }, + { 'calt', kContextualAlternatesType, kContextualAlternatesOnSelector, kContextualAlternatesOffSelector }, + { 'case', kCaseSensitiveLayoutType, kCaseSensitiveLayoutOnSelector, kCaseSensitiveLayoutOffSelector }, + { 'clig', kLigaturesType, kContextualLigaturesOnSelector, kContextualLigaturesOffSelector }, + { 'cpsp', kCaseSensitiveLayoutType, kCaseSensitiveSpacingOnSelector, kCaseSensitiveSpacingOffSelector }, + { 'cswh', kContextualAlternatesType, kContextualSwashAlternatesOnSelector, kContextualSwashAlternatesOffSelector }, + { 'dlig', kLigaturesType, kRareLigaturesOnSelector, kRareLigaturesOffSelector }, + { 'expt', kCharacterShapeType, kExpertCharactersSelector, 16 }, + { 'frac', kFractionsType, kDiagonalFractionsSelector, kNoFractionsSelector }, + { 'fwid', kTextSpacingType, kMonospacedTextSelector, 7 }, + { 'halt', kTextSpacingType, kAltHalfWidthTextSelector, 7 }, + { 'hist', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector }, + { 'hkna', kAlternateKanaType, kAlternateHorizKanaOnSelector, kAlternateHorizKanaOffSelector, }, + { 'hlig', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector }, + { 'hngl', kTransliterationType, kHanjaToHangulSelector, kNoTransliterationSelector }, + { 'hojo', kCharacterShapeType, kHojoCharactersSelector, 16 }, + { 'hwid', kTextSpacingType, kHalfWidthTextSelector, 7 }, + { 'ital', kItalicCJKRomanType, kCJKItalicRomanOnSelector, kCJKItalicRomanOffSelector }, + { 'jp04', kCharacterShapeType, kJIS2004CharactersSelector, 16 }, + { 'jp78', kCharacterShapeType, kJIS1978CharactersSelector, 16 }, + { 'jp83', kCharacterShapeType, kJIS1983CharactersSelector, 16 }, + { 'jp90', kCharacterShapeType, kJIS1990CharactersSelector, 16 }, + { 'liga', kLigaturesType, kCommonLigaturesOnSelector, kCommonLigaturesOffSelector }, + { 'lnum', kNumberCaseType, kUpperCaseNumbersSelector, 2 }, + { 'mgrk', kMathematicalExtrasType, kMathematicalGreekOnSelector, kMathematicalGreekOffSelector }, + { 'nlck', kCharacterShapeType, kNLCCharactersSelector, 16 }, + { 'onum', kNumberCaseType, kLowerCaseNumbersSelector, 2 }, + { 'ordn', kVerticalPositionType, kOrdinalsSelector, kNormalPositionSelector }, + { 'palt', kTextSpacingType, kAltProportionalTextSelector, 7 }, + { 'pcap', kLowerCaseType, kLowerCasePetiteCapsSelector, kDefaultLowerCaseSelector }, + { 'pkna', kTextSpacingType, kProportionalTextSelector, 7 }, + { 'pnum', kNumberSpacingType, kProportionalNumbersSelector, 4 }, + { 'pwid', kTextSpacingType, kProportionalTextSelector, 7 }, + { 'qwid', kTextSpacingType, kQuarterWidthTextSelector, 7 }, + { 'ruby', kRubyKanaType, kRubyKanaOnSelector, kRubyKanaOffSelector }, + { 'sinf', kVerticalPositionType, kScientificInferiorsSelector, kNormalPositionSelector }, + { 'smcp', kLowerCaseType, kLowerCaseSmallCapsSelector, kDefaultLowerCaseSelector }, + { 'smpl', kCharacterShapeType, kSimplifiedCharactersSelector, 16 }, + { 'ss01', kStylisticAlternativesType, kStylisticAltOneOnSelector, kStylisticAltOneOffSelector }, + { 'ss02', kStylisticAlternativesType, kStylisticAltTwoOnSelector, kStylisticAltTwoOffSelector }, + { 'ss03', kStylisticAlternativesType, kStylisticAltThreeOnSelector, kStylisticAltThreeOffSelector }, + { 'ss04', kStylisticAlternativesType, kStylisticAltFourOnSelector, kStylisticAltFourOffSelector }, + { 'ss05', kStylisticAlternativesType, kStylisticAltFiveOnSelector, kStylisticAltFiveOffSelector }, + { 'ss06', kStylisticAlternativesType, kStylisticAltSixOnSelector, kStylisticAltSixOffSelector }, + { 'ss07', kStylisticAlternativesType, kStylisticAltSevenOnSelector, kStylisticAltSevenOffSelector }, + { 'ss08', kStylisticAlternativesType, kStylisticAltEightOnSelector, kStylisticAltEightOffSelector }, + { 'ss09', kStylisticAlternativesType, kStylisticAltNineOnSelector, kStylisticAltNineOffSelector }, + { 'ss10', kStylisticAlternativesType, kStylisticAltTenOnSelector, kStylisticAltTenOffSelector }, + { 'ss11', kStylisticAlternativesType, kStylisticAltElevenOnSelector, kStylisticAltElevenOffSelector }, + { 'ss12', kStylisticAlternativesType, kStylisticAltTwelveOnSelector, kStylisticAltTwelveOffSelector }, + { 'ss13', kStylisticAlternativesType, kStylisticAltThirteenOnSelector, kStylisticAltThirteenOffSelector }, + { 'ss14', kStylisticAlternativesType, kStylisticAltFourteenOnSelector, kStylisticAltFourteenOffSelector }, + { 'ss15', kStylisticAlternativesType, kStylisticAltFifteenOnSelector, kStylisticAltFifteenOffSelector }, + { 'ss16', kStylisticAlternativesType, kStylisticAltSixteenOnSelector, kStylisticAltSixteenOffSelector }, + { 'ss17', kStylisticAlternativesType, kStylisticAltSeventeenOnSelector, kStylisticAltSeventeenOffSelector }, + { 'ss18', kStylisticAlternativesType, kStylisticAltEighteenOnSelector, kStylisticAltEighteenOffSelector }, + { 'ss19', kStylisticAlternativesType, kStylisticAltNineteenOnSelector, kStylisticAltNineteenOffSelector }, + { 'ss20', kStylisticAlternativesType, kStylisticAltTwentyOnSelector, kStylisticAltTwentyOffSelector }, + { 'subs', kVerticalPositionType, kInferiorsSelector, kNormalPositionSelector }, + { 'sups', kVerticalPositionType, kSuperiorsSelector, kNormalPositionSelector }, + { 'swsh', kContextualAlternatesType, kSwashAlternatesOnSelector, kSwashAlternatesOffSelector }, + { 'titl', kStyleOptionsType, kTitlingCapsSelector, kNoStyleOptionsSelector }, + { 'tnam', kCharacterShapeType, kTraditionalNamesCharactersSelector, 16 }, + { 'tnum', kNumberSpacingType, kMonospacedNumbersSelector, 4 }, + { 'trad', kCharacterShapeType, kTraditionalCharactersSelector, 16 }, + { 'twid', kTextSpacingType, kThirdWidthTextSelector, 7 }, + { 'unic', kLetterCaseType, 14, 15 }, + { 'valt', kTextSpacingType, kAltProportionalTextSelector, 7 }, + { 'vert', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector }, + { 'vhal', kTextSpacingType, kAltHalfWidthTextSelector, 7 }, + { 'vkna', kAlternateKanaType, kAlternateVertKanaOnSelector, kAlternateVertKanaOffSelector }, + { 'vpal', kTextSpacingType, kAltProportionalTextSelector, 7 }, + { 'vrt2', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector }, + { 'zero', kTypographicExtrasType, kSlashedZeroOnSelector, kSlashedZeroOffSelector }, +}; + +static int +_hb_feature_mapping_cmp (const void *key_, const void *entry_) +{ + unsigned int key = * (unsigned int *) key_; + const feature_mapping_t * entry = (const feature_mapping_t *) entry_; + return key < entry->otFeatureTag ? -1 : + key > entry->otFeatureTag ? 1 : + 0; +} + +hb_bool_t +_hb_coretext_shape (hb_shape_plan_t *shape_plan, + hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features) +{ + hb_face_t *face = font->face; + hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); + hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); + + /* Attach marks to their bases, to match the 'ot' shaper. + * Adapted from hb-ot-shape:hb_form_clusters(). + * Note that this only makes us be closer to the 'ot' shaper, + * but by no means the same. For example, if there's + * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will + * continue pointing to B2 even though B2 was merged into B1's + * cluster... */ + { + hb_unicode_funcs_t *unicode = buffer->unicode; + unsigned int count = buffer->len; + hb_glyph_info_t *info = buffer->info; + for (unsigned int i = 1; i < count; i++) + if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (info[i].codepoint))) + buffer->merge_clusters (i - 1, i + 1); + } + + hb_auto_array_t feature_records; + hb_auto_array_t range_records; + + /* + * Set up features. + * (copied + modified from code from hb-uniscribe.cc) + */ + if (num_features) + { + /* Sort features by start/end events. */ + hb_auto_array_t feature_events; + for (unsigned int i = 0; i < num_features; i++) + { + const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag, + feature_mappings, + ARRAY_LENGTH (feature_mappings), + sizeof (feature_mappings[0]), + _hb_feature_mapping_cmp); + if (!mapping) + continue; + + active_feature_t feature; + feature.rec.feature = mapping->aatFeatureType; + feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable; + feature.order = i; + + feature_event_t *event; + + event = feature_events.push (); + if (unlikely (!event)) + goto fail_features; + event->index = features[i].start; + event->start = true; + event->feature = feature; + + event = feature_events.push (); + if (unlikely (!event)) + goto fail_features; + event->index = features[i].end; + event->start = false; + event->feature = feature; + } + feature_events.qsort (); + /* Add a strategic final event. */ + { + active_feature_t feature; + feature.rec.feature = HB_TAG_NONE; + feature.rec.setting = 0; + feature.order = num_features + 1; + + feature_event_t *event = feature_events.push (); + if (unlikely (!event)) + goto fail_features; + event->index = 0; /* This value does magic. */ + event->start = false; + event->feature = feature; + } + + /* Scan events and save features for each range. */ + hb_auto_array_t active_features; + unsigned int last_index = 0; + for (unsigned int i = 0; i < feature_events.len; i++) + { + feature_event_t *event = &feature_events[i]; + + if (event->index != last_index) + { + /* Save a snapshot of active features and the range. */ + range_record_t *range = range_records.push (); + if (unlikely (!range)) + goto fail_features; + + if (active_features.len) + { + CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + + /* TODO sort and resolve conflicting features? */ + /* active_features.qsort (); */ + for (unsigned int j = 0; j < active_features.len; j++) + { + CFStringRef keys[2] = { + kCTFontFeatureTypeIdentifierKey, + kCTFontFeatureSelectorIdentifierKey + }; + CFNumberRef values[2] = { + CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature), + CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting) + }; + CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault, + (const void **) keys, + (const void **) values, + 2, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFRelease (values[0]); + CFRelease (values[1]); + + CFArrayAppendValue (features_array, dict); + CFRelease (dict); + + } + + CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault, + (const void **) &kCTFontFeatureSettingsAttribute, + (const void **) &features_array, + 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFRelease (features_array); + + CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes); + CFRelease (attributes); + + range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc); + CFRelease (font_desc); + } + else + { + range->font = NULL; + } + + range->index_first = last_index; + range->index_last = event->index - 1; + + last_index = event->index; + } + + if (event->start) { + active_feature_t *feature = active_features.push (); + if (unlikely (!feature)) + goto fail_features; + *feature = event->feature; + } else { + active_feature_t *feature = active_features.find (&event->feature); + if (feature) + active_features.remove (feature - active_features.array); + } + } + + if (!range_records.len) /* No active feature found. */ + goto fail_features; + } + else + { + fail_features: + num_features = 0; + } + + unsigned int scratch_size; + hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size); + +#define ALLOCATE_ARRAY(Type, name, len, on_no_room) \ + Type *name = (Type *) scratch; \ + { \ + unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \ + if (unlikely (_consumed > scratch_size)) \ + { \ + on_no_room; \ + assert (0); \ + } \ + scratch += _consumed; \ + scratch_size -= _consumed; \ + } + + ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/); + unsigned int chars_len = 0; + for (unsigned int i = 0; i < buffer->len; i++) { + hb_codepoint_t c = buffer->info[i].codepoint; + if (likely (c <= 0xFFFFu)) + pchars[chars_len++] = c; + else if (unlikely (c > 0x10FFFFu)) + pchars[chars_len++] = 0xFFFDu; + else { + pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10); + pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1)); + } + } + + ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, /*nothing*/); + chars_len = 0; + for (unsigned int i = 0; i < buffer->len; i++) + { + hb_codepoint_t c = buffer->info[i].codepoint; + unsigned int cluster = buffer->info[i].cluster; + log_clusters[chars_len++] = cluster; + if (hb_in_range (c, 0x10000u, 0x10FFFFu)) + log_clusters[chars_len++] = cluster; /* Surrogates. */ + } + +#define FAIL(...) \ + HB_STMT_START { \ + DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \ + ret = false; \ + goto fail; \ + } HB_STMT_END; + + bool ret = true; + CFStringRef string_ref = NULL; + CTLineRef line = NULL; + + if (0) + { +resize_and_retry: + DEBUG_MSG (CORETEXT, buffer, "Buffer resize"); + /* string_ref uses the scratch-buffer for backing store, and line references + * string_ref (via attr_string). We must release those before resizing buffer. */ + assert (string_ref); + assert (line); + CFRelease (string_ref); + CFRelease (line); + string_ref = NULL; + line = NULL; + + /* Get previous start-of-scratch-area, that we use later for readjusting + * our existing scratch arrays. */ + unsigned int old_scratch_used; + hb_buffer_t::scratch_buffer_t *old_scratch; + old_scratch = buffer->get_scratch_buffer (&old_scratch_used); + old_scratch_used = scratch - old_scratch; + + if (unlikely (!buffer->ensure (buffer->allocated * 2))) + FAIL ("Buffer resize failed"); + + /* Adjust scratch, pchars, and log_cluster arrays. This is ugly, but really the + * cleanest way to do without completely restructuring the rest of this shaper. */ + scratch = buffer->get_scratch_buffer (&scratch_size); + pchars = reinterpret_cast (((char *) scratch + ((char *) pchars - (char *) old_scratch))); + log_clusters = reinterpret_cast (((char *) scratch + ((char *) log_clusters - (char *) old_scratch))); + scratch += old_scratch_used; + scratch_size -= old_scratch_used; + } +retry: + { + string_ref = CFStringCreateWithCharactersNoCopy (NULL, + pchars, chars_len, + kCFAllocatorNull); + if (unlikely (!string_ref)) + FAIL ("CFStringCreateWithCharactersNoCopy failed"); + + /* Create an attributed string, populate it, and create a line from it, then release attributed string. */ + { + CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (kCFAllocatorDefault, + chars_len); + if (unlikely (!attr_string)) + FAIL ("CFAttributedStringCreateMutable failed"); + CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref); + if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction)) + { + CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), + kCTVerticalFormsAttributeName, kCFBooleanTrue); + } + + if (buffer->props.language) + { +/* What's the iOS equivalent of this check? + * The symbols was introduced in iOS 7.0. + * At any rate, our fallback is safe and works fine. */ +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 +# define kCTLanguageAttributeName CFSTR ("NSLanguage") +#endif + CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault, + hb_language_to_string (buffer->props.language), + kCFStringEncodingUTF8, + kCFAllocatorNull); + if (unlikely (!lang)) + FAIL ("CFStringCreateWithCStringNoCopy failed"); + CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), + kCTLanguageAttributeName, lang); + CFRelease (lang); + } + CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), + kCTFontAttributeName, font_data->ct_font); + + if (num_features) + { + unsigned int start = 0; + range_record_t *last_range = &range_records[0]; + for (unsigned int k = 0; k < chars_len; k++) + { + range_record_t *range = last_range; + while (log_clusters[k] < range->index_first) + range--; + while (log_clusters[k] > range->index_last) + range++; + if (range != last_range) + { + if (last_range->font) + CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start), + kCTFontAttributeName, last_range->font); + + start = k; + } + + last_range = range; + } + if (start != chars_len && last_range->font) + CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start), + kCTFontAttributeName, last_range->font); + } + + int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1; + CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level); + CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault, + (const void **) &kCTTypesetterOptionForcedEmbeddingLevel, + (const void **) &level_number, + 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (unlikely (!options)) + FAIL ("CFDictionaryCreate failed"); + + CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options); + CFRelease (options); + CFRelease (attr_string); + if (unlikely (!typesetter)) + FAIL ("CTTypesetterCreateWithAttributedStringAndOptions failed"); + + line = CTTypesetterCreateLine (typesetter, CFRangeMake(0, 0)); + CFRelease (typesetter); + if (unlikely (!line)) + FAIL ("CTTypesetterCreateLine failed"); + } + + CFArrayRef glyph_runs = CTLineGetGlyphRuns (line); + unsigned int num_runs = CFArrayGetCount (glyph_runs); + DEBUG_MSG (CORETEXT, NULL, "Num runs: %d", num_runs); + + buffer->len = 0; + uint32_t status_and = ~0, status_or = 0; + double advances_so_far = 0; + /* For right-to-left runs, CoreText returns the glyphs positioned such that + * any trailing whitespace is to the left of (0,0). Adjust coordinate system + * to fix for that. Test with any RTL string with trailing spaces. + * https://code.google.com/p/chromium/issues/detail?id=469028 + */ + if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) + { + advances_so_far -= CTLineGetTrailingWhitespaceWidth (line); + if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction)) + advances_so_far = -advances_so_far; + } + + const CFRange range_all = CFRangeMake (0, 0); + + for (unsigned int i = 0; i < num_runs; i++) + { + CTRunRef run = static_cast(CFArrayGetValueAtIndex (glyph_runs, i)); + CTRunStatus run_status = CTRunGetStatus (run); + status_or |= run_status; + status_and &= run_status; + DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status); + double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL); + if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction)) + run_advance = -run_advance; + DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance); + + /* CoreText does automatic font fallback (AKA "cascading") for characters + * not supported by the requested font, and provides no way to turn it off, + * so we must detect if the returned run uses a font other than the requested + * one and fill in the buffer with .notdef glyphs instead of random glyph + * indices from a different font. + */ + CFDictionaryRef attributes = CTRunGetAttributes (run); + CTFontRef run_ct_font = static_cast(CFDictionaryGetValue (attributes, kCTFontAttributeName)); + if (!CFEqual (run_ct_font, font_data->ct_font)) + { + /* The run doesn't use our main font instance. We have to figure out + * whether font fallback happened, or this is just CoreText giving us + * another CTFont using the same underlying CGFont. CoreText seems + * to do that in a variety of situations, one of which being vertical + * text, but also perhaps for caching reasons. + * + * First, see if it uses any of our subfonts created to set font features... + * + * Next, compare the CGFont to the one we used to create our fonts. + * Even this doesn't work all the time. + * + * Finally, we compare PS names, which I don't think are unique... + * + * Looks like if we really want to be sure here we have to modify the + * font to change the name table, similar to what we do in the uniscribe + * backend. + * + * However, even that wouldn't work if we were passed in the CGFont to + * begin with. + * + * Webkit uses a slightly different approach: it installs LastResort + * as fallback chain, and then checks PS name of used font against + * LastResort. That one is safe for any font except for LastResort, + * as opposed to ours, which can fail if we are using any uninstalled + * font that has the same name as an installed font. + * + * See: http://github.com/behdad/harfbuzz/pull/36 + */ + bool matched = false; + for (unsigned int i = 0; i < range_records.len; i++) + if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font)) + { + matched = true; + break; + } + if (!matched) + { + CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0); + if (run_cg_font) + { + matched = CFEqual (run_cg_font, face_data); + CFRelease (run_cg_font); + } + } + if (!matched) + { + CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFontPostScriptNameKey); + CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey); + CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0); + CFRelease (run_ps_name); + CFRelease (font_ps_name); + if (result == kCFCompareEqualTo) + matched = true; + } + if (!matched) + { + CFRange range = CTRunGetStringRange (run); + DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld", + range.location, range.location + range.length); + if (!buffer->ensure_inplace (buffer->len + range.length)) + goto resize_and_retry; + hb_glyph_info_t *info = buffer->info + buffer->len; + + hb_codepoint_t notdef = 0; + hb_direction_t dir = buffer->props.direction; + hb_position_t x_advance, y_advance, x_offset, y_offset; + hb_font_get_glyph_advance_for_direction (font, notdef, dir, &x_advance, &y_advance); + hb_font_get_glyph_origin_for_direction (font, notdef, dir, &x_offset, &y_offset); + hb_position_t advance = x_advance + y_advance; + x_offset = -x_offset; + y_offset = -y_offset; + + unsigned int old_len = buffer->len; + for (CFIndex j = range.location; j < range.location + range.length; j++) + { + UniChar ch = CFStringGetCharacterAtIndex (string_ref, j); + if (hb_in_range (ch, 0xDC00u, 0xDFFFu) && range.location < j) + { + ch = CFStringGetCharacterAtIndex (string_ref, j - 1); + if (hb_in_range (ch, 0xD800u, 0xDBFFu)) + /* This is the second of a surrogate pair. Don't need .notdef + * for this one. */ + continue; + } + if (buffer->unicode->is_default_ignorable (ch)) + continue; + + info->codepoint = notdef; + info->cluster = log_clusters[j]; + + info->mask = advance; + info->var1.i32 = x_offset; + info->var2.i32 = y_offset; + + info++; + buffer->len++; + } + if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) + buffer->reverse_range (old_len, buffer->len); + advances_so_far += run_advance; + continue; + } + } + + unsigned int num_glyphs = CTRunGetGlyphCount (run); + if (num_glyphs == 0) + continue; + + if (!buffer->ensure_inplace (buffer->len + num_glyphs)) + goto resize_and_retry; + + hb_glyph_info_t *run_info = buffer->info + buffer->len; + + /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always + * succeed, and so copying data to our own buffer will be rare. Reports + * have it that this changed in OS X 10.10 Yosemite, and NULL is returned + * frequently. At any rate, we can test that codepath by setting USE_PTR + * to false. */ + +#define USE_PTR true + +#define SCRATCH_SAVE() \ + unsigned int scratch_size_saved = scratch_size; \ + hb_buffer_t::scratch_buffer_t *scratch_saved = scratch + +#define SCRATCH_RESTORE() \ + scratch_size = scratch_size_saved; \ + scratch = scratch_saved; + + { /* Setup glyphs */ + SCRATCH_SAVE(); + const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL; + if (!glyphs) { + ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry); + CTRunGetGlyphs (run, range_all, glyph_buf); + glyphs = glyph_buf; + } + const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : NULL; + if (!string_indices) { + ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry); + CTRunGetStringIndices (run, range_all, index_buf); + string_indices = index_buf; + } + hb_glyph_info_t *info = run_info; + for (unsigned int j = 0; j < num_glyphs; j++) + { + info->codepoint = glyphs[j]; + info->cluster = log_clusters[string_indices[j]]; + info++; + } + SCRATCH_RESTORE(); + } + { + /* Setup positions. + * Note that CoreText does not return advances for glyphs. As such, + * for all but last glyph, we use the delta position to next glyph as + * advance (in the advance direction only), and for last glyph we set + * whatever is needed to make the whole run's advance add up. */ + SCRATCH_SAVE(); + const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL; + if (!positions) { + ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry); + CTRunGetPositions (run, range_all, position_buf); + positions = position_buf; + } + hb_glyph_info_t *info = run_info; + CGFloat x_mult = font_data->x_mult, y_mult = font_data->y_mult; + if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) + { + hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult; + for (unsigned int j = 0; j < num_glyphs; j++) + { + double advance; + if (likely (j + 1 < num_glyphs)) + advance = positions[j + 1].x - positions[j].x; + else /* last glyph */ + advance = run_advance - (positions[j].x - positions[0].x); + info->mask = advance * x_mult; + info->var1.i32 = x_offset; + info->var2.i32 = positions[j].y * y_mult; + info++; + } + } + else + { + hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult; + for (unsigned int j = 0; j < num_glyphs; j++) + { + double advance; + if (likely (j + 1 < num_glyphs)) + advance = positions[j + 1].y - positions[j].y; + else /* last glyph */ + advance = run_advance - (positions[j].y - positions[0].y); + info->mask = advance * y_mult; + info->var1.i32 = positions[j].x * x_mult; + info->var2.i32 = y_offset; + info++; + } + } + SCRATCH_RESTORE(); + advances_so_far += run_advance; + } +#undef SCRATCH_RESTORE +#undef SCRATCH_SAVE +#undef USE_PTR +#undef ALLOCATE_ARRAY + + buffer->len += num_glyphs; + } + + /* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel, + * or if it does, it doesn't resepct it. So we get runs with wrong + * directions. As such, disable the assert... It wouldn't crash, but + * cursoring will be off... + * + * http://crbug.com/419769 + */ + if (0) + { + /* Make sure all runs had the expected direction. */ + bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); + assert (bool (status_and & kCTRunStatusRightToLeft) == backward); + assert (bool (status_or & kCTRunStatusRightToLeft) == backward); + } + + buffer->clear_positions (); + + unsigned int count = buffer->len; + hb_glyph_info_t *info = buffer->info; + hb_glyph_position_t *pos = buffer->pos; + if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) + for (unsigned int i = 0; i < count; i++) + { + pos->x_advance = info->mask; + pos->x_offset = info->var1.i32; + pos->y_offset = info->var2.i32; + info++, pos++; + } + else + for (unsigned int i = 0; i < count; i++) + { + pos->y_advance = info->mask; + pos->x_offset = info->var1.i32; + pos->y_offset = info->var2.i32; + info++, pos++; + } + + /* Fix up clusters so that we never return out-of-order indices; + * if core text has reordered glyphs, we'll merge them to the + * beginning of the reordered cluster. CoreText is nice enough + * to tell us whenever it has produced nonmonotonic results... + * Note that we assume the input clusters were nonmonotonic to + * begin with. + * + * This does *not* mean we'll form the same clusters as Uniscribe + * or the native OT backend, only that the cluster indices will be + * monotonic in the output buffer. */ + if (count > 1 && (status_or & kCTRunStatusNonMonotonic)) + { + hb_glyph_info_t *info = buffer->info; + if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) + { + unsigned int cluster = info[count - 1].cluster; + for (unsigned int i = count - 1; i > 0; i--) + { + cluster = MIN (cluster, info[i - 1].cluster); + info[i - 1].cluster = cluster; + } + } + else + { + unsigned int cluster = info[0].cluster; + for (unsigned int i = 1; i < count; i++) + { + cluster = MIN (cluster, info[i].cluster); + info[i].cluster = cluster; + } + } + } + } + +#undef FAIL + +fail: + if (string_ref) + CFRelease (string_ref); + if (line) + CFRelease (line); + + for (unsigned int i = 0; i < range_records.len; i++) + if (range_records[i].font) + CFRelease (range_records[i].font); + + return ret; +} + + +/* + * AAT shaper + */ + +HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face) +HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font) + + +/* + * shaper face data + */ + +struct hb_coretext_aat_shaper_face_data_t {}; + +hb_coretext_aat_shaper_face_data_t * +_hb_coretext_aat_shaper_face_data_create (hb_face_t *face) +{ + hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT); + /* Umm, we just reference the table to check whether it exists. + * Maybe add better API for this? */ + if (!hb_blob_get_length (mort_blob)) + { + hb_blob_destroy (mort_blob); + mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX); + if (!hb_blob_get_length (mort_blob)) + { + hb_blob_destroy (mort_blob); + return NULL; + } + } + hb_blob_destroy (mort_blob); + + return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL; +} + +void +_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED) +{ +} + + +/* + * shaper font data + */ + +struct hb_coretext_aat_shaper_font_data_t {}; + +hb_coretext_aat_shaper_font_data_t * +_hb_coretext_aat_shaper_font_data_create (hb_font_t *font) +{ + return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL; +} + +void +_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED) +{ +} + + +/* + * shaper shape_plan data + */ + +struct hb_coretext_aat_shaper_shape_plan_data_t {}; + +hb_coretext_aat_shaper_shape_plan_data_t * +_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, + const hb_feature_t *user_features HB_UNUSED, + unsigned int num_user_features HB_UNUSED) +{ + return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; +} + +void +_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED) +{ +} + + +/* + * shaper + */ + +hb_bool_t +_hb_coretext_aat_shape (hb_shape_plan_t *shape_plan, + hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features) +{ + return _hb_coretext_shape (shape_plan, font, buffer, features, num_features); +} diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-coretext.h b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-coretext.h new file mode 100644 index 00000000000..25267bc9784 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-coretext.h @@ -0,0 +1,60 @@ +/* + * Copyright © 2012 Mozilla Foundation. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Mozilla Author(s): Jonathan Kew + */ + +#ifndef HB_CORETEXT_H +#define HB_CORETEXT_H + +#include "hb.h" + +#include +#if TARGET_OS_IPHONE +# include +# include +#else +# include +#endif + +HB_BEGIN_DECLS + + +#define HB_CORETEXT_TAG_MORT HB_TAG('m','o','r','t') +#define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x') + + +hb_face_t * +hb_coretext_face_create (CGFontRef cg_font); + + +CGFontRef +hb_coretext_face_get_cg_font (hb_face_t *face); + +CTFontRef +hb_coretext_font_get_ct_font (hb_font_t *font); + + +HB_END_DECLS + +#endif /* HB_CORETEXT_H */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-deprecated.h b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-deprecated.h new file mode 100644 index 00000000000..14d435f0068 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-deprecated.h @@ -0,0 +1,51 @@ +/* + * Copyright © 2013 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_H_IN +#error "Include instead." +#endif + +#ifndef HB_DEPRECATED_H +#define HB_DEPRECATED_H + +#include "hb-common.h" +#include "hb-unicode.h" +#include "hb-font.h" + +HB_BEGIN_DECLS + +#ifndef HB_DISABLE_DEPRECATED + +#define HB_SCRIPT_CANADIAN_ABORIGINAL HB_SCRIPT_CANADIAN_SYLLABICS + +#define HB_BUFFER_FLAGS_DEFAULT HB_BUFFER_FLAG_DEFAULT +#define HB_BUFFER_SERIALIZE_FLAGS_DEFAULT HB_BUFFER_SERIALIZE_FLAG_DEFAULT + +#endif + +HB_END_DECLS + +#endif /* HB_DEPRECATED_H */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face-private.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face-private.hh new file mode 100644 index 00000000000..c4266fff4f0 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face-private.hh @@ -0,0 +1,107 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_FACE_PRIVATE_HH +#define HB_FACE_PRIVATE_HH + +#include "hb-private.hh" + +#include "hb-object-private.hh" +#include "hb-shaper-private.hh" +#include "hb-shape-plan-private.hh" + + +/* + * hb_face_t + */ + +struct hb_face_t { + hb_object_header_t header; + ASSERT_POD (); + + hb_bool_t immutable; + + hb_reference_table_func_t reference_table_func; + void *user_data; + hb_destroy_func_t destroy; + + unsigned int index; + mutable unsigned int upem; + mutable unsigned int num_glyphs; + + struct hb_shaper_data_t shaper_data; + + struct plan_node_t { + hb_shape_plan_t *shape_plan; + plan_node_t *next; + } *shape_plans; + + + inline hb_blob_t *reference_table (hb_tag_t tag) const + { + hb_blob_t *blob; + + if (unlikely (!reference_table_func)) + return hb_blob_get_empty (); + + blob = reference_table_func (/*XXX*/const_cast (this), tag, user_data); + if (unlikely (!blob)) + return hb_blob_get_empty (); + + return blob; + } + + inline HB_PURE_FUNC unsigned int get_upem (void) const + { + if (unlikely (!upem)) + load_upem (); + return upem; + } + + inline unsigned int get_num_glyphs (void) const + { + if (unlikely (num_glyphs == (unsigned int) -1)) + load_num_glyphs (); + return num_glyphs; + } + + private: + HB_INTERNAL void load_upem (void) const; + HB_INTERNAL void load_num_glyphs (void) const; +}; + +extern HB_INTERNAL const hb_face_t _hb_face_nil; + +#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS +#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, face); +#include "hb-shaper-list.hh" +#undef HB_SHAPER_IMPLEMENT +#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS + + +#endif /* HB_FACE_PRIVATE_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face.cc b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face.cc new file mode 100644 index 00000000000..b5019a122de --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face.cc @@ -0,0 +1,481 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-private.hh" + +#include "hb-ot-layout-private.hh" + +#include "hb-font-private.hh" +#include "hb-open-file-private.hh" +#include "hb-ot-head-table.hh" +#include "hb-ot-maxp-table.hh" + +#include "hb-cache-private.hh" + +#include + + +/* + * hb_face_t + */ + +const hb_face_t _hb_face_nil = { + HB_OBJECT_HEADER_STATIC, + + true, /* immutable */ + + NULL, /* reference_table_func */ + NULL, /* user_data */ + NULL, /* destroy */ + + 0, /* index */ + 1000, /* upem */ + 0, /* num_glyphs */ + + { +#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, +#include "hb-shaper-list.hh" +#undef HB_SHAPER_IMPLEMENT + }, + + NULL, /* shape_plans */ +}; + + +/** + * hb_face_create_for_tables: + * @reference_table_func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Return value: (transfer full) + * + * Since: 0.9.2 + **/ +hb_face_t * +hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, + void *user_data, + hb_destroy_func_t destroy) +{ + hb_face_t *face; + + if (!reference_table_func || !(face = hb_object_create ())) { + if (destroy) + destroy (user_data); + return hb_face_get_empty (); + } + + face->reference_table_func = reference_table_func; + face->user_data = user_data; + face->destroy = destroy; + + face->upem = 0; + face->num_glyphs = (unsigned int) -1; + + return face; +} + + +typedef struct hb_face_for_data_closure_t { + hb_blob_t *blob; + unsigned int index; +} hb_face_for_data_closure_t; + +static hb_face_for_data_closure_t * +_hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index) +{ + hb_face_for_data_closure_t *closure; + + closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t)); + if (unlikely (!closure)) + return NULL; + + closure->blob = blob; + closure->index = index; + + return closure; +} + +static void +_hb_face_for_data_closure_destroy (hb_face_for_data_closure_t *closure) +{ + hb_blob_destroy (closure->blob); + free (closure); +} + +static hb_blob_t * +_hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) +{ + hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data; + + if (tag == HB_TAG_NONE) + return hb_blob_reference (data->blob); + + const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer::lock_instance (data->blob); + const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index); + + const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag); + + hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length); + + return blob; +} + +/** + * hb_face_create: (Xconstructor) + * @blob: + * @index: + * + * + * + * Return value: (transfer full): + * + * Since: 0.9.2 + **/ +hb_face_t * +hb_face_create (hb_blob_t *blob, + unsigned int index) +{ + hb_face_t *face; + + if (unlikely (!blob)) + blob = hb_blob_get_empty (); + + hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer::sanitize (hb_blob_reference (blob)), index); + + if (unlikely (!closure)) + return hb_face_get_empty (); + + face = hb_face_create_for_tables (_hb_face_for_data_reference_table, + closure, + (hb_destroy_func_t) _hb_face_for_data_closure_destroy); + + hb_face_set_index (face, index); + + return face; +} + +/** + * hb_face_get_empty: + * + * + * + * Return value: (transfer full) + * + * Since: 0.9.2 + **/ +hb_face_t * +hb_face_get_empty (void) +{ + return const_cast (&_hb_face_nil); +} + + +/** + * hb_face_reference: (skip) + * @face: a face. + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_face_t * +hb_face_reference (hb_face_t *face) +{ + return hb_object_reference (face); +} + +/** + * hb_face_destroy: (skip) + * @face: a face. + * + * + * + * Since: 0.9.2 + **/ +void +hb_face_destroy (hb_face_t *face) +{ + if (!hb_object_destroy (face)) return; + + for (hb_face_t::plan_node_t *node = face->shape_plans; node; ) + { + hb_face_t::plan_node_t *next = node->next; + hb_shape_plan_destroy (node->shape_plan); + free (node); + node = next; + } + +#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face); +#include "hb-shaper-list.hh" +#undef HB_SHAPER_IMPLEMENT + + if (face->destroy) + face->destroy (face->user_data); + + free (face); +} + +/** + * hb_face_set_user_data: (skip) + * @face: a face. + * @key: + * @data: + * @destroy: + * @replace: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_face_set_user_data (hb_face_t *face, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (face, key, data, destroy, replace); +} + +/** + * hb_face_get_user_data: (skip) + * @face: a face. + * @key: + * + * + * + * Return value: (transfer none): + * + * Since: 0.9.2 + **/ +void * +hb_face_get_user_data (hb_face_t *face, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (face, key); +} + +/** + * hb_face_make_immutable: + * @face: a face. + * + * + * + * Since: 0.9.2 + **/ +void +hb_face_make_immutable (hb_face_t *face) +{ + if (unlikely (hb_object_is_inert (face))) + return; + + face->immutable = true; +} + +/** + * hb_face_is_immutable: + * @face: a face. + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_face_is_immutable (hb_face_t *face) +{ + return face->immutable; +} + + +/** + * hb_face_reference_table: + * @face: a face. + * @tag: + * + * + * + * Return value: (transfer full): + * + * Since: 0.9.2 + **/ +hb_blob_t * +hb_face_reference_table (hb_face_t *face, + hb_tag_t tag) +{ + return face->reference_table (tag); +} + +/** + * hb_face_reference_blob: + * @face: a face. + * + * + * + * Return value: (transfer full): + * + * Since: 0.9.2 + **/ +hb_blob_t * +hb_face_reference_blob (hb_face_t *face) +{ + return face->reference_table (HB_TAG_NONE); +} + +/** + * hb_face_set_index: + * @face: a face. + * @index: + * + * + * + * Since: 0.9.2 + **/ +void +hb_face_set_index (hb_face_t *face, + unsigned int index) +{ + if (face->immutable) + return; + + face->index = index; +} + +/** + * hb_face_get_index: + * @face: a face. + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +unsigned int +hb_face_get_index (hb_face_t *face) +{ + return face->index; +} + +/** + * hb_face_set_upem: + * @face: a face. + * @upem: + * + * + * + * Since: 0.9.2 + **/ +void +hb_face_set_upem (hb_face_t *face, + unsigned int upem) +{ + if (face->immutable) + return; + + face->upem = upem; +} + +/** + * hb_face_get_upem: + * @face: a face. + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +unsigned int +hb_face_get_upem (hb_face_t *face) +{ + return face->get_upem (); +} + +void +hb_face_t::load_upem (void) const +{ + hb_blob_t *head_blob = OT::Sanitizer::sanitize (reference_table (HB_OT_TAG_head)); + const OT::head *head_table = OT::Sanitizer::lock_instance (head_blob); + upem = head_table->get_upem (); + hb_blob_destroy (head_blob); +} + +/** + * hb_face_set_glyph_count: + * @face: a face. + * @glyph_count: + * + * + * + * Since: 0.9.7 + **/ +void +hb_face_set_glyph_count (hb_face_t *face, + unsigned int glyph_count) +{ + if (face->immutable) + return; + + face->num_glyphs = glyph_count; +} + +/** + * hb_face_get_glyph_count: + * @face: a face. + * + * + * + * Return value: + * + * Since: 0.9.7 + **/ +unsigned int +hb_face_get_glyph_count (hb_face_t *face) +{ + return face->get_num_glyphs (); +} + +void +hb_face_t::load_num_glyphs (void) const +{ + hb_blob_t *maxp_blob = OT::Sanitizer::sanitize (reference_table (HB_OT_TAG_maxp)); + const OT::maxp *maxp_table = OT::Sanitizer::lock_instance (maxp_blob); + num_glyphs = maxp_table->get_num_glyphs (); + hb_blob_destroy (maxp_blob); +} + + diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face.h b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face.h new file mode 100644 index 00000000000..85807dda302 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-face.h @@ -0,0 +1,117 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#ifndef HB_H_IN +#error "Include instead." +#endif + +#ifndef HB_FACE_H +#define HB_FACE_H + +#include "hb-common.h" +#include "hb-blob.h" + +HB_BEGIN_DECLS + + +/* + * hb_face_t + */ + +typedef struct hb_face_t hb_face_t; + +hb_face_t * +hb_face_create (hb_blob_t *blob, + unsigned int index); + +typedef hb_blob_t * (*hb_reference_table_func_t) (hb_face_t *face, hb_tag_t tag, void *user_data); + +/* calls destroy() when not needing user_data anymore */ +hb_face_t * +hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, + void *user_data, + hb_destroy_func_t destroy); + +hb_face_t * +hb_face_get_empty (void); + +hb_face_t * +hb_face_reference (hb_face_t *face); + +void +hb_face_destroy (hb_face_t *face); + +hb_bool_t +hb_face_set_user_data (hb_face_t *face, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + + +void * +hb_face_get_user_data (hb_face_t *face, + hb_user_data_key_t *key); + +void +hb_face_make_immutable (hb_face_t *face); + +hb_bool_t +hb_face_is_immutable (hb_face_t *face); + + +hb_blob_t * +hb_face_reference_table (hb_face_t *face, + hb_tag_t tag); + +hb_blob_t * +hb_face_reference_blob (hb_face_t *face); + +void +hb_face_set_index (hb_face_t *face, + unsigned int index); + +unsigned int +hb_face_get_index (hb_face_t *face); + +void +hb_face_set_upem (hb_face_t *face, + unsigned int upem); + +unsigned int +hb_face_get_upem (hb_face_t *face); + +void +hb_face_set_glyph_count (hb_face_t *face, + unsigned int glyph_count); + +unsigned int +hb_face_get_glyph_count (hb_face_t *face); + + +HB_END_DECLS + +#endif /* HB_FACE_H */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-fallback-shape.cc b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-fallback-shape.cc new file mode 100644 index 00000000000..8e1628be033 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-fallback-shape.cc @@ -0,0 +1,141 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#define HB_SHAPER fallback +#include "hb-shaper-impl-private.hh" + + +/* + * shaper face data + */ + +struct hb_fallback_shaper_face_data_t {}; + +hb_fallback_shaper_face_data_t * +_hb_fallback_shaper_face_data_create (hb_face_t *face HB_UNUSED) +{ + return (hb_fallback_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED; +} + +void +_hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data HB_UNUSED) +{ +} + + +/* + * shaper font data + */ + +struct hb_fallback_shaper_font_data_t {}; + +hb_fallback_shaper_font_data_t * +_hb_fallback_shaper_font_data_create (hb_font_t *font HB_UNUSED) +{ + return (hb_fallback_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; +} + +void +_hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data HB_UNUSED) +{ +} + + +/* + * shaper shape_plan data + */ + +struct hb_fallback_shaper_shape_plan_data_t {}; + +hb_fallback_shaper_shape_plan_data_t * +_hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, + const hb_feature_t *user_features HB_UNUSED, + unsigned int num_user_features HB_UNUSED) +{ + return (hb_fallback_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; +} + +void +_hb_fallback_shaper_shape_plan_data_destroy (hb_fallback_shaper_shape_plan_data_t *data HB_UNUSED) +{ +} + + +/* + * shaper + */ + +hb_bool_t +_hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED, + hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features HB_UNUSED, + unsigned int num_features HB_UNUSED) +{ + /* TODO + * + * - Apply fallback kern. + * - Handle Variation Selectors? + * - Apply normalization? + * + * This will make the fallback shaper into a dumb "TrueType" + * shaper which many people unfortunately still request. + */ + + hb_codepoint_t space; + bool has_space = font->get_glyph (' ', 0, &space); + + buffer->clear_positions (); + + hb_direction_t direction = buffer->props.direction; + hb_unicode_funcs_t *unicode = buffer->unicode; + unsigned int count = buffer->len; + hb_glyph_info_t *info = buffer->info; + hb_glyph_position_t *pos = buffer->pos; + for (unsigned int i = 0; i < count; i++) + { + if (has_space && unicode->is_default_ignorable (info[i].codepoint)) { + info[i].codepoint = space; + pos[i].x_advance = 0; + pos[i].y_advance = 0; + continue; + } + font->get_glyph (info[i].codepoint, 0, &info[i].codepoint); + font->get_glyph_advance_for_direction (info[i].codepoint, + direction, + &pos[i].x_advance, + &pos[i].y_advance); + font->subtract_glyph_origin_for_direction (info[i].codepoint, + direction, + &pos[i].x_offset, + &pos[i].y_offset); + } + + if (HB_DIRECTION_IS_BACKWARD (direction)) + hb_buffer_reverse (buffer); + + return true; +} diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font-private.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font-private.hh new file mode 100644 index 00000000000..253e71786f6 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font-private.hh @@ -0,0 +1,415 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_FONT_PRIVATE_HH +#define HB_FONT_PRIVATE_HH + +#include "hb-private.hh" + +#include "hb-object-private.hh" +#include "hb-face-private.hh" +#include "hb-shaper-private.hh" + + + +/* + * hb_font_funcs_t + */ + +#define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \ + HB_FONT_FUNC_IMPLEMENT (glyph) \ + HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \ + HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \ + HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \ + HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \ + HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \ + HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \ + HB_FONT_FUNC_IMPLEMENT (glyph_extents) \ + HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \ + HB_FONT_FUNC_IMPLEMENT (glyph_name) \ + HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \ + /* ^--- Add new callbacks here */ + +struct hb_font_funcs_t { + hb_object_header_t header; + ASSERT_POD (); + + hb_bool_t immutable; + + /* Don't access these directly. Call hb_font_get_*() instead. */ + + struct { +#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name; + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT + } get; + + struct { +#define HB_FONT_FUNC_IMPLEMENT(name) void *name; + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT + } user_data; + + struct { +#define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name; + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT + } destroy; +}; + + + +/* + * hb_font_t + */ + +struct hb_font_t { + hb_object_header_t header; + ASSERT_POD (); + + hb_bool_t immutable; + + hb_font_t *parent; + hb_face_t *face; + + int x_scale; + int y_scale; + + unsigned int x_ppem; + unsigned int y_ppem; + + hb_font_funcs_t *klass; + void *user_data; + hb_destroy_func_t destroy; + + struct hb_shaper_data_t shaper_data; + + + /* Convert from font-space to user-space */ + inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, this->x_scale); } + inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, this->y_scale); } + + /* Convert from parent-font user-space to our user-space */ + inline hb_position_t parent_scale_x_distance (hb_position_t v) { + if (unlikely (parent && parent->x_scale != x_scale)) + return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale); + return v; + } + inline hb_position_t parent_scale_y_distance (hb_position_t v) { + if (unlikely (parent && parent->y_scale != y_scale)) + return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale); + return v; + } + inline hb_position_t parent_scale_x_position (hb_position_t v) { + return parent_scale_x_distance (v); + } + inline hb_position_t parent_scale_y_position (hb_position_t v) { + return parent_scale_y_distance (v); + } + + inline void parent_scale_distance (hb_position_t *x, hb_position_t *y) { + *x = parent_scale_x_distance (*x); + *y = parent_scale_y_distance (*y); + } + inline void parent_scale_position (hb_position_t *x, hb_position_t *y) { + *x = parent_scale_x_position (*x); + *y = parent_scale_y_position (*y); + } + + + /* Public getters */ + + inline hb_bool_t has_glyph (hb_codepoint_t unicode) + { + hb_codepoint_t glyph; + return get_glyph (unicode, 0, &glyph); + } + + inline hb_bool_t get_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector, + hb_codepoint_t *glyph) + { + *glyph = 0; + return klass->get.glyph (this, user_data, + unicode, variation_selector, glyph, + klass->user_data.glyph); + } + + inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph) + { + return klass->get.glyph_h_advance (this, user_data, + glyph, + klass->user_data.glyph_h_advance); + } + + inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph) + { + return klass->get.glyph_v_advance (this, user_data, + glyph, + klass->user_data.glyph_v_advance); + } + + inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) + { + *x = *y = 0; + return klass->get.glyph_h_origin (this, user_data, + glyph, x, y, + klass->user_data.glyph_h_origin); + } + + inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) + { + *x = *y = 0; + return klass->get.glyph_v_origin (this, user_data, + glyph, x, y, + klass->user_data.glyph_v_origin); + } + + inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph) + { + return klass->get.glyph_h_kerning (this, user_data, + left_glyph, right_glyph, + klass->user_data.glyph_h_kerning); + } + + inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph) + { + return klass->get.glyph_v_kerning (this, user_data, + top_glyph, bottom_glyph, + klass->user_data.glyph_v_kerning); + } + + inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph, + hb_glyph_extents_t *extents) + { + memset (extents, 0, sizeof (*extents)); + return klass->get.glyph_extents (this, user_data, + glyph, + extents, + klass->user_data.glyph_extents); + } + + inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index, + hb_position_t *x, hb_position_t *y) + { + *x = *y = 0; + return klass->get.glyph_contour_point (this, user_data, + glyph, point_index, + x, y, + klass->user_data.glyph_contour_point); + } + + inline hb_bool_t get_glyph_name (hb_codepoint_t glyph, + char *name, unsigned int size) + { + if (size) *name = '\0'; + return klass->get.glyph_name (this, user_data, + glyph, + name, size, + klass->user_data.glyph_name); + } + + inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph) + { + *glyph = 0; + if (len == -1) len = strlen (name); + return klass->get.glyph_from_name (this, user_data, + name, len, + glyph, + klass->user_data.glyph_from_name); + } + + + /* A bit higher-level, and with fallback */ + + inline void get_glyph_advance_for_direction (hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) + { + if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) { + *x = get_glyph_h_advance (glyph); + *y = 0; + } else { + *x = 0; + *y = get_glyph_v_advance (glyph); + } + } + + /* Internal only */ + inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) + { + *x = get_glyph_h_advance (glyph) / 2; + + /* TODO use font_metrics.ascent */ + *y = y_scale; + } + + inline void get_glyph_origin_for_direction (hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) + { + if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) + { + if (!get_glyph_h_origin (glyph, x, y) && + get_glyph_v_origin (glyph, x, y)) + { + hb_position_t dx, dy; + guess_v_origin_minus_h_origin (glyph, &dx, &dy); + *x -= dx; *y -= dy; + } + } + else + { + if (!get_glyph_v_origin (glyph, x, y) && + get_glyph_h_origin (glyph, x, y)) + { + hb_position_t dx, dy; + guess_v_origin_minus_h_origin (glyph, &dx, &dy); + *x += dx; *y += dy; + } + } + } + + inline void add_glyph_origin_for_direction (hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) + { + hb_position_t origin_x, origin_y; + + get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y); + + *x += origin_x; + *y += origin_y; + } + + inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) + { + hb_position_t origin_x, origin_y; + + get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y); + + *x -= origin_x; + *y -= origin_y; + } + + inline void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) + { + if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) { + *x = get_glyph_h_kerning (first_glyph, second_glyph); + *y = 0; + } else { + *x = 0; + *y = get_glyph_v_kerning (first_glyph, second_glyph); + } + } + + inline hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph, + hb_direction_t direction, + hb_glyph_extents_t *extents) + { + hb_bool_t ret = get_glyph_extents (glyph, extents); + + if (ret) + subtract_glyph_origin_for_direction (glyph, direction, &extents->x_bearing, &extents->y_bearing); + + return ret; + } + + inline hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) + { + hb_bool_t ret = get_glyph_contour_point (glyph, point_index, x, y); + + if (ret) + subtract_glyph_origin_for_direction (glyph, direction, x, y); + + return ret; + } + + /* Generates gidDDD if glyph has no name. */ + inline void + glyph_to_string (hb_codepoint_t glyph, + char *s, unsigned int size) + { + if (get_glyph_name (glyph, s, size)) return; + + if (size && snprintf (s, size, "gid%u", glyph) < 0) + *s = '\0'; + } + + /* Parses gidDDD and uniUUUU strings automatically. */ + inline hb_bool_t + glyph_from_string (const char *s, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph) + { + if (get_glyph_from_name (s, len, glyph)) return true; + + if (len == -1) len = strlen (s); + + /* Straight glyph index. */ + if (hb_codepoint_parse (s, len, 10, glyph)) + return true; + + if (len > 3) + { + /* gidDDD syntax for glyph indices. */ + if (0 == strncmp (s, "gid", 3) && + hb_codepoint_parse (s + 3, len - 3, 10, glyph)) + return true; + + /* uniUUUU and other Unicode character indices. */ + hb_codepoint_t unichar; + if (0 == strncmp (s, "uni", 3) && + hb_codepoint_parse (s + 3, len - 3, 16, &unichar) && + get_glyph (unichar, 0, glyph)) + return true; + } + + return false; + } + + private: + inline hb_position_t em_scale (int16_t v, int scale) { return (hb_position_t) (v * (int64_t) scale / face->get_upem ()); } +}; + +#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS +#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font); +#include "hb-shaper-list.hh" +#undef HB_SHAPER_IMPLEMENT +#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS + + +#endif /* HB_FONT_PRIVATE_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font.cc b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font.cc new file mode 100644 index 00000000000..fdf871f15ff --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font.cc @@ -0,0 +1,1266 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-private.hh" + +#include "hb-ot-layout-private.hh" + +#include "hb-font-private.hh" +#include "hb-open-file-private.hh" +#include "hb-ot-head-table.hh" +#include "hb-ot-maxp-table.hh" + +#include "hb-cache-private.hh" + +#include + + +/* + * hb_font_funcs_t + */ + +static hb_bool_t +hb_font_get_glyph_nil (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t unicode, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent->get_glyph (unicode, variation_selector, glyph); + + *glyph = 0; + return false; +} + +static hb_position_t +hb_font_get_glyph_h_advance_nil (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph)); + + return font->x_scale; +} + +static hb_position_t +hb_font_get_glyph_v_advance_nil (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph)); + + return font->y_scale; +} + +static hb_bool_t +hb_font_get_glyph_h_origin_nil (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + if (font->parent) { + hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y); + if (ret) + font->parent_scale_position (x, y); + return ret; + } + + *x = *y = 0; + return false; +} + +static hb_bool_t +hb_font_get_glyph_v_origin_nil (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + if (font->parent) { + hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y); + if (ret) + font->parent_scale_position (x, y); + return ret; + } + + *x = *y = 0; + return false; +} + +static hb_position_t +hb_font_get_glyph_h_kerning_nil (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t left_glyph, + hb_codepoint_t right_glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph)); + + return 0; +} + +static hb_position_t +hb_font_get_glyph_v_kerning_nil (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t top_glyph, + hb_codepoint_t bottom_glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph)); + + return 0; +} + +static hb_bool_t +hb_font_get_glyph_extents_nil (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + void *user_data HB_UNUSED) +{ + if (font->parent) { + hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents); + if (ret) { + font->parent_scale_position (&extents->x_bearing, &extents->y_bearing); + font->parent_scale_distance (&extents->width, &extents->height); + } + return ret; + } + + memset (extents, 0, sizeof (*extents)); + return false; +} + +static hb_bool_t +hb_font_get_glyph_contour_point_nil (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + unsigned int point_index, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + if (font->parent) { + hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y); + if (ret) + font->parent_scale_position (x, y); + return ret; + } + + *x = *y = 0; + return false; +} + +static hb_bool_t +hb_font_get_glyph_name_nil (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + char *name, unsigned int size, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent->get_glyph_name (glyph, name, size); + + if (size) *name = '\0'; + return false; +} + +static hb_bool_t +hb_font_get_glyph_from_name_nil (hb_font_t *font, + void *font_data HB_UNUSED, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent->get_glyph_from_name (name, len, glyph); + + *glyph = 0; + return false; +} + + +static const hb_font_funcs_t _hb_font_funcs_nil = { + HB_OBJECT_HEADER_STATIC, + + true, /* immutable */ + + { +#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil, + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT + } +}; + + +/** + * hb_font_funcs_create: (Xconstructor) + * + * + * + * Return value: (transfer full): + * + * Since: 0.9.2 + **/ +hb_font_funcs_t * +hb_font_funcs_create (void) +{ + hb_font_funcs_t *ffuncs; + + if (!(ffuncs = hb_object_create ())) + return hb_font_funcs_get_empty (); + + ffuncs->get = _hb_font_funcs_nil.get; + + return ffuncs; +} + +/** + * hb_font_funcs_get_empty: + * + * + * + * Return value: (transfer full): + * + * Since: 0.9.2 + **/ +hb_font_funcs_t * +hb_font_funcs_get_empty (void) +{ + return const_cast (&_hb_font_funcs_nil); +} + +/** + * hb_font_funcs_reference: (skip) + * @ffuncs: font functions. + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_font_funcs_t * +hb_font_funcs_reference (hb_font_funcs_t *ffuncs) +{ + return hb_object_reference (ffuncs); +} + +/** + * hb_font_funcs_destroy: (skip) + * @ffuncs: font functions. + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_funcs_destroy (hb_font_funcs_t *ffuncs) +{ + if (!hb_object_destroy (ffuncs)) return; + +#define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy.name) \ + ffuncs->destroy.name (ffuncs->user_data.name); + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT + + free (ffuncs); +} + +/** + * hb_font_funcs_set_user_data: (skip) + * @ffuncs: font functions. + * @key: + * @data: + * @destroy: + * @replace: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (ffuncs, key, data, destroy, replace); +} + +/** + * hb_font_funcs_get_user_data: (skip) + * @ffuncs: font functions. + * @key: + * + * + * + * Return value: (transfer none): + * + * Since: 0.9.2 + **/ +void * +hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (ffuncs, key); +} + + +/** + * hb_font_funcs_make_immutable: + * @ffuncs: font functions. + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs) +{ + if (unlikely (hb_object_is_inert (ffuncs))) + return; + + ffuncs->immutable = true; +} + +/** + * hb_font_funcs_is_immutable: + * @ffuncs: font functions. + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs) +{ + return ffuncs->immutable; +} + + +#define HB_FONT_FUNC_IMPLEMENT(name) \ + \ +void \ +hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \ + hb_font_get_##name##_func_t func, \ + void *user_data, \ + hb_destroy_func_t destroy) \ +{ \ + if (ffuncs->immutable) { \ + if (destroy) \ + destroy (user_data); \ + return; \ + } \ + \ + if (ffuncs->destroy.name) \ + ffuncs->destroy.name (ffuncs->user_data.name); \ + \ + if (func) { \ + ffuncs->get.name = func; \ + ffuncs->user_data.name = user_data; \ + ffuncs->destroy.name = destroy; \ + } else { \ + ffuncs->get.name = hb_font_get_##name##_nil; \ + ffuncs->user_data.name = NULL; \ + ffuncs->destroy.name = NULL; \ + } \ +} + +HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT + + +/* Public getters */ + +/** + * hb_font_get_glyph: + * @font: a font. + * @unicode: + * @variation_selector: + * @glyph: (out): + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_font_get_glyph (hb_font_t *font, + hb_codepoint_t unicode, hb_codepoint_t variation_selector, + hb_codepoint_t *glyph) +{ + return font->get_glyph (unicode, variation_selector, glyph); +} + +/** + * hb_font_get_glyph_h_advance: + * @font: a font. + * @glyph: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_position_t +hb_font_get_glyph_h_advance (hb_font_t *font, + hb_codepoint_t glyph) +{ + return font->get_glyph_h_advance (glyph); +} + +/** + * hb_font_get_glyph_v_advance: + * @font: a font. + * @glyph: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_position_t +hb_font_get_glyph_v_advance (hb_font_t *font, + hb_codepoint_t glyph) +{ + return font->get_glyph_v_advance (glyph); +} + +/** + * hb_font_get_glyph_h_origin: + * @font: a font. + * @glyph: + * @x: (out): + * @y: (out): + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_font_get_glyph_h_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) +{ + return font->get_glyph_h_origin (glyph, x, y); +} + +/** + * hb_font_get_glyph_v_origin: + * @font: a font. + * @glyph: + * @x: (out): + * @y: (out): + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_font_get_glyph_v_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) +{ + return font->get_glyph_v_origin (glyph, x, y); +} + +/** + * hb_font_get_glyph_h_kerning: + * @font: a font. + * @left_glyph: + * @right_glyph: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_position_t +hb_font_get_glyph_h_kerning (hb_font_t *font, + hb_codepoint_t left_glyph, hb_codepoint_t right_glyph) +{ + return font->get_glyph_h_kerning (left_glyph, right_glyph); +} + +/** + * hb_font_get_glyph_v_kerning: + * @font: a font. + * @top_glyph: + * @bottom_glyph: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_position_t +hb_font_get_glyph_v_kerning (hb_font_t *font, + hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph) +{ + return font->get_glyph_v_kerning (top_glyph, bottom_glyph); +} + +/** + * hb_font_get_glyph_extents: + * @font: a font. + * @glyph: + * @extents: (out): + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_font_get_glyph_extents (hb_font_t *font, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents) +{ + return font->get_glyph_extents (glyph, extents); +} + +/** + * hb_font_get_glyph_contour_point: + * @font: a font. + * @glyph: + * @point_index: + * @x: (out): + * @y: (out): + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_font_get_glyph_contour_point (hb_font_t *font, + hb_codepoint_t glyph, unsigned int point_index, + hb_position_t *x, hb_position_t *y) +{ + return font->get_glyph_contour_point (glyph, point_index, x, y); +} + +/** + * hb_font_get_glyph_name: + * @font: a font. + * @glyph: + * @name: (array length=size): + * @size: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_font_get_glyph_name (hb_font_t *font, + hb_codepoint_t glyph, + char *name, unsigned int size) +{ + return font->get_glyph_name (glyph, name, size); +} + +/** + * hb_font_get_glyph_from_name: + * @font: a font. + * @name: (array length=len): + * @len: + * @glyph: (out): + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_font_get_glyph_from_name (hb_font_t *font, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph) +{ + return font->get_glyph_from_name (name, len, glyph); +} + + +/* A bit higher-level, and with fallback */ + +/** + * hb_font_get_glyph_advance_for_direction: + * @font: a font. + * @glyph: + * @direction: + * @x: (out): + * @y: (out): + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_get_glyph_advance_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) +{ + return font->get_glyph_advance_for_direction (glyph, direction, x, y); +} + +/** + * hb_font_get_glyph_origin_for_direction: + * @font: a font. + * @glyph: + * @direction: + * @x: (out): + * @y: (out): + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_get_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) +{ + return font->get_glyph_origin_for_direction (glyph, direction, x, y); +} + +/** + * hb_font_add_glyph_origin_for_direction: + * @font: a font. + * @glyph: + * @direction: + * @x: (out): + * @y: (out): + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_add_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) +{ + return font->add_glyph_origin_for_direction (glyph, direction, x, y); +} + +/** + * hb_font_subtract_glyph_origin_for_direction: + * @font: a font. + * @glyph: + * @direction: + * @x: (out): + * @y: (out): + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_subtract_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) +{ + return font->subtract_glyph_origin_for_direction (glyph, direction, x, y); +} + +/** + * hb_font_get_glyph_kerning_for_direction: + * @font: a font. + * @first_glyph: + * @second_glyph: + * @direction: + * @x: (out): + * @y: (out): + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_get_glyph_kerning_for_direction (hb_font_t *font, + hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) +{ + return font->get_glyph_kerning_for_direction (first_glyph, second_glyph, direction, x, y); +} + +/** + * hb_font_get_glyph_extents_for_origin: + * @font: a font. + * @glyph: + * @direction: + * @extents: (out): + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_font_get_glyph_extents_for_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_glyph_extents_t *extents) +{ + return font->get_glyph_extents_for_origin (glyph, direction, extents); +} + +/** + * hb_font_get_glyph_contour_point_for_origin: + * @font: a font. + * @glyph: + * @point_index: + * @direction: + * @x: (out): + * @y: (out): + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_font_get_glyph_contour_point_for_origin (hb_font_t *font, + hb_codepoint_t glyph, unsigned int point_index, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) +{ + return font->get_glyph_contour_point_for_origin (glyph, point_index, direction, x, y); +} + +/* Generates gidDDD if glyph has no name. */ +/** + * hb_font_glyph_to_string: + * @font: a font. + * @glyph: + * @s: (array length=size): + * @size: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_glyph_to_string (hb_font_t *font, + hb_codepoint_t glyph, + char *s, unsigned int size) +{ + font->glyph_to_string (glyph, s, size); +} + +/* Parses gidDDD and uniUUUU strings automatically. */ +/** + * hb_font_glyph_from_string: + * @font: a font. + * @s: (array length=len) (element-type uint8_t): + * @len: + * @glyph: (out): + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_font_glyph_from_string (hb_font_t *font, + const char *s, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph) +{ + return font->glyph_from_string (s, len, glyph); +} + + +/* + * hb_font_t + */ + +/** + * hb_font_create: (Xconstructor) + * @face: a face. + * + * + * + * Return value: (transfer full): + * + * Since: 0.9.2 + **/ +hb_font_t * +hb_font_create (hb_face_t *face) +{ + hb_font_t *font; + + if (unlikely (!face)) + face = hb_face_get_empty (); + if (!(font = hb_object_create ())) + return hb_font_get_empty (); + + hb_face_make_immutable (face); + font->face = hb_face_reference (face); + font->klass = hb_font_funcs_get_empty (); + + font->x_scale = font->y_scale = hb_face_get_upem (face); + + return font; +} + +/** + * hb_font_create_sub_font: + * @parent: parent font. + * + * + * + * Return value: (transfer full): + * + * Since: 0.9.2 + **/ +hb_font_t * +hb_font_create_sub_font (hb_font_t *parent) +{ + if (unlikely (!parent)) + parent = hb_font_get_empty (); + + hb_font_t *font = hb_font_create (parent->face); + + if (unlikely (hb_object_is_inert (font))) + return font; + + font->parent = hb_font_reference (parent); + + font->x_scale = parent->x_scale; + font->y_scale = parent->y_scale; + font->x_ppem = parent->x_ppem; + font->y_ppem = parent->y_ppem; + + return font; +} + +/** + * hb_font_get_empty: + * + * + * + * Return value: (transfer full) + * + * Since: 0.9.2 + **/ +hb_font_t * +hb_font_get_empty (void) +{ + static const hb_font_t _hb_font_nil = { + HB_OBJECT_HEADER_STATIC, + + true, /* immutable */ + + NULL, /* parent */ + const_cast (&_hb_face_nil), + + 0, /* x_scale */ + 0, /* y_scale */ + + 0, /* x_ppem */ + 0, /* y_ppem */ + + const_cast (&_hb_font_funcs_nil), /* klass */ + NULL, /* user_data */ + NULL, /* destroy */ + + { +#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, +#include "hb-shaper-list.hh" +#undef HB_SHAPER_IMPLEMENT + } + }; + + return const_cast (&_hb_font_nil); +} + +/** + * hb_font_reference: (skip) + * @font: a font. + * + * + * + * Return value: (transfer full): + * + * Since: 0.9.2 + **/ +hb_font_t * +hb_font_reference (hb_font_t *font) +{ + return hb_object_reference (font); +} + +/** + * hb_font_destroy: (skip) + * @font: a font. + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_destroy (hb_font_t *font) +{ + if (!hb_object_destroy (font)) return; + +#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, font); +#include "hb-shaper-list.hh" +#undef HB_SHAPER_IMPLEMENT + + if (font->destroy) + font->destroy (font->user_data); + + hb_font_destroy (font->parent); + hb_face_destroy (font->face); + hb_font_funcs_destroy (font->klass); + + free (font); +} + +/** + * hb_font_set_user_data: (skip) + * @font: a font. + * @key: + * @data: + * @destroy: + * @replace: + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_font_set_user_data (hb_font_t *font, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (font, key, data, destroy, replace); +} + +/** + * hb_font_get_user_data: (skip) + * @font: a font. + * @key: + * + * + * + * Return value: (transfer none): + * + * Since: 0.9.2 + **/ +void * +hb_font_get_user_data (hb_font_t *font, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (font, key); +} + +/** + * hb_font_make_immutable: + * @font: a font. + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_make_immutable (hb_font_t *font) +{ + if (unlikely (hb_object_is_inert (font))) + return; + + if (font->parent) + hb_font_make_immutable (font->parent); + + font->immutable = true; +} + +/** + * hb_font_is_immutable: + * @font: a font. + * + * + * + * Return value: + * + * Since: 0.9.2 + **/ +hb_bool_t +hb_font_is_immutable (hb_font_t *font) +{ + return font->immutable; +} + +/** + * hb_font_set_parent: + * @font: a font. + * @parent: new parent. + * + * Sets parent font of @font. + * + * Since: 1.0.5 + **/ +void +hb_font_set_parent (hb_font_t *font, + hb_font_t *parent) +{ + if (font->immutable) + return; + + if (!parent) + parent = hb_font_get_empty (); + + hb_font_t *old = font->parent; + + font->parent = hb_font_reference (parent); + + hb_font_destroy (old); +} + +/** + * hb_font_get_parent: + * @font: a font. + * + * + * + * Return value: (transfer none): + * + * Since: 0.9.2 + **/ +hb_font_t * +hb_font_get_parent (hb_font_t *font) +{ + return font->parent; +} + +/** + * hb_font_get_face: + * @font: a font. + * + * + * + * Return value: (transfer none): + * + * Since: 0.9.2 + **/ +hb_face_t * +hb_font_get_face (hb_font_t *font) +{ + return font->face; +} + + +/** + * hb_font_set_funcs: + * @font: a font. + * @klass: (closure font_data) (destroy destroy) (scope notified): + * @font_data: + * @destroy: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_set_funcs (hb_font_t *font, + hb_font_funcs_t *klass, + void *font_data, + hb_destroy_func_t destroy) +{ + if (font->immutable) { + if (destroy) + destroy (font_data); + return; + } + + if (font->destroy) + font->destroy (font->user_data); + + if (!klass) + klass = hb_font_funcs_get_empty (); + + hb_font_funcs_reference (klass); + hb_font_funcs_destroy (font->klass); + font->klass = klass; + font->user_data = font_data; + font->destroy = destroy; +} + +/** + * hb_font_set_funcs_data: + * @font: a font. + * @font_data: (destroy destroy) (scope notified): + * @destroy: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_set_funcs_data (hb_font_t *font, + void *font_data, + hb_destroy_func_t destroy) +{ + /* Destroy user_data? */ + if (font->immutable) { + if (destroy) + destroy (font_data); + return; + } + + if (font->destroy) + font->destroy (font->user_data); + + font->user_data = font_data; + font->destroy = destroy; +} + + +/** + * hb_font_set_scale: + * @font: a font. + * @x_scale: + * @y_scale: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_set_scale (hb_font_t *font, + int x_scale, + int y_scale) +{ + if (font->immutable) + return; + + font->x_scale = x_scale; + font->y_scale = y_scale; +} + +/** + * hb_font_get_scale: + * @font: a font. + * @x_scale: (out): + * @y_scale: (out): + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_get_scale (hb_font_t *font, + int *x_scale, + int *y_scale) +{ + if (x_scale) *x_scale = font->x_scale; + if (y_scale) *y_scale = font->y_scale; +} + +/** + * hb_font_set_ppem: + * @font: a font. + * @x_ppem: + * @y_ppem: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_set_ppem (hb_font_t *font, + unsigned int x_ppem, + unsigned int y_ppem) +{ + if (font->immutable) + return; + + font->x_ppem = x_ppem; + font->y_ppem = y_ppem; +} + +/** + * hb_font_get_ppem: + * @font: a font. + * @x_ppem: (out): + * @y_ppem: (out): + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_get_ppem (hb_font_t *font, + unsigned int *x_ppem, + unsigned int *y_ppem) +{ + if (x_ppem) *x_ppem = font->x_ppem; + if (y_ppem) *y_ppem = font->y_ppem; +} diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font.h b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font.h new file mode 100644 index 00000000000..21049ca4a29 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-font.h @@ -0,0 +1,512 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#ifndef HB_H_IN +#error "Include instead." +#endif + +#ifndef HB_FONT_H +#define HB_FONT_H + +#include "hb-common.h" +#include "hb-face.h" + +HB_BEGIN_DECLS + + +typedef struct hb_font_t hb_font_t; + + +/* + * hb_font_funcs_t + */ + +typedef struct hb_font_funcs_t hb_font_funcs_t; + +hb_font_funcs_t * +hb_font_funcs_create (void); + +hb_font_funcs_t * +hb_font_funcs_get_empty (void); + +hb_font_funcs_t * +hb_font_funcs_reference (hb_font_funcs_t *ffuncs); + +void +hb_font_funcs_destroy (hb_font_funcs_t *ffuncs); + +hb_bool_t +hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + + +void * +hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs, + hb_user_data_key_t *key); + + +void +hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs); + +hb_bool_t +hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs); + + +/* glyph extents */ + +/* Note that height is negative in coordinate systems that grow up. */ +typedef struct hb_glyph_extents_t +{ + hb_position_t x_bearing; /* left side of glyph from origin. */ + hb_position_t y_bearing; /* top side of glyph from origin. */ + hb_position_t width; /* distance from left to right side. */ + hb_position_t height; /* distance from top to bottom side. */ +} hb_glyph_extents_t; + + +/* func types */ + +typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t unicode, hb_codepoint_t variation_selector, + hb_codepoint_t *glyph, + void *user_data); + + +typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + void *user_data); +typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t; +typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t; + +typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y, + void *user_data); +typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t; +typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t; + +typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, + void *user_data); +typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t; +typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t; + + +typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + void *user_data); +typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, unsigned int point_index, + hb_position_t *x, hb_position_t *y, + void *user_data); + + +typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + char *name, unsigned int size, + void *user_data); +typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *font_data, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph, + void *user_data); + + +/* func setters */ + +/** + * hb_font_funcs_set_glyph_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_glyph_h_advance_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_h_advance_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_glyph_v_advance_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_v_advance_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_glyph_h_origin_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_h_origin_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_glyph_v_origin_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_v_origin_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_glyph_h_kerning_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_h_kerning_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_glyph_v_kerning_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_v_kerning_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_glyph_extents_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_extents_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_glyph_contour_point_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_contour_point_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_glyph_name_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_name_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_glyph_from_name_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + **/ +void +hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_from_name_func_t func, + void *user_data, hb_destroy_func_t destroy); + + +/* func dispatch */ + +hb_bool_t +hb_font_get_glyph (hb_font_t *font, + hb_codepoint_t unicode, hb_codepoint_t variation_selector, + hb_codepoint_t *glyph); + +hb_position_t +hb_font_get_glyph_h_advance (hb_font_t *font, + hb_codepoint_t glyph); +hb_position_t +hb_font_get_glyph_v_advance (hb_font_t *font, + hb_codepoint_t glyph); + +hb_bool_t +hb_font_get_glyph_h_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y); +hb_bool_t +hb_font_get_glyph_v_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y); + +hb_position_t +hb_font_get_glyph_h_kerning (hb_font_t *font, + hb_codepoint_t left_glyph, hb_codepoint_t right_glyph); +hb_position_t +hb_font_get_glyph_v_kerning (hb_font_t *font, + hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph); + +hb_bool_t +hb_font_get_glyph_extents (hb_font_t *font, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents); + +hb_bool_t +hb_font_get_glyph_contour_point (hb_font_t *font, + hb_codepoint_t glyph, unsigned int point_index, + hb_position_t *x, hb_position_t *y); + +hb_bool_t +hb_font_get_glyph_name (hb_font_t *font, + hb_codepoint_t glyph, + char *name, unsigned int size); +hb_bool_t +hb_font_get_glyph_from_name (hb_font_t *font, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph); + + +/* high-level funcs, with fallback */ + +void +hb_font_get_glyph_advance_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); +void +hb_font_get_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); +void +hb_font_add_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); +void +hb_font_subtract_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); + +void +hb_font_get_glyph_kerning_for_direction (hb_font_t *font, + hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); + +hb_bool_t +hb_font_get_glyph_extents_for_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_glyph_extents_t *extents); + +hb_bool_t +hb_font_get_glyph_contour_point_for_origin (hb_font_t *font, + hb_codepoint_t glyph, unsigned int point_index, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); + +/* Generates gidDDD if glyph has no name. */ +void +hb_font_glyph_to_string (hb_font_t *font, + hb_codepoint_t glyph, + char *s, unsigned int size); +/* Parses gidDDD and uniUUUU strings automatically. */ +hb_bool_t +hb_font_glyph_from_string (hb_font_t *font, + const char *s, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph); + + +/* + * hb_font_t + */ + +/* Fonts are very light-weight objects */ + +hb_font_t * +hb_font_create (hb_face_t *face); + +hb_font_t * +hb_font_create_sub_font (hb_font_t *parent); + +hb_font_t * +hb_font_get_empty (void); + +hb_font_t * +hb_font_reference (hb_font_t *font); + +void +hb_font_destroy (hb_font_t *font); + +hb_bool_t +hb_font_set_user_data (hb_font_t *font, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + + +void * +hb_font_get_user_data (hb_font_t *font, + hb_user_data_key_t *key); + +void +hb_font_make_immutable (hb_font_t *font); + +hb_bool_t +hb_font_is_immutable (hb_font_t *font); + +void +hb_font_set_parent (hb_font_t *font, + hb_font_t *parent); + +hb_font_t * +hb_font_get_parent (hb_font_t *font); + +hb_face_t * +hb_font_get_face (hb_font_t *font); + + +void +hb_font_set_funcs (hb_font_t *font, + hb_font_funcs_t *klass, + void *font_data, + hb_destroy_func_t destroy); + +/* Be *very* careful with this function! */ +void +hb_font_set_funcs_data (hb_font_t *font, + void *font_data, + hb_destroy_func_t destroy); + + +void +hb_font_set_scale (hb_font_t *font, + int x_scale, + int y_scale); + +void +hb_font_get_scale (hb_font_t *font, + int *x_scale, + int *y_scale); + +/* + * A zero value means "no hinting in that direction" + */ +void +hb_font_set_ppem (hb_font_t *font, + unsigned int x_ppem, + unsigned int y_ppem); + +void +hb_font_get_ppem (hb_font_t *font, + unsigned int *x_ppem, + unsigned int *y_ppem); + + +HB_END_DECLS + +#endif /* HB_FONT_H */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ft.cc b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ft.cc new file mode 100644 index 00000000000..5a8eb2f1a57 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ft.cc @@ -0,0 +1,650 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2009 Keith Stribley + * Copyright © 2015 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-private.hh" + +#include "hb-ft.h" + +#include "hb-font-private.hh" + +#include FT_ADVANCES_H +#include FT_TRUETYPE_TABLES_H + + + +#ifndef HB_DEBUG_FT +#define HB_DEBUG_FT (HB_DEBUG+0) +#endif + + +/* TODO: + * + * In general, this file does a fine job of what it's supposed to do. + * There are, however, things that need more work: + * + * - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy. + * Have not investigated. + * + * - FreeType works in 26.6 mode. Clients can decide to use that mode, and everything + * would work fine. However, we also abuse this API for performing in font-space, + * but don't pass the correct flags to FreeType. We just abuse the no-hinting mode + * for that, such that no rounding etc happens. As such, we don't set ppem, and + * pass NO_HINTING as load_flags. Would be much better to use NO_SCALE, and scale + * ourselves, like we do in uniscribe, etc. + * + * - We don't handle / allow for emboldening / obliqueing. + * + * - In the future, we should add constructors to create fonts in font space? + * + * - FT_Load_Glyph() is exteremely costly. Do something about it? + */ + + +struct hb_ft_font_t +{ + FT_Face ft_face; + int load_flags; + bool unref; /* Whether to destroy ft_face when done. */ +}; + +static hb_ft_font_t * +_hb_ft_font_create (FT_Face ft_face, bool unref) +{ + hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t)); + + if (unlikely (!ft_font)) + return NULL; + + ft_font->ft_face = ft_face; + ft_font->unref = unref; + + ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; + + return ft_font; +} + +static void +_hb_ft_font_destroy (hb_ft_font_t *ft_font) +{ + if (ft_font->unref) + FT_Done_Face (ft_font->ft_face); + + free (ft_font); +} + +/** + * hb_ft_font_set_load_flags: + * @font: + * @load_flags: + * + * + * + * Since: 1.0.5 + **/ +void +hb_ft_font_set_load_flags (hb_font_t *font, int load_flags) +{ + if (font->immutable) + return; + + if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) + return; + + hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; + + ft_font->load_flags = load_flags; +} + +/** + * hb_ft_font_get_load_flags: + * @font: + * + * + * + * Return value: + * Since: 1.0.5 + **/ +int +hb_ft_font_get_load_flags (hb_font_t *font) +{ + if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) + return 0; + + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; + + return ft_font->load_flags; +} + +FT_Face +hb_ft_font_get_face (hb_font_t *font) +{ + if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) + return NULL; + + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; + + return ft_font->ft_face; +} + + + +static hb_bool_t +hb_ft_get_glyph (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t unicode, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) + +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + unsigned int g; + + if (likely (!variation_selector)) + g = FT_Get_Char_Index (ft_font->ft_face, unicode); + else + g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector); + + if (unlikely (!g)) + return false; + + *glyph = g; + return true; +} + +static hb_position_t +hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Fixed v; + + if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v))) + return 0; + + if (font->x_scale < 0) + v = -v; + + return (v + (1<<9)) >> 10; +} + +static hb_position_t +hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Fixed v; + + if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v))) + return 0; + + if (font->y_scale < 0) + v = -v; + + /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates + * have a Y growing upward. Hence the extra negation. */ + return (-v + (1<<9)) >> 10; +} + +static hb_bool_t +hb_ft_get_glyph_h_origin (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, + hb_position_t *x HB_UNUSED, + hb_position_t *y HB_UNUSED, + void *user_data HB_UNUSED) +{ + /* We always work in the horizontal coordinates. */ + return true; +} + +static hb_bool_t +hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Face ft_face = ft_font->ft_face; + + if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) + return false; + + /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates + * have a Y growing upward. Hence the extra negation. */ + *x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX; + *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY); + + if (font->x_scale < 0) + *x = -*x; + if (font->y_scale < 0) + *y = -*y; + + return true; +} + +static hb_position_t +hb_ft_get_glyph_h_kerning (hb_font_t *font, + void *font_data, + hb_codepoint_t left_glyph, + hb_codepoint_t right_glyph, + void *user_data HB_UNUSED) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Vector kerningv; + + FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED; + if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv)) + return 0; + + return kerningv.x; +} + +static hb_position_t +hb_ft_get_glyph_v_kerning (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t top_glyph HB_UNUSED, + hb_codepoint_t bottom_glyph HB_UNUSED, + void *user_data HB_UNUSED) +{ + /* FreeType API doesn't support vertical kerning */ + return 0; +} + +static hb_bool_t +hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + void *user_data HB_UNUSED) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Face ft_face = ft_font->ft_face; + + if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) + return false; + + extents->x_bearing = ft_face->glyph->metrics.horiBearingX; + extents->y_bearing = ft_face->glyph->metrics.horiBearingY; + extents->width = ft_face->glyph->metrics.width; + extents->height = -ft_face->glyph->metrics.height; + return true; +} + +static hb_bool_t +hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + unsigned int point_index, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Face ft_face = ft_font->ft_face; + + if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) + return false; + + if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)) + return false; + + if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points)) + return false; + + *x = ft_face->glyph->outline.points[point_index].x; + *y = ft_face->glyph->outline.points[point_index].y; + + return true; +} + +static hb_bool_t +hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + char *name, unsigned int size, + void *user_data HB_UNUSED) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + + hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size); + if (ret && (size && !*name)) + ret = false; + + return ret; +} + +static hb_bool_t +hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED, + void *font_data, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Face ft_face = ft_font->ft_face; + + if (len < 0) + *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name); + else { + /* Make a nul-terminated version. */ + char buf[128]; + len = MIN (len, (int) sizeof (buf) - 1); + strncpy (buf, name, len); + buf[len] = '\0'; + *glyph = FT_Get_Name_Index (ft_face, buf); + } + + if (*glyph == 0) + { + /* Check whether the given name was actually the name of glyph 0. */ + char buf[128]; + if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) && + len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len)) + return true; + } + + return *glyph != 0; +} + + +static void +_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref) +{ + static const hb_font_funcs_t ft_ffuncs = { + HB_OBJECT_HEADER_STATIC, + + true, /* immutable */ + + { +#define HB_FONT_FUNC_IMPLEMENT(name) hb_ft_get_##name, + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT + } + }; + + hb_font_set_funcs (font, + const_cast (&ft_ffuncs), + _hb_ft_font_create (ft_face, unref), + (hb_destroy_func_t) _hb_ft_font_destroy); +} + + +static hb_blob_t * +reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) +{ + FT_Face ft_face = (FT_Face) user_data; + FT_Byte *buffer; + FT_ULong length = 0; + FT_Error error; + + /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */ + + error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length); + if (error) + return NULL; + + buffer = (FT_Byte *) malloc (length); + if (buffer == NULL) + return NULL; + + error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length); + if (error) + return NULL; + + return hb_blob_create ((const char *) buffer, length, + HB_MEMORY_MODE_WRITABLE, + buffer, free); +} + +/** + * hb_ft_face_create: + * @ft_face: (destroy destroy) (scope notified): + * @destroy: + * + * + * + * Return value: (transfer full): + * Since: 0.9.2 + **/ +hb_face_t * +hb_ft_face_create (FT_Face ft_face, + hb_destroy_func_t destroy) +{ + hb_face_t *face; + + if (ft_face->stream->read == NULL) { + hb_blob_t *blob; + + blob = hb_blob_create ((const char *) ft_face->stream->base, + (unsigned int) ft_face->stream->size, + HB_MEMORY_MODE_READONLY, + ft_face, destroy); + face = hb_face_create (blob, ft_face->face_index); + hb_blob_destroy (blob); + } else { + face = hb_face_create_for_tables (reference_table, ft_face, destroy); + } + + hb_face_set_index (face, ft_face->face_index); + hb_face_set_upem (face, ft_face->units_per_EM); + + return face; +} + +/** + * hb_ft_face_create_referenced: + * @ft_face: + * + * + * + * Return value: (transfer full): + * Since: 0.9.38 + **/ +hb_face_t * +hb_ft_face_create_referenced (FT_Face ft_face) +{ + FT_Reference_Face (ft_face); + return hb_ft_face_create (ft_face, (hb_destroy_func_t) FT_Done_Face); +} + +static void +hb_ft_face_finalize (FT_Face ft_face) +{ + hb_face_destroy ((hb_face_t *) ft_face->generic.data); +} + +/** + * hb_ft_face_create_cached: + * @ft_face: + * + * + * + * Return value: (transfer full): + * Since: 0.9.2 + **/ +hb_face_t * +hb_ft_face_create_cached (FT_Face ft_face) +{ + if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize)) + { + if (ft_face->generic.finalizer) + ft_face->generic.finalizer (ft_face); + + ft_face->generic.data = hb_ft_face_create (ft_face, NULL); + ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize; + } + + return hb_face_reference ((hb_face_t *) ft_face->generic.data); +} + + +/** + * hb_ft_font_create: + * @ft_face: (destroy destroy) (scope notified): + * @destroy: + * + * + * + * Return value: (transfer full): + * Since: 0.9.2 + **/ +hb_font_t * +hb_ft_font_create (FT_Face ft_face, + hb_destroy_func_t destroy) +{ + hb_font_t *font; + hb_face_t *face; + + face = hb_ft_face_create (ft_face, destroy); + font = hb_font_create (face); + hb_face_destroy (face); + _hb_ft_font_set_funcs (font, ft_face, false); + hb_font_set_scale (font, + (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16), + (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16)); +#if 0 /* hb-ft works in no-hinting model */ + hb_font_set_ppem (font, + ft_face->size->metrics.x_ppem, + ft_face->size->metrics.y_ppem); +#endif + + return font; +} + +/** + * hb_ft_font_create_referenced: + * @ft_face: + * + * + * + * Return value: (transfer full): + * Since: 0.9.38 + **/ +hb_font_t * +hb_ft_font_create_referenced (FT_Face ft_face) +{ + FT_Reference_Face (ft_face); + return hb_ft_font_create (ft_face, (hb_destroy_func_t) FT_Done_Face); +} + + +/* Thread-safe, lock-free, FT_Library */ + +static FT_Library ft_library; + +#ifdef HB_USE_ATEXIT +static +void free_ft_library (void) +{ + FT_Done_FreeType (ft_library); +} +#endif + +static FT_Library +get_ft_library (void) +{ +retry: + FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library); + + if (unlikely (!library)) + { + /* Not found; allocate one. */ + if (FT_Init_FreeType (&library)) + return NULL; + + if (!hb_atomic_ptr_cmpexch (&ft_library, NULL, library)) { + FT_Done_FreeType (library); + goto retry; + } + +#ifdef HB_USE_ATEXIT + atexit (free_ft_library); /* First person registers atexit() callback. */ +#endif + } + + return library; +} + +static void +_release_blob (FT_Face ft_face) +{ + hb_blob_destroy ((hb_blob_t *) ft_face->generic.data); +} + +void +hb_ft_font_set_funcs (hb_font_t *font) +{ + hb_blob_t *blob = hb_face_reference_blob (font->face); + unsigned int blob_length; + const char *blob_data = hb_blob_get_data (blob, &blob_length); + if (unlikely (!blob_length)) + DEBUG_MSG (FT, font, "Font face has empty blob"); + + FT_Face ft_face = NULL; + FT_Error err = FT_New_Memory_Face (get_ft_library (), + (const FT_Byte *) blob_data, + blob_length, + hb_face_get_index (font->face), + &ft_face); + + if (unlikely (err)) { + hb_blob_destroy (blob); + DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed"); + return; + } + + FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE); + + FT_Set_Char_Size (ft_face, + abs (font->x_scale), abs (font->y_scale), + 0, 0); +#if 0 + font->x_ppem * 72 * 64 / font->x_scale, + font->y_ppem * 72 * 64 / font->y_scale); +#endif + if (font->x_scale < 0 || font->y_scale < 0) + { + FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0, + 0, font->y_scale < 0 ? -1 : +1}; + FT_Set_Transform (ft_face, &matrix, NULL); + } + + ft_face->generic.data = blob; + ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob; + + _hb_ft_font_set_funcs (font, ft_face, true); + hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING); +} diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ft.h b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ft.h new file mode 100644 index 00000000000..368c317a083 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ft.h @@ -0,0 +1,126 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2015 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_FT_H +#define HB_FT_H + +#include "hb.h" + +#include +#include FT_FREETYPE_H + +HB_BEGIN_DECLS + +/* + * Note: FreeType is not thread-safe. + * Hence, these functions are not either. + */ + +/* + * hb-face from ft-face. + */ + +/* This one creates a new hb-face for given ft-face. + * When the returned hb-face is destroyed, the destroy + * callback is called (if not NULL), with the ft-face passed + * to it. + * + * The client is responsible to make sure that ft-face is + * destroyed after hb-face is destroyed. + * + * Most often you don't want this function. You should use either + * hb_ft_face_create_cached(), or hb_ft_face_create_referenced(). + * In particular, if you are going to pass NULL as destroy, you + * probably should use (the more recent) hb_ft_face_create_referenced() + * instead. + */ +hb_face_t * +hb_ft_face_create (FT_Face ft_face, + hb_destroy_func_t destroy); + +/* This version is like hb_ft_face_create(), except that it caches + * the hb-face using the generic pointer of the ft-face. This means + * that subsequent calls to this function with the same ft-face will + * return the same hb-face (correctly referenced). + * + * Client is still responsible for making sure that ft-face is destroyed + * after hb-face is. + */ +hb_face_t * +hb_ft_face_create_cached (FT_Face ft_face); + +/* This version is like hb_ft_face_create(), except that it calls + * FT_Reference_Face() on ft-face, as such keeping ft-face alive + * as long as the hb-face is. + * + * This is the most convenient version to use. Use it unless you have + * very good reasons not to. + */ +hb_face_t * +hb_ft_face_create_referenced (FT_Face ft_face); + + +/* + * hb-font from ft-face. + */ + +/* + * Note: + * + * Set face size on ft-face before creating hb-font from it. + * Otherwise hb-ft would NOT pick up the font size correctly. + */ + +/* See notes on hb_ft_face_create(). Same issues re lifecycle-management + * apply here. Use hb_ft_font_create_referenced() if you can. */ +hb_font_t * +hb_ft_font_create (FT_Face ft_face, + hb_destroy_func_t destroy); + +/* See notes on hb_ft_face_create_referenced() re lifecycle-management + * issues. */ +hb_font_t * +hb_ft_font_create_referenced (FT_Face ft_face); + +FT_Face +hb_ft_font_get_face (hb_font_t *font); + +void +hb_ft_font_set_load_flags (hb_font_t *font, int load_flags); + +int +hb_ft_font_get_load_flags (hb_font_t *font); + +/* Makes an hb_font_t use FreeType internally to implement font functions. */ +void +hb_ft_font_set_funcs (hb_font_t *font); + + +HB_END_DECLS + +#endif /* HB_FT_H */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-mutex-private.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-mutex-private.hh new file mode 100644 index 00000000000..a69d8869ec1 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-mutex-private.hh @@ -0,0 +1,141 @@ +/* + * Copyright © 2007 Chris Wilson + * Copyright © 2009,2010 Red Hat, Inc. + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Contributor(s): + * Chris Wilson + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_MUTEX_PRIVATE_HH +#define HB_MUTEX_PRIVATE_HH + +#include "hb-private.hh" + + +/* mutex */ + +/* We need external help for these */ + +#if defined(HB_MUTEX_IMPL_INIT) \ + && defined(hb_mutex_impl_init) \ + && defined(hb_mutex_impl_lock) \ + && defined(hb_mutex_impl_unlock) \ + && defined(hb_mutex_impl_finish) + +/* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */ + + +#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__)) + +#include +typedef CRITICAL_SECTION hb_mutex_impl_t; +#define HB_MUTEX_IMPL_INIT {0} +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +#define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0) +#else +#define hb_mutex_impl_init(M) InitializeCriticalSection (M) +#endif +#define hb_mutex_impl_lock(M) EnterCriticalSection (M) +#define hb_mutex_impl_unlock(M) LeaveCriticalSection (M) +#define hb_mutex_impl_finish(M) DeleteCriticalSection (M) + + +#elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__)) + +#include +typedef pthread_mutex_t hb_mutex_impl_t; +#define HB_MUTEX_IMPL_INIT PTHREAD_MUTEX_INITIALIZER +#define hb_mutex_impl_init(M) pthread_mutex_init (M, NULL) +#define hb_mutex_impl_lock(M) pthread_mutex_lock (M) +#define hb_mutex_impl_unlock(M) pthread_mutex_unlock (M) +#define hb_mutex_impl_finish(M) pthread_mutex_destroy (M) + + +#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES) + +#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD) +# include +# define HB_SCHED_YIELD() sched_yield () +#else +# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END +#endif + +/* This actually is not a totally awful implementation. */ +typedef volatile int hb_mutex_impl_t; +#define HB_MUTEX_IMPL_INIT 0 +#define hb_mutex_impl_init(M) *(M) = 0 +#define hb_mutex_impl_lock(M) HB_STMT_START { while (__sync_lock_test_and_set((M), 1)) HB_SCHED_YIELD (); } HB_STMT_END +#define hb_mutex_impl_unlock(M) __sync_lock_release (M) +#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END + + +#elif !defined(HB_NO_MT) + +#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD) +# include +# define HB_SCHED_YIELD() sched_yield () +#else +# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END +#endif + +#define HB_MUTEX_INT_NIL 1 /* Warn that fallback implementation is in use. */ +typedef volatile int hb_mutex_impl_t; +#define HB_MUTEX_IMPL_INIT 0 +#define hb_mutex_impl_init(M) *(M) = 0 +#define hb_mutex_impl_lock(M) HB_STMT_START { while (*(M)) HB_SCHED_YIELD (); (*(M))++; } HB_STMT_END +#define hb_mutex_impl_unlock(M) (*(M))--; +#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END + + +#else /* HB_NO_MT */ + +typedef int hb_mutex_impl_t; +#define HB_MUTEX_IMPL_INIT 0 +#define hb_mutex_impl_init(M) HB_STMT_START {} HB_STMT_END +#define hb_mutex_impl_lock(M) HB_STMT_START {} HB_STMT_END +#define hb_mutex_impl_unlock(M) HB_STMT_START {} HB_STMT_END +#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END + + +#endif + + +#define HB_MUTEX_INIT {HB_MUTEX_IMPL_INIT} + +struct hb_mutex_t +{ + /* TODO Add tracing. */ + + hb_mutex_impl_t m; + + inline void init (void) { hb_mutex_impl_init (&m); } + inline void lock (void) { hb_mutex_impl_lock (&m); } + inline void unlock (void) { hb_mutex_impl_unlock (&m); } + inline void finish (void) { hb_mutex_impl_finish (&m); } +}; + + +#endif /* HB_MUTEX_PRIVATE_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-object-private.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-object-private.hh new file mode 100644 index 00000000000..f2bb23ee7d1 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-object-private.hh @@ -0,0 +1,202 @@ +/* + * Copyright © 2007 Chris Wilson + * Copyright © 2009,2010 Red Hat, Inc. + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Contributor(s): + * Chris Wilson + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OBJECT_PRIVATE_HH +#define HB_OBJECT_PRIVATE_HH + +#include "hb-private.hh" + +#include "hb-atomic-private.hh" +#include "hb-mutex-private.hh" + + +/* Debug */ + +#ifndef HB_DEBUG_OBJECT +#define HB_DEBUG_OBJECT (HB_DEBUG+0) +#endif + + +/* reference_count */ + +#define HB_REFERENCE_COUNT_INERT_VALUE -1 +#define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD +#define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT(HB_REFERENCE_COUNT_INERT_VALUE)} + +struct hb_reference_count_t +{ + hb_atomic_int_t ref_count; + + inline void init (int v) { ref_count.set_unsafe (v); } + inline int get_unsafe (void) const { return ref_count.get_unsafe (); } + inline int inc (void) { return ref_count.inc (); } + inline int dec (void) { return ref_count.dec (); } + inline void finish (void) { ref_count.set_unsafe (HB_REFERENCE_COUNT_POISON_VALUE); } + + inline bool is_inert (void) const { return ref_count.get_unsafe () == HB_REFERENCE_COUNT_INERT_VALUE; } + inline bool is_valid (void) const { return ref_count.get_unsafe () > 0; } +}; + + +/* user_data */ + +#define HB_USER_DATA_ARRAY_INIT {HB_MUTEX_INIT, HB_LOCKABLE_SET_INIT} +struct hb_user_data_array_t +{ + struct hb_user_data_item_t { + hb_user_data_key_t *key; + void *data; + hb_destroy_func_t destroy; + + inline bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; } + inline bool operator == (hb_user_data_item_t &other) const { return key == other.key; } + + void finish (void) { if (destroy) destroy (data); } + }; + + hb_mutex_t lock; + hb_lockable_set_t items; + + inline void init (void) { lock.init (); items.init (); } + + HB_INTERNAL bool set (hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + + HB_INTERNAL void *get (hb_user_data_key_t *key); + + inline void finish (void) { items.finish (lock); lock.finish (); } +}; + + +/* object_header */ + +struct hb_object_header_t +{ + hb_reference_count_t ref_count; + hb_user_data_array_t user_data; + +#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, HB_USER_DATA_ARRAY_INIT} + + private: + ASSERT_POD (); +}; + + +/* object */ + +template +static inline void hb_object_trace (const Type *obj, const char *function) +{ + DEBUG_MSG (OBJECT, (void *) obj, + "%s refcount=%d", + function, + obj ? obj->header.ref_count.get_unsafe () : 0); +} + +template +static inline Type *hb_object_create (void) +{ + Type *obj = (Type *) calloc (1, sizeof (Type)); + + if (unlikely (!obj)) + return obj; + + hb_object_init (obj); + hb_object_trace (obj, HB_FUNC); + return obj; +} +template +static inline void hb_object_init (Type *obj) +{ + obj->header.ref_count.init (1); + obj->header.user_data.init (); +} +template +static inline bool hb_object_is_inert (const Type *obj) +{ + return unlikely (obj->header.ref_count.is_inert ()); +} +template +static inline bool hb_object_is_valid (const Type *obj) +{ + return likely (obj->header.ref_count.is_valid ()); +} +template +static inline Type *hb_object_reference (Type *obj) +{ + hb_object_trace (obj, HB_FUNC); + if (unlikely (!obj || hb_object_is_inert (obj))) + return obj; + assert (hb_object_is_valid (obj)); + obj->header.ref_count.inc (); + return obj; +} +template +static inline bool hb_object_destroy (Type *obj) +{ + hb_object_trace (obj, HB_FUNC); + if (unlikely (!obj || hb_object_is_inert (obj))) + return false; + assert (hb_object_is_valid (obj)); + if (obj->header.ref_count.dec () != 1) + return false; + + obj->header.ref_count.finish (); /* Do this before user_data */ + obj->header.user_data.finish (); + return true; +} +template +static inline bool hb_object_set_user_data (Type *obj, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + if (unlikely (!obj || hb_object_is_inert (obj))) + return false; + assert (hb_object_is_valid (obj)); + return obj->header.user_data.set (key, data, destroy, replace); +} + +template +static inline void *hb_object_get_user_data (Type *obj, + hb_user_data_key_t *key) +{ + if (unlikely (!obj || hb_object_is_inert (obj))) + return NULL; + assert (hb_object_is_valid (obj)); + return obj->header.user_data.get (key); +} + + +#endif /* HB_OBJECT_PRIVATE_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-file-private.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-file-private.hh new file mode 100644 index 00000000000..2d3b13c5236 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-file-private.hh @@ -0,0 +1,268 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OPEN_FILE_PRIVATE_HH +#define HB_OPEN_FILE_PRIVATE_HH + +#include "hb-open-type-private.hh" + + +namespace OT { + + +/* + * + * The OpenType Font File + * + */ + + +/* + * Organization of an OpenType Font + */ + +struct OpenTypeFontFile; +struct OffsetTable; +struct TTCHeader; + + +typedef struct TableRecord +{ + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + Tag tag; /* 4-byte identifier. */ + CheckSum checkSum; /* CheckSum for this table. */ + ULONG offset; /* Offset from beginning of TrueType font + * file. */ + ULONG length; /* Length of this table. */ + public: + DEFINE_SIZE_STATIC (16); +} OpenTypeTable; + +typedef struct OffsetTable +{ + friend struct OpenTypeFontFile; + + inline unsigned int get_table_count (void) const + { return numTables; } + inline const TableRecord& get_table (unsigned int i) const + { + if (unlikely (i >= numTables)) return Null(TableRecord); + return tables[i]; + } + inline bool find_table_index (hb_tag_t tag, unsigned int *table_index) const + { + Tag t; + t.set (tag); + unsigned int count = numTables; + for (unsigned int i = 0; i < count; i++) + { + if (t == tables[i].tag) + { + if (table_index) *table_index = i; + return true; + } + } + if (table_index) *table_index = Index::NOT_FOUND_INDEX; + return false; + } + inline const TableRecord& get_table_by_tag (hb_tag_t tag) const + { + unsigned int table_index; + find_table_index (tag, &table_index); + return get_table (table_index); + } + + public: + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables)); + } + + protected: + Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */ + USHORT numTables; /* Number of tables. */ + USHORT searchRangeZ; /* (Maximum power of 2 <= numTables) x 16 */ + USHORT entrySelectorZ; /* Log2(maximum power of 2 <= numTables). */ + USHORT rangeShiftZ; /* NumTables x 16-searchRange. */ + TableRecord tables[VAR]; /* TableRecord entries. numTables items */ + public: + DEFINE_SIZE_ARRAY (12, tables); +} OpenTypeFontFace; + + +/* + * TrueType Collections + */ + +struct TTCHeaderVersion1 +{ + friend struct TTCHeader; + + inline unsigned int get_face_count (void) const { return table.len; } + inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (table.sanitize (c, this)); + } + + protected: + Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ + FixedVersion version; /* Version of the TTC Header (1.0), + * 0x00010000u */ + ArrayOf, ULONG> + table; /* Array of offsets to the OffsetTable for each font + * from the beginning of the file */ + public: + DEFINE_SIZE_ARRAY (12, table); +}; + +struct TTCHeader +{ + friend struct OpenTypeFontFile; + + private: + + inline unsigned int get_face_count (void) const + { + switch (u.header.version.major) { + case 2: /* version 2 is compatible with version 1 */ + case 1: return u.version1.get_face_count (); + default:return 0; + } + } + inline const OpenTypeFontFace& get_face (unsigned int i) const + { + switch (u.header.version.major) { + case 2: /* version 2 is compatible with version 1 */ + case 1: return u.version1.get_face (i); + default:return Null(OpenTypeFontFace); + } + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!u.header.version.sanitize (c))) return_trace (false); + switch (u.header.version.major) { + case 2: /* version 2 is compatible with version 1 */ + case 1: return_trace (u.version1.sanitize (c)); + default:return_trace (true); + } + } + + protected: + union { + struct { + Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ + FixedVersion version; /* Version of the TTC Header (1.0 or 2.0), + * 0x00010000u or 0x00020000u */ + } header; + TTCHeaderVersion1 version1; + } u; +}; + + +/* + * OpenType Font File + */ + +struct OpenTypeFontFile +{ + static const hb_tag_t tableTag = HB_TAG ('_','_','_','_'); /* Sanitizer needs this. */ + + static const hb_tag_t CFFTag = HB_TAG ('O','T','T','O'); /* OpenType with Postscript outlines */ + static const hb_tag_t TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ); /* OpenType with TrueType outlines */ + static const hb_tag_t TTCTag = HB_TAG ('t','t','c','f'); /* TrueType Collection */ + static const hb_tag_t TrueTag = HB_TAG ('t','r','u','e'); /* Obsolete Apple TrueType */ + static const hb_tag_t Typ1Tag = HB_TAG ('t','y','p','1'); /* Obsolete Apple Type1 font in SFNT container */ + + inline hb_tag_t get_tag (void) const { return u.tag; } + + inline unsigned int get_face_count (void) const + { + switch (u.tag) { + case CFFTag: /* All the non-collection tags */ + case TrueTag: + case Typ1Tag: + case TrueTypeTag: return 1; + case TTCTag: return u.ttcHeader.get_face_count (); + default: return 0; + } + } + inline const OpenTypeFontFace& get_face (unsigned int i) const + { + switch (u.tag) { + /* Note: for non-collection SFNT data we ignore index. This is because + * Apple dfont container is a container of SFNT's. So each SFNT is a + * non-TTC, but the index is more than zero. */ + case CFFTag: /* All the non-collection tags */ + case TrueTag: + case Typ1Tag: + case TrueTypeTag: return u.fontFace; + case TTCTag: return u.ttcHeader.get_face (i); + default: return Null(OpenTypeFontFace); + } + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!u.tag.sanitize (c))) return_trace (false); + switch (u.tag) { + case CFFTag: /* All the non-collection tags */ + case TrueTag: + case Typ1Tag: + case TrueTypeTag: return_trace (u.fontFace.sanitize (c)); + case TTCTag: return_trace (u.ttcHeader.sanitize (c)); + default: return_trace (true); + } + } + + protected: + union { + Tag tag; /* 4-byte identifier. */ + OpenTypeFontFace fontFace; + TTCHeader ttcHeader; + } u; + public: + DEFINE_SIZE_UNION (4, tag); +}; + + +} /* namespace OT */ + + +#endif /* HB_OPEN_FILE_PRIVATE_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-type-private.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-type-private.hh new file mode 100644 index 00000000000..6b3520cf071 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-open-type-private.hh @@ -0,0 +1,1046 @@ +/* + * Copyright © 2007,2008,2009,2010 Red Hat, Inc. + * Copyright © 2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OPEN_TYPE_PRIVATE_HH +#define HB_OPEN_TYPE_PRIVATE_HH + +#include "hb-private.hh" + + +namespace OT { + + + +/* + * Casts + */ + +/* Cast to struct T, reference to reference */ +template +static inline const Type& CastR(const TObject &X) +{ return reinterpret_cast (X); } +template +static inline Type& CastR(TObject &X) +{ return reinterpret_cast (X); } + +/* Cast to struct T, pointer to pointer */ +template +static inline const Type* CastP(const TObject *X) +{ return reinterpret_cast (X); } +template +static inline Type* CastP(TObject *X) +{ return reinterpret_cast (X); } + +/* StructAtOffset(P,Ofs) returns the struct T& that is placed at memory + * location pointed to by P plus Ofs bytes. */ +template +static inline const Type& StructAtOffset(const void *P, unsigned int offset) +{ return * reinterpret_cast ((const char *) P + offset); } +template +static inline Type& StructAtOffset(void *P, unsigned int offset) +{ return * reinterpret_cast ((char *) P + offset); } + +/* StructAfter(X) returns the struct T& that is placed after X. + * Works with X of variable size also. X must implement get_size() */ +template +static inline const Type& StructAfter(const TObject &X) +{ return StructAtOffset(&X, X.get_size()); } +template +static inline Type& StructAfter(TObject &X) +{ return StructAtOffset(&X, X.get_size()); } + + + +/* + * Size checking + */ + +/* Check _assertion in a method environment */ +#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \ + inline void _instance_assertion_on_line_##_line (void) const \ + { \ + ASSERT_STATIC (_assertion); \ + ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \ + } +# define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion) +# define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion) + +/* Check that _code compiles in a method environment */ +#define _DEFINE_COMPILES_ASSERTION1(_line, _code) \ + inline void _compiles_assertion_on_line_##_line (void) const \ + { _code; } +# define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code) +# define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code) + + +#define DEFINE_SIZE_STATIC(size) \ + DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \ + static const unsigned int static_size = (size); \ + static const unsigned int min_size = (size) + +/* Size signifying variable-sized array */ +#define VAR 1 + +#define DEFINE_SIZE_UNION(size, _member) \ + DEFINE_INSTANCE_ASSERTION (this->u._member.static_size == (size)); \ + static const unsigned int min_size = (size) + +#define DEFINE_SIZE_MIN(size) \ + DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)); \ + static const unsigned int min_size = (size) + +#define DEFINE_SIZE_ARRAY(size, array) \ + DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \ + DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \ + static const unsigned int min_size = (size) + +#define DEFINE_SIZE_ARRAY2(size, array1, array2) \ + DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \ + DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \ + static const unsigned int min_size = (size) + + + +/* + * Null objects + */ + +/* Global nul-content Null pool. Enlarge as necessary. */ +/* TODO This really should be a extern HB_INTERNAL and defined somewhere... */ +static const void *_NullPool[(256+8) / sizeof (void *)]; + +/* Generic nul-content Null objects. */ +template +static inline const Type& Null (void) { + ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool)); + return *CastP (_NullPool); +} + +/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */ +#define DEFINE_NULL_DATA(Type, data) \ +static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \ +template <> \ +/*static*/ inline const Type& Null (void) { \ + return *CastP (_Null##Type); \ +} /* The following line really exists such that we end in a place needing semicolon */ \ +ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type)) + +/* Accessor macro. */ +#define Null(Type) Null() + + +/* + * Dispatch + */ + +template +struct hb_dispatch_context_t +{ + static const unsigned int max_debug_depth = MaxDebugDepth; + typedef Return return_t; + template + inline bool may_dispatch (const T *obj, const F *format) { return true; } + static return_t no_dispatch_return_value (void) { return Context::default_return_value (); } +}; + + +/* + * Sanitize + */ + +#ifndef HB_DEBUG_SANITIZE +#define HB_DEBUG_SANITIZE (HB_DEBUG+0) +#endif + + +#define TRACE_SANITIZE(this) \ + hb_auto_trace_t trace \ + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ + ""); + +/* This limits sanitizing time on really broken fonts. */ +#ifndef HB_SANITIZE_MAX_EDITS +#define HB_SANITIZE_MAX_EDITS 100 +#endif + +struct hb_sanitize_context_t : + hb_dispatch_context_t +{ + inline hb_sanitize_context_t (void) : + debug_depth (0), + start (NULL), end (NULL), + writable (false), edit_count (0), + blob (NULL) {} + + inline const char *get_name (void) { return "SANITIZE"; } + template + inline bool may_dispatch (const T *obj, const F *format) + { return format->sanitize (this); } + template + inline return_t dispatch (const T &obj) { return obj.sanitize (this); } + static return_t default_return_value (void) { return true; } + static return_t no_dispatch_return_value (void) { return false; } + bool stop_sublookup_iteration (const return_t r) const { return !r; } + + inline void init (hb_blob_t *b) + { + this->blob = hb_blob_reference (b); + this->writable = false; + } + + inline void start_processing (void) + { + this->start = hb_blob_get_data (this->blob, NULL); + this->end = this->start + hb_blob_get_length (this->blob); + assert (this->start <= this->end); /* Must not overflow. */ + this->edit_count = 0; + this->debug_depth = 0; + + DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1, + "start [%p..%p] (%lu bytes)", + this->start, this->end, + (unsigned long) (this->end - this->start)); + } + + inline void end_processing (void) + { + DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1, + "end [%p..%p] %u edit requests", + this->start, this->end, this->edit_count); + + hb_blob_destroy (this->blob); + this->blob = NULL; + this->start = this->end = NULL; + } + + inline bool check_range (const void *base, unsigned int len) const + { + const char *p = (const char *) base; + bool ok = this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len; + + DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, + "check_range [%p..%p] (%d bytes) in [%p..%p] -> %s", + p, p + len, len, + this->start, this->end, + ok ? "OK" : "OUT-OF-RANGE"); + + return likely (ok); + } + + inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const + { + const char *p = (const char *) base; + bool overflows = _hb_unsigned_int_mul_overflows (len, record_size); + unsigned int array_size = record_size * len; + bool ok = !overflows && this->check_range (base, array_size); + + DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, + "check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s", + p, p + (record_size * len), record_size, len, (unsigned int) array_size, + this->start, this->end, + overflows ? "OVERFLOWS" : ok ? "OK" : "OUT-OF-RANGE"); + + return likely (ok); + } + + template + inline bool check_struct (const Type *obj) const + { + return likely (this->check_range (obj, obj->min_size)); + } + + inline bool may_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED) + { + if (this->edit_count >= HB_SANITIZE_MAX_EDITS) + return false; + + const char *p = (const char *) base; + this->edit_count++; + + DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, + "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s", + this->edit_count, + p, p + len, len, + this->start, this->end, + this->writable ? "GRANTED" : "DENIED"); + + return this->writable; + } + + template + inline bool try_set (const Type *obj, const ValueType &v) { + if (this->may_edit (obj, obj->static_size)) { + const_cast (obj)->set (v); + return true; + } + return false; + } + + mutable unsigned int debug_depth; + const char *start, *end; + bool writable; + unsigned int edit_count; + hb_blob_t *blob; +}; + + + +/* Template to sanitize an object. */ +template +struct Sanitizer +{ + static hb_blob_t *sanitize (hb_blob_t *blob) { + hb_sanitize_context_t c[1]; + bool sane; + + /* TODO is_sane() stuff */ + + c->init (blob); + + retry: + DEBUG_MSG_FUNC (SANITIZE, c->start, "start"); + + c->start_processing (); + + if (unlikely (!c->start)) { + c->end_processing (); + return blob; + } + + Type *t = CastP (const_cast (c->start)); + + sane = t->sanitize (c); + if (sane) { + if (c->edit_count) { + DEBUG_MSG_FUNC (SANITIZE, c->start, "passed first round with %d edits; going for second round", c->edit_count); + + /* sanitize again to ensure no toe-stepping */ + c->edit_count = 0; + sane = t->sanitize (c); + if (c->edit_count) { + DEBUG_MSG_FUNC (SANITIZE, c->start, "requested %d edits in second round; FAILLING", c->edit_count); + sane = false; + } + } + } else { + unsigned int edit_count = c->edit_count; + if (edit_count && !c->writable) { + c->start = hb_blob_get_data_writable (blob, NULL); + c->end = c->start + hb_blob_get_length (blob); + + if (c->start) { + c->writable = true; + /* ok, we made it writable by relocating. try again */ + DEBUG_MSG_FUNC (SANITIZE, c->start, "retry"); + goto retry; + } + } + } + + c->end_processing (); + + DEBUG_MSG_FUNC (SANITIZE, c->start, sane ? "PASSED" : "FAILED"); + if (sane) + return blob; + else { + hb_blob_destroy (blob); + return hb_blob_get_empty (); + } + } + + static const Type* lock_instance (hb_blob_t *blob) { + hb_blob_make_immutable (blob); + const char *base = hb_blob_get_data (blob, NULL); + return unlikely (!base) ? &Null(Type) : CastP (base); + } +}; + + + +/* + * Serialize + */ + +#ifndef HB_DEBUG_SERIALIZE +#define HB_DEBUG_SERIALIZE (HB_DEBUG+0) +#endif + + +#define TRACE_SERIALIZE(this) \ + hb_auto_trace_t trace \ + (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \ + ""); + + +struct hb_serialize_context_t +{ + inline hb_serialize_context_t (void *start, unsigned int size) + { + this->start = (char *) start; + this->end = this->start + size; + + this->ran_out_of_room = false; + this->head = this->start; + this->debug_depth = 0; + } + + template + inline Type *start_serialize (void) + { + DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1, + "start [%p..%p] (%lu bytes)", + this->start, this->end, + (unsigned long) (this->end - this->start)); + + return start_embed (); + } + + inline void end_serialize (void) + { + DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1, + "end [%p..%p] serialized %d bytes; %s", + this->start, this->end, + (int) (this->head - this->start), + this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room"); + + } + + template + inline Type *copy (void) + { + assert (!this->ran_out_of_room); + unsigned int len = this->head - this->start; + void *p = malloc (len); + if (p) + memcpy (p, this->start, len); + return reinterpret_cast (p); + } + + template + inline Type *allocate_size (unsigned int size) + { + if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) { + this->ran_out_of_room = true; + return NULL; + } + memset (this->head, 0, size); + char *ret = this->head; + this->head += size; + return reinterpret_cast (ret); + } + + template + inline Type *allocate_min (void) + { + return this->allocate_size (Type::min_size); + } + + template + inline Type *start_embed (void) + { + Type *ret = reinterpret_cast (this->head); + return ret; + } + + template + inline Type *embed (const Type &obj) + { + unsigned int size = obj.get_size (); + Type *ret = this->allocate_size (size); + if (unlikely (!ret)) return NULL; + memcpy (ret, obj, size); + return ret; + } + + template + inline Type *extend_min (Type &obj) + { + unsigned int size = obj.min_size; + assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head); + if (unlikely (!this->allocate_size (((char *) &obj) + size - this->head))) return NULL; + return reinterpret_cast (&obj); + } + + template + inline Type *extend (Type &obj) + { + unsigned int size = obj.get_size (); + assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head); + if (unlikely (!this->allocate_size (((char *) &obj) + size - this->head))) return NULL; + return reinterpret_cast (&obj); + } + + inline void truncate (void *head) + { + assert (this->start < head && head <= this->head); + this->head = (char *) head; + } + + unsigned int debug_depth; + char *start, *end, *head; + bool ran_out_of_room; +}; + +template +struct Supplier +{ + inline Supplier (const Type *array, unsigned int len_) + { + head = array; + len = len_; + } + inline const Type operator [] (unsigned int i) const + { + if (unlikely (i >= len)) return Type (); + return head[i]; + } + + inline void advance (unsigned int count) + { + if (unlikely (count > len)) + count = len; + len -= count; + head += count; + } + + private: + inline Supplier (const Supplier &); /* Disallow copy */ + inline Supplier& operator= (const Supplier &); /* Disallow copy */ + + unsigned int len; + const Type *head; +}; + + + + +/* + * + * The OpenType Font File: Data Types + */ + + +/* "The following data types are used in the OpenType font file. + * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */ + +/* + * Int types + */ + + +template struct BEInt; + +template +struct BEInt +{ + public: + inline void set (Type V) + { + v = V; + } + inline operator Type (void) const + { + return v; + } + private: uint8_t v; +}; +template +struct BEInt +{ + public: + inline void set (Type V) + { + v[0] = (V >> 8) & 0xFF; + v[1] = (V ) & 0xFF; + } + inline operator Type (void) const + { + return (v[0] << 8) + + (v[1] ); + } + private: uint8_t v[2]; +}; +template +struct BEInt +{ + public: + inline void set (Type V) + { + v[0] = (V >> 16) & 0xFF; + v[1] = (V >> 8) & 0xFF; + v[2] = (V ) & 0xFF; + } + inline operator Type (void) const + { + return (v[0] << 16) + + (v[1] << 8) + + (v[2] ); + } + private: uint8_t v[3]; +}; +template +struct BEInt +{ + public: + inline void set (Type V) + { + v[0] = (V >> 24) & 0xFF; + v[1] = (V >> 16) & 0xFF; + v[2] = (V >> 8) & 0xFF; + v[3] = (V ) & 0xFF; + } + inline operator Type (void) const + { + return (v[0] << 24) + + (v[1] << 16) + + (v[2] << 8) + + (v[3] ); + } + private: uint8_t v[4]; +}; + +/* Integer types in big-endian order and no alignment requirement */ +template +struct IntType +{ + inline void set (Type i) { v.set (i); } + inline operator Type(void) const { return v; } + inline bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; } + inline bool operator != (const IntType &o) const { return !(*this == o); } + static inline int cmp (const IntType *a, const IntType *b) { return b->cmp (*a); } + inline int cmp (Type a) const + { + Type b = v; + if (sizeof (Type) < sizeof (int)) + return (int) a - (int) b; + else + return a < b ? -1 : a == b ? 0 : +1; + } + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + protected: + BEInt v; + public: + DEFINE_SIZE_STATIC (Size); +}; + +typedef IntType BYTE; /* 8-bit unsigned integer. */ +typedef IntType USHORT; /* 16-bit unsigned integer. */ +typedef IntType SHORT; /* 16-bit signed integer. */ +typedef IntType ULONG; /* 32-bit unsigned integer. */ +typedef IntType LONG; /* 32-bit signed integer. */ +typedef IntType UINT24; /* 24-bit unsigned integer. */ + +/* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */ +typedef SHORT FWORD; + +/* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */ +typedef USHORT UFWORD; + +/* Date represented in number of seconds since 12:00 midnight, January 1, + * 1904. The value is represented as a signed 64-bit integer. */ +struct LONGDATETIME +{ + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + protected: + LONG major; + ULONG minor; + public: + DEFINE_SIZE_STATIC (8); +}; + +/* Array of four uint8s (length = 32 bits) used to identify a script, language + * system, feature, or baseline */ +struct Tag : ULONG +{ + /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ + inline operator const char* (void) const { return reinterpret_cast (&this->v); } + inline operator char* (void) { return reinterpret_cast (&this->v); } + public: + DEFINE_SIZE_STATIC (4); +}; +DEFINE_NULL_DATA (Tag, " "); + +/* Glyph index number, same as uint16 (length = 16 bits) */ +struct GlyphID : USHORT { + static inline int cmp (const GlyphID *a, const GlyphID *b) { return b->USHORT::cmp (*a); } + inline int cmp (hb_codepoint_t a) const { return (int) a - (int) *this; } +}; + +/* Script/language-system/feature index */ +struct Index : USHORT { + static const unsigned int NOT_FOUND_INDEX = 0xFFFFu; +}; +DEFINE_NULL_DATA (Index, "\xff\xff"); + +/* Offset, Null offset = 0 */ +template +struct Offset : Type +{ + inline bool is_null (void) const { return 0 == *this; } + public: + DEFINE_SIZE_STATIC (sizeof(Type)); +}; + + +/* CheckSum */ +struct CheckSum : ULONG +{ + /* This is reference implementation from the spec. */ + static inline uint32_t CalcTableChecksum (const ULONG *Table, uint32_t Length) + { + uint32_t Sum = 0L; + const ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size; + + while (Table < EndPtr) + Sum += *Table++; + return Sum; + } + + /* Note: data should be 4byte aligned and have 4byte padding at the end. */ + inline void set_for_data (const void *data, unsigned int length) + { set (CalcTableChecksum ((const ULONG *) data, length)); } + + public: + DEFINE_SIZE_STATIC (4); +}; + + +/* + * Version Numbers + */ + +struct FixedVersion +{ + inline uint32_t to_int (void) const { return (major << 16) + minor; } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + USHORT major; + USHORT minor; + public: + DEFINE_SIZE_STATIC (4); +}; + + + +/* + * Template subclasses of Offset that do the dereferencing. + * Use: (base+offset) + */ + +template +struct OffsetTo : Offset +{ + inline const Type& operator () (const void *base) const + { + unsigned int offset = *this; + if (unlikely (!offset)) return Null(Type); + return StructAtOffset (base, offset); + } + + inline Type& serialize (hb_serialize_context_t *c, const void *base) + { + Type *t = c->start_embed (); + this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */ + return *t; + } + + inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) return_trace (false); + unsigned int offset = *this; + if (unlikely (!offset)) return_trace (true); + const Type &obj = StructAtOffset (base, offset); + return_trace (likely (obj.sanitize (c)) || neuter (c)); + } + template + inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) return_trace (false); + unsigned int offset = *this; + if (unlikely (!offset)) return_trace (true); + const Type &obj = StructAtOffset (base, offset); + return_trace (likely (obj.sanitize (c, user_data)) || neuter (c)); + } + + /* Set the offset to Null */ + inline bool neuter (hb_sanitize_context_t *c) const { + return c->try_set (this, 0); + } + DEFINE_SIZE_STATIC (sizeof(OffsetType)); +}; +template +static inline const Type& operator + (const Base &base, const OffsetTo &offset) { return offset (base); } +template +static inline Type& operator + (Base &base, OffsetTo &offset) { return offset (base); } + + +/* + * Array Types + */ + +/* An array with a number of elements. */ +template +struct ArrayOf +{ + const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const + { + unsigned int count = len; + if (unlikely (start_offset > count)) + count = 0; + else + count -= start_offset; + count = MIN (count, *pcount); + *pcount = count; + return array + start_offset; + } + + inline const Type& operator [] (unsigned int i) const + { + if (unlikely (i >= len)) return Null(Type); + return array[i]; + } + inline Type& operator [] (unsigned int i) + { + return array[i]; + } + inline unsigned int get_size (void) const + { return len.static_size + len * Type::static_size; } + + inline bool serialize (hb_serialize_context_t *c, + unsigned int items_len) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + len.set (items_len); /* TODO(serialize) Overflow? */ + if (unlikely (!c->extend (*this))) return_trace (false); + return_trace (true); + } + + inline bool serialize (hb_serialize_context_t *c, + Supplier &items, + unsigned int items_len) + { + TRACE_SERIALIZE (this); + if (unlikely (!serialize (c, items_len))) return_trace (false); + for (unsigned int i = 0; i < items_len; i++) + array[i] = items[i]; + items.advance (items_len); + return_trace (true); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c))) return_trace (false); + + /* Note: for structs that do not reference other structs, + * we do not need to call their sanitize() as we already did + * a bound check on the aggregate array size. We just include + * a small unreachable expression to make sure the structs + * pointed to do have a simple sanitize(), ie. they do not + * reference other structs via offsets. + */ + (void) (false && array[0].sanitize (c)); + + return_trace (true); + } + inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c))) return_trace (false); + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + if (unlikely (!array[i].sanitize (c, base))) + return_trace (false); + return_trace (true); + } + template + inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c))) return_trace (false); + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + if (unlikely (!array[i].sanitize (c, base, user_data))) + return_trace (false); + return_trace (true); + } + + template + inline int lsearch (const SearchType &x) const + { + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + if (!this->array[i].cmp (x)) + return i; + return -1; + } + + private: + inline bool sanitize_shallow (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && c->check_array (array, Type::static_size, len)); + } + + public: + LenType len; + Type array[VAR]; + public: + DEFINE_SIZE_ARRAY (sizeof (LenType), array); +}; + +/* Array of Offset's */ +template +struct OffsetArrayOf : ArrayOf > {}; + +/* Array of offsets relative to the beginning of the array itself. */ +template +struct OffsetListOf : OffsetArrayOf +{ + inline const Type& operator [] (unsigned int i) const + { + if (unlikely (i >= this->len)) return Null(Type); + return this+this->array[i]; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (OffsetArrayOf::sanitize (c, this)); + } + template + inline bool sanitize (hb_sanitize_context_t *c, T user_data) const + { + TRACE_SANITIZE (this); + return_trace (OffsetArrayOf::sanitize (c, this, user_data)); + } +}; + + +/* An array starting at second element. */ +template +struct HeadlessArrayOf +{ + inline const Type& operator [] (unsigned int i) const + { + if (unlikely (i >= len || !i)) return Null(Type); + return array[i-1]; + } + inline unsigned int get_size (void) const + { return len.static_size + (len ? len - 1 : 0) * Type::static_size; } + + inline bool serialize (hb_serialize_context_t *c, + Supplier &items, + unsigned int items_len) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + len.set (items_len); /* TODO(serialize) Overflow? */ + if (unlikely (!items_len)) return_trace (true); + if (unlikely (!c->extend (*this))) return_trace (false); + for (unsigned int i = 0; i < items_len - 1; i++) + array[i] = items[i]; + items.advance (items_len - 1); + return_trace (true); + } + + inline bool sanitize_shallow (hb_sanitize_context_t *c) const + { + return c->check_struct (this) + && c->check_array (this, Type::static_size, len); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!sanitize_shallow (c))) return_trace (false); + + /* Note: for structs that do not reference other structs, + * we do not need to call their sanitize() as we already did + * a bound check on the aggregate array size. We just include + * a small unreachable expression to make sure the structs + * pointed to do have a simple sanitize(), ie. they do not + * reference other structs via offsets. + */ + (void) (false && array[0].sanitize (c)); + + return_trace (true); + } + + LenType len; + Type array[VAR]; + public: + DEFINE_SIZE_ARRAY (sizeof (LenType), array); +}; + + +/* An array with sorted elements. Supports binary searching. */ +template +struct SortedArrayOf : ArrayOf +{ + template + inline int bsearch (const SearchType &x) const + { + /* Hand-coded bsearch here since this is in the hot inner loop. */ + int min = 0, max = (int) this->len - 1; + while (min <= max) + { + int mid = (min + max) / 2; + int c = this->array[mid].cmp (x); + if (c < 0) + max = mid - 1; + else if (c > 0) + min = mid + 1; + else + return mid; + } + return -1; + } +}; + + +} /* namespace OT */ + + +#endif /* HB_OPEN_TYPE_PRIVATE_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-cmap-table.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-cmap-table.hh new file mode 100644 index 00000000000..b0e2f36a436 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-cmap-table.hh @@ -0,0 +1,528 @@ +/* + * Copyright © 2014 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_CMAP_TABLE_HH +#define HB_OT_CMAP_TABLE_HH + +#include "hb-open-type-private.hh" + + +namespace OT { + + +/* + * cmap -- Character To Glyph Index Mapping Table + */ + +#define HB_OT_TAG_cmap HB_TAG('c','m','a','p') + + +struct CmapSubtableFormat0 +{ + inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const + { + hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0; + if (!gid) + return false; + *glyph = gid; + return true; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + protected: + USHORT format; /* Format number is set to 0. */ + USHORT lengthZ; /* Byte length of this subtable. */ + USHORT languageZ; /* Ignore. */ + BYTE glyphIdArray[256];/* An array that maps character + * code to glyph index values. */ + public: + DEFINE_SIZE_STATIC (6 + 256); +}; + +struct CmapSubtableFormat4 +{ + inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const + { + unsigned int segCount; + const USHORT *endCount; + const USHORT *startCount; + const USHORT *idDelta; + const USHORT *idRangeOffset; + const USHORT *glyphIdArray; + unsigned int glyphIdArrayLength; + + segCount = this->segCountX2 / 2; + endCount = this->values; + startCount = endCount + segCount + 1; + idDelta = startCount + segCount; + idRangeOffset = idDelta + segCount; + glyphIdArray = idRangeOffset + segCount; + glyphIdArrayLength = (this->length - 16 - 8 * segCount) / 2; + + /* Custom two-array bsearch. */ + int min = 0, max = (int) segCount - 1; + unsigned int i; + while (min <= max) + { + int mid = (min + max) / 2; + if (codepoint < startCount[mid]) + max = mid - 1; + else if (codepoint > endCount[mid]) + min = mid + 1; + else + { + i = mid; + goto found; + } + } + return false; + + found: + hb_codepoint_t gid; + unsigned int rangeOffset = idRangeOffset[i]; + if (rangeOffset == 0) + gid = codepoint + idDelta[i]; + else + { + /* Somebody has been smoking... */ + unsigned int index = rangeOffset / 2 + (codepoint - startCount[i]) + i - segCount; + if (unlikely (index >= glyphIdArrayLength)) + return false; + gid = glyphIdArray[index]; + if (unlikely (!gid)) + return false; + gid += idDelta[i]; + } + + *glyph = gid & 0xFFFFu; + return true; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) + return_trace (false); + + if (unlikely (!c->check_range (this, length))) + { + /* Some broken fonts have too long of a "length" value. + * If that is the case, just change the value to truncate + * the subtable at the end of the blob. */ + uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535, + (uintptr_t) (c->end - + (char *) this)); + if (!c->try_set (&length, new_length)) + return_trace (false); + } + + return_trace (16 + 4 * (unsigned int) segCountX2 <= length); + } + + protected: + USHORT format; /* Format number is set to 4. */ + USHORT length; /* This is the length in bytes of the + * subtable. */ + USHORT languageZ; /* Ignore. */ + USHORT segCountX2; /* 2 x segCount. */ + USHORT searchRangeZ; /* 2 * (2**floor(log2(segCount))) */ + USHORT entrySelectorZ; /* log2(searchRange/2) */ + USHORT rangeShiftZ; /* 2 x segCount - searchRange */ + + USHORT values[VAR]; +#if 0 + USHORT endCount[segCount]; /* End characterCode for each segment, + * last=0xFFFFu. */ + USHORT reservedPad; /* Set to 0. */ + USHORT startCount[segCount]; /* Start character code for each segment. */ + SHORT idDelta[segCount]; /* Delta for all character codes in segment. */ + USHORT idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */ + USHORT glyphIdArray[VAR]; /* Glyph index array (arbitrary length) */ +#endif + + public: + DEFINE_SIZE_ARRAY (14, values); +}; + +struct CmapSubtableLongGroup +{ + friend struct CmapSubtableFormat12; + friend struct CmapSubtableFormat13; + + int cmp (hb_codepoint_t codepoint) const + { + if (codepoint < startCharCode) return -1; + if (codepoint > endCharCode) return +1; + return 0; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + private: + ULONG startCharCode; /* First character code in this group. */ + ULONG endCharCode; /* Last character code in this group. */ + ULONG glyphID; /* Glyph index; interpretation depends on + * subtable format. */ + public: + DEFINE_SIZE_STATIC (12); +}; + +template +struct CmapSubtableTrimmed +{ + inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const + { + /* Rely on our implicit array bound-checking. */ + hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode]; + if (!gid) + return false; + *glyph = gid; + return true; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && glyphIdArray.sanitize (c)); + } + + protected: + UINT formatReserved; /* Subtable format and (maybe) padding. */ + UINT lengthZ; /* Byte length of this subtable. */ + UINT languageZ; /* Ignore. */ + UINT startCharCode; /* First character code covered. */ + ArrayOf + glyphIdArray; /* Array of glyph index values for character + * codes in the range. */ + public: + DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray); +}; + +struct CmapSubtableFormat6 : CmapSubtableTrimmed {}; +struct CmapSubtableFormat10 : CmapSubtableTrimmed {}; + +template +struct CmapSubtableLongSegmented +{ + inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const + { + int i = groups.bsearch (codepoint); + if (i == -1) + return false; + *glyph = T::group_get_glyph (groups[i], codepoint); + return true; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && groups.sanitize (c)); + } + + protected: + USHORT format; /* Subtable format; set to 12. */ + USHORT reservedZ; /* Reserved; set to 0. */ + ULONG lengthZ; /* Byte length of this subtable. */ + ULONG languageZ; /* Ignore. */ + SortedArrayOf + groups; /* Groupings. */ + public: + DEFINE_SIZE_ARRAY (16, groups); +}; + +struct CmapSubtableFormat12 : CmapSubtableLongSegmented +{ + static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, + hb_codepoint_t u) + { return group.glyphID + (u - group.startCharCode); } +}; + +struct CmapSubtableFormat13 : CmapSubtableLongSegmented +{ + static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, + hb_codepoint_t u HB_UNUSED) + { return group.glyphID; } +}; + +typedef enum +{ + GLYPH_VARIANT_NOT_FOUND = 0, + GLYPH_VARIANT_FOUND = 1, + GLYPH_VARIANT_USE_DEFAULT = 2 +} glyph_variant_t; + +struct UnicodeValueRange +{ + inline int cmp (const hb_codepoint_t &codepoint) const + { + if (codepoint < startUnicodeValue) return -1; + if (codepoint > startUnicodeValue + additionalCount) return +1; + return 0; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + UINT24 startUnicodeValue; /* First value in this range. */ + BYTE additionalCount; /* Number of additional values in this + * range. */ + public: + DEFINE_SIZE_STATIC (4); +}; + +typedef SortedArrayOf DefaultUVS; + +struct UVSMapping +{ + inline int cmp (const hb_codepoint_t &codepoint) const + { + return unicodeValue.cmp (codepoint); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + UINT24 unicodeValue; /* Base Unicode value of the UVS */ + GlyphID glyphID; /* Glyph ID of the UVS */ + public: + DEFINE_SIZE_STATIC (5); +}; + +typedef SortedArrayOf NonDefaultUVS; + +struct VariationSelectorRecord +{ + inline glyph_variant_t get_glyph (hb_codepoint_t codepoint, + hb_codepoint_t *glyph, + const void *base) const + { + int i; + const DefaultUVS &defaults = base+defaultUVS; + i = defaults.bsearch (codepoint); + if (i != -1) + return GLYPH_VARIANT_USE_DEFAULT; + const NonDefaultUVS &nonDefaults = base+nonDefaultUVS; + i = nonDefaults.bsearch (codepoint); + if (i != -1) + { + *glyph = nonDefaults[i].glyphID; + return GLYPH_VARIANT_FOUND; + } + return GLYPH_VARIANT_NOT_FOUND; + } + + inline int cmp (const hb_codepoint_t &variation_selector) const + { + return varSelector.cmp (variation_selector); + } + + inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + defaultUVS.sanitize (c, base) && + nonDefaultUVS.sanitize (c, base)); + } + + UINT24 varSelector; /* Variation selector. */ + OffsetTo + defaultUVS; /* Offset to Default UVS Table. May be 0. */ + OffsetTo + nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */ + public: + DEFINE_SIZE_STATIC (11); +}; + +struct CmapSubtableFormat14 +{ + inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph) const + { + return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + record.sanitize (c, this)); + } + + protected: + USHORT format; /* Format number is set to 0. */ + ULONG lengthZ; /* Byte length of this subtable. */ + SortedArrayOf + record; /* Variation selector records; sorted + * in increasing order of `varSelector'. */ + public: + DEFINE_SIZE_ARRAY (10, record); +}; + +struct CmapSubtable +{ + /* Note: We intentionally do NOT implement subtable formats 2 and 8. */ + + inline bool get_glyph (hb_codepoint_t codepoint, + hb_codepoint_t *glyph) const + { + switch (u.format) { + case 0: return u.format0 .get_glyph(codepoint, glyph); + case 4: return u.format4 .get_glyph(codepoint, glyph); + case 6: return u.format6 .get_glyph(codepoint, glyph); + case 10: return u.format10.get_glyph(codepoint, glyph); + case 12: return u.format12.get_glyph(codepoint, glyph); + case 13: return u.format13.get_glyph(codepoint, glyph); + case 14: + default: return false; + } + } + + inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph) const + { + switch (u.format) { + case 14: return u.format14.get_glyph_variant(codepoint, variation_selector, glyph); + default: return GLYPH_VARIANT_NOT_FOUND; + } + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!u.format.sanitize (c)) return_trace (false); + switch (u.format) { + case 0: return_trace (u.format0 .sanitize (c)); + case 4: return_trace (u.format4 .sanitize (c)); + case 6: return_trace (u.format6 .sanitize (c)); + case 10: return_trace (u.format10.sanitize (c)); + case 12: return_trace (u.format12.sanitize (c)); + case 13: return_trace (u.format13.sanitize (c)); + case 14: return_trace (u.format14.sanitize (c)); + default:return_trace (true); + } + } + + protected: + union { + USHORT format; /* Format identifier */ + CmapSubtableFormat0 format0; + CmapSubtableFormat4 format4; + CmapSubtableFormat6 format6; + CmapSubtableFormat10 format10; + CmapSubtableFormat12 format12; + CmapSubtableFormat13 format13; + CmapSubtableFormat14 format14; + } u; + public: + DEFINE_SIZE_UNION (2, format); +}; + + +struct EncodingRecord +{ + inline int cmp (const EncodingRecord &other) const + { + int ret; + ret = platformID.cmp (other.platformID); + if (ret) return ret; + ret = encodingID.cmp (other.encodingID); + if (ret) return ret; + return 0; + } + + inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + subtable.sanitize (c, base)); + } + + USHORT platformID; /* Platform ID. */ + USHORT encodingID; /* Platform-specific encoding ID. */ + OffsetTo + subtable; /* Byte offset from beginning of table to the subtable for this encoding. */ + public: + DEFINE_SIZE_STATIC (8); +}; + +struct cmap +{ + static const hb_tag_t tableTag = HB_OT_TAG_cmap; + + inline const CmapSubtable *find_subtable (unsigned int platform_id, + unsigned int encoding_id) const + { + EncodingRecord key; + key.platformID.set (platform_id); + key.encodingID.set (encoding_id); + + /* Note: We can use bsearch, but since it has no performance + * implications, we use lsearch and as such accept fonts with + * unsorted subtable list. */ + int result = encodingRecord./*bsearch*/lsearch (key); + if (result == -1 || !encodingRecord[result].subtable) + return NULL; + + return &(this+encodingRecord[result].subtable); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + likely (version == 0) && + encodingRecord.sanitize (c, this)); + } + + USHORT version; /* Table version number (0). */ + SortedArrayOf + encodingRecord; /* Encoding tables. */ + public: + DEFINE_SIZE_ARRAY (4, encodingRecord); +}; + + +} /* namespace OT */ + + +#endif /* HB_OT_CMAP_TABLE_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-font.cc b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-font.cc new file mode 100644 index 00000000000..836c3bf0e85 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-font.cc @@ -0,0 +1,434 @@ +/* + * Copyright © 2011,2014 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod, Roozbeh Pournader + */ + +#include "hb-private.hh" + +#include "hb-ot.h" + +#include "hb-font-private.hh" + +#include "hb-ot-cmap-table.hh" +#include "hb-ot-glyf-table.hh" +#include "hb-ot-head-table.hh" +#include "hb-ot-hhea-table.hh" +#include "hb-ot-hmtx-table.hh" + + +struct hb_ot_face_metrics_accelerator_t +{ + unsigned int num_metrics; + unsigned int num_advances; + unsigned int default_advance; + const OT::_mtx *table; + hb_blob_t *blob; + + inline void init (hb_face_t *face, + hb_tag_t _hea_tag, hb_tag_t _mtx_tag, + unsigned int default_advance_) + { + this->default_advance = default_advance_; + this->num_metrics = face->get_num_glyphs (); + + hb_blob_t *_hea_blob = OT::Sanitizer::sanitize (face->reference_table (_hea_tag)); + const OT::_hea *_hea = OT::Sanitizer::lock_instance (_hea_blob); + this->num_advances = _hea->numberOfLongMetrics; + hb_blob_destroy (_hea_blob); + + this->blob = OT::Sanitizer::sanitize (face->reference_table (_mtx_tag)); + if (unlikely (!this->num_advances || + 2 * (this->num_advances + this->num_metrics) > hb_blob_get_length (this->blob))) + { + this->num_metrics = this->num_advances = 0; + hb_blob_destroy (this->blob); + this->blob = hb_blob_get_empty (); + } + this->table = OT::Sanitizer::lock_instance (this->blob); + } + + inline void fini (void) + { + hb_blob_destroy (this->blob); + } + + inline unsigned int get_advance (hb_codepoint_t glyph) const + { + if (unlikely (glyph >= this->num_metrics)) + { + /* If this->num_metrics is zero, it means we don't have the metrics table + * for this direction: return default advance. Otherwise, it means that the + * glyph index is out of bound: return zero. */ + if (this->num_metrics) + return 0; + else + return this->default_advance; + } + + if (glyph >= this->num_advances) + glyph = this->num_advances - 1; + + return this->table->longMetric[glyph].advance; + } +}; + +struct hb_ot_face_glyf_accelerator_t +{ + bool short_offset; + unsigned int num_glyphs; + const OT::loca *loca; + const OT::glyf *glyf; + hb_blob_t *loca_blob; + hb_blob_t *glyf_blob; + unsigned int glyf_len; + + inline void init (hb_face_t *face) + { + hb_blob_t *head_blob = OT::Sanitizer::sanitize (face->reference_table (HB_OT_TAG_head)); + const OT::head *head = OT::Sanitizer::lock_instance (head_blob); + if ((unsigned int) head->indexToLocFormat > 1 || head->glyphDataFormat != 0) + { + /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ + hb_blob_destroy (head_blob); + return; + } + this->short_offset = 0 == head->indexToLocFormat; + hb_blob_destroy (head_blob); + + this->loca_blob = OT::Sanitizer::sanitize (face->reference_table (HB_OT_TAG_loca)); + this->loca = OT::Sanitizer::lock_instance (this->loca_blob); + this->glyf_blob = OT::Sanitizer::sanitize (face->reference_table (HB_OT_TAG_glyf)); + this->glyf = OT::Sanitizer::lock_instance (this->glyf_blob); + + this->num_glyphs = MAX (1u, hb_blob_get_length (this->loca_blob) / (this->short_offset ? 2 : 4)) - 1; + this->glyf_len = hb_blob_get_length (this->glyf_blob); + } + + inline void fini (void) + { + hb_blob_destroy (this->loca_blob); + hb_blob_destroy (this->glyf_blob); + } + + inline bool get_extents (hb_codepoint_t glyph, + hb_glyph_extents_t *extents) const + { + if (unlikely (glyph >= this->num_glyphs)) + return false; + + unsigned int start_offset, end_offset; + if (this->short_offset) + { + start_offset = 2 * this->loca->u.shortsZ[glyph]; + end_offset = 2 * this->loca->u.shortsZ[glyph + 1]; + } + else + { + start_offset = this->loca->u.longsZ[glyph]; + end_offset = this->loca->u.longsZ[glyph + 1]; + } + + if (start_offset > end_offset || end_offset > this->glyf_len) + return false; + + if (end_offset - start_offset < OT::glyfGlyphHeader::static_size) + return true; /* Empty glyph; zero extents. */ + + const OT::glyfGlyphHeader &glyph_header = OT::StructAtOffset (this->glyf, start_offset); + + extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax); + extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax); + extents->width = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing; + extents->height = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing; + + return true; + } +}; + +struct hb_ot_face_cmap_accelerator_t +{ + const OT::CmapSubtable *table; + const OT::CmapSubtable *uvs_table; + hb_blob_t *blob; + + inline void init (hb_face_t *face) + { + this->blob = OT::Sanitizer::sanitize (face->reference_table (HB_OT_TAG_cmap)); + const OT::cmap *cmap = OT::Sanitizer::lock_instance (this->blob); + const OT::CmapSubtable *subtable = NULL; + const OT::CmapSubtable *subtable_uvs = NULL; + + /* 32-bit subtables. */ + if (!subtable) subtable = cmap->find_subtable (3, 10); + if (!subtable) subtable = cmap->find_subtable (0, 6); + if (!subtable) subtable = cmap->find_subtable (0, 4); + /* 16-bit subtables. */ + if (!subtable) subtable = cmap->find_subtable (3, 1); + if (!subtable) subtable = cmap->find_subtable (0, 3); + if (!subtable) subtable = cmap->find_subtable (0, 2); + if (!subtable) subtable = cmap->find_subtable (0, 1); + if (!subtable) subtable = cmap->find_subtable (0, 0); + if (!subtable) subtable = cmap->find_subtable (3, 0); + /* Meh. */ + if (!subtable) subtable = &OT::Null(OT::CmapSubtable); + + /* UVS subtable. */ + if (!subtable_uvs) subtable_uvs = cmap->find_subtable (0, 5); + /* Meh. */ + if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtable); + + this->table = subtable; + this->uvs_table = subtable_uvs; + } + + inline void fini (void) + { + hb_blob_destroy (this->blob); + } + + inline bool get_glyph (hb_codepoint_t unicode, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph) const + { + if (unlikely (variation_selector)) + { + switch (this->uvs_table->get_glyph_variant (unicode, + variation_selector, + glyph)) + { + case OT::GLYPH_VARIANT_NOT_FOUND: return false; + case OT::GLYPH_VARIANT_FOUND: return true; + case OT::GLYPH_VARIANT_USE_DEFAULT: break; + } + } + + return this->table->get_glyph (unicode, glyph); + } +}; + + +struct hb_ot_font_t +{ + hb_ot_face_cmap_accelerator_t cmap; + hb_ot_face_metrics_accelerator_t h_metrics; + hb_ot_face_metrics_accelerator_t v_metrics; + hb_ot_face_glyf_accelerator_t glyf; +}; + + +static hb_ot_font_t * +_hb_ot_font_create (hb_face_t *face) +{ + hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t)); + + if (unlikely (!ot_font)) + return NULL; + + unsigned int upem = face->get_upem (); + + ot_font->cmap.init (face); + ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, upem>>1); + ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, upem); /* TODO Can we do this lazily? */ + ot_font->glyf.init (face); + + return ot_font; +} + +static void +_hb_ot_font_destroy (hb_ot_font_t *ot_font) +{ + ot_font->cmap.fini (); + ot_font->h_metrics.fini (); + ot_font->v_metrics.fini (); + ot_font->glyf.fini (); + + free (ot_font); +} + + +static hb_bool_t +hb_ot_get_glyph (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t unicode, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) + +{ + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; + return ot_font->cmap.get_glyph (unicode, variation_selector, glyph); +} + +static hb_position_t +hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) +{ + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; + return font->em_scale_x (ot_font->h_metrics.get_advance (glyph)); +} + +static hb_position_t +hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) +{ + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; + return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph)); +} + +static hb_bool_t +hb_ot_get_glyph_h_origin (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, + hb_position_t *x HB_UNUSED, + hb_position_t *y HB_UNUSED, + void *user_data HB_UNUSED) +{ + /* We always work in the horizontal coordinates. */ + return true; +} + +static hb_bool_t +hb_ot_get_glyph_v_origin (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + /* TODO */ + return false; +} + +static hb_position_t +hb_ot_get_glyph_h_kerning (hb_font_t *font, + void *font_data, + hb_codepoint_t left_glyph, + hb_codepoint_t right_glyph, + void *user_data HB_UNUSED) +{ + /* TODO */ + return 0; +} + +static hb_position_t +hb_ot_get_glyph_v_kerning (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t top_glyph HB_UNUSED, + hb_codepoint_t bottom_glyph HB_UNUSED, + void *user_data HB_UNUSED) +{ + /* OpenType doesn't have vertical-kerning other than GPOS. */ + return 0; +} + +static hb_bool_t +hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + void *user_data HB_UNUSED) +{ + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; + bool ret = ot_font->glyf.get_extents (glyph, extents); + extents->x_bearing = font->em_scale_x (extents->x_bearing); + extents->y_bearing = font->em_scale_y (extents->y_bearing); + extents->width = font->em_scale_x (extents->width); + extents->height = font->em_scale_y (extents->height); + return ret; +} + +static hb_bool_t +hb_ot_get_glyph_contour_point (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + unsigned int point_index, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + /* TODO */ + return false; +} + +static hb_bool_t +hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + char *name, unsigned int size, + void *user_data HB_UNUSED) +{ + /* TODO */ + return false; +} + +static hb_bool_t +hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED, + void *font_data, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) +{ + /* TODO */ + return false; +} + + +static hb_font_funcs_t * +_hb_ot_get_font_funcs (void) +{ + static const hb_font_funcs_t ot_ffuncs = { + HB_OBJECT_HEADER_STATIC, + + true, /* immutable */ + + { +#define HB_FONT_FUNC_IMPLEMENT(name) hb_ot_get_##name, + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT + } + }; + + return const_cast (&ot_ffuncs); +} + + +/** + * Since: 0.9.28 + **/ +void +hb_ot_font_set_funcs (hb_font_t *font) +{ + hb_ot_font_t *ot_font = _hb_ot_font_create (font->face); + if (unlikely (!ot_font)) + return; + + hb_font_set_funcs (font, + _hb_ot_get_font_funcs (), + ot_font, + (hb_destroy_func_t) _hb_ot_font_destroy); +} diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-font.h b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-font.h new file mode 100644 index 00000000000..b9947a16bc8 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-font.h @@ -0,0 +1,45 @@ +/* + * Copyright © 2014 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod, Roozbeh Pournader + */ + +#ifndef HB_OT_H_IN +#error "Include instead." +#endif + +#ifndef HB_OT_FONT_H +#define HB_OT_FONT_H + +#include "hb.h" + +HB_BEGIN_DECLS + + +void +hb_ot_font_set_funcs (hb_font_t *font); + + +HB_END_DECLS + +#endif /* HB_OT_FONT_H */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-glyf-table.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-glyf-table.hh new file mode 100644 index 00000000000..616bd6650d8 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-glyf-table.hh @@ -0,0 +1,104 @@ +/* + * Copyright © 2015 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_GLYF_TABLE_HH +#define HB_OT_GLYF_TABLE_HH + +#include "hb-open-type-private.hh" + + +namespace OT { + + +/* + * loca -- Index to Location + */ + +#define HB_OT_TAG_loca HB_TAG('l','o','c','a') + + +struct loca +{ + static const hb_tag_t tableTag = HB_OT_TAG_loca; + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (true); + } + + public: + union { + USHORT shortsZ[VAR]; /* Location offset divided by 2. */ + ULONG longsZ[VAR]; /* Location offset. */ + } u; + DEFINE_SIZE_ARRAY (0, u.longsZ); +}; + + +/* + * glyf -- TrueType Glyph Data + */ + +#define HB_OT_TAG_glyf HB_TAG('g','l','y','f') + + +struct glyf +{ + static const hb_tag_t tableTag = HB_OT_TAG_glyf; + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + /* We don't check for anything specific here. The users of the + * struct do all the hard work... */ + return_trace (true); + } + + public: + BYTE dataX[VAR]; /* Glyphs data. */ + + DEFINE_SIZE_ARRAY (0, dataX); +}; + +struct glyfGlyphHeader +{ + SHORT numberOfContours; /* If the number of contours is + * greater than or equal to zero, + * this is a simple glyph; if negative, + * this is a composite glyph. */ + SHORT xMin; /* Minimum x for coordinate data. */ + SHORT yMin; /* Minimum y for coordinate data. */ + SHORT xMax; /* Maximum x for coordinate data. */ + SHORT yMax; /* Maximum y for coordinate data. */ + + DEFINE_SIZE_STATIC (10); +}; + +} /* namespace OT */ + + +#endif /* HB_OT_GLYF_TABLE_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-head-table.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-head-table.hh new file mode 100644 index 00000000000..3cd59fbf2dd --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-head-table.hh @@ -0,0 +1,152 @@ +/* + * Copyright © 2010 Red Hat, Inc. + * Copyright © 2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_HEAD_TABLE_HH +#define HB_OT_HEAD_TABLE_HH + +#include "hb-open-type-private.hh" + + +namespace OT { + + +/* + * head -- Font Header + */ + +#define HB_OT_TAG_head HB_TAG('h','e','a','d') + +struct head +{ + static const hb_tag_t tableTag = HB_OT_TAG_head; + + inline unsigned int get_upem (void) const + { + unsigned int upem = unitsPerEm; + /* If no valid head table found, assume 1000, which matches typical Type1 usage. */ + return 16 <= upem && upem <= 16384 ? upem : 1000; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && likely (version.major == 1)); + } + + protected: + FixedVersion version; /* Version of the head table--currently + * 0x00010000u for version 1.0. */ + FixedVersion fontRevision; /* Set by font manufacturer. */ + ULONG checkSumAdjustment; /* To compute: set it to 0, sum the + * entire font as ULONG, then store + * 0xB1B0AFBAu - sum. */ + ULONG magicNumber; /* Set to 0x5F0F3CF5u. */ + USHORT flags; /* Bit 0: Baseline for font at y=0; + * Bit 1: Left sidebearing point at x=0; + * Bit 2: Instructions may depend on point size; + * Bit 3: Force ppem to integer values for all + * internal scaler math; may use fractional + * ppem sizes if this bit is clear; + * Bit 4: Instructions may alter advance width + * (the advance widths might not scale linearly); + + * Bits 5-10: These should be set according to + * Apple's specification. However, they are not + * implemented in OpenType. + * Bit 5: This bit should be set in fonts that are + * intended to e laid out vertically, and in + * which the glyphs have been drawn such that an + * x-coordinate of 0 corresponds to the desired + * vertical baseline. + * Bit 6: This bit must be set to zero. + * Bit 7: This bit should be set if the font + * requires layout for correct linguistic + * rendering (e.g. Arabic fonts). + * Bit 8: This bit should be set for a GX font + * which has one or more metamorphosis effects + * designated as happening by default. + * Bit 9: This bit should be set if the font + * contains any strong right-to-left glyphs. + * Bit 10: This bit should be set if the font + * contains Indic-style rearrangement effects. + + * Bit 11: Font data is 'lossless,' as a result + * of having been compressed and decompressed + * with the Agfa MicroType Express engine. + * Bit 12: Font converted (produce compatible metrics) + * Bit 13: Font optimized for ClearType™. + * Note, fonts that rely on embedded bitmaps (EBDT) + * for rendering should not be considered optimized + * for ClearType, and therefore should keep this bit + * cleared. + * Bit 14: Last Resort font. If set, indicates that + * the glyphs encoded in the cmap subtables are simply + * generic symbolic representations of code point + * ranges and don’t truly represent support for those + * code points. If unset, indicates that the glyphs + * encoded in the cmap subtables represent proper + * support for those code points. + * Bit 15: Reserved, set to 0. */ + USHORT unitsPerEm; /* Valid range is from 16 to 16384. This value + * should be a power of 2 for fonts that have + * TrueType outlines. */ + LONGDATETIME created; /* Number of seconds since 12:00 midnight, + January 1, 1904. 64-bit integer */ + LONGDATETIME modified; /* Number of seconds since 12:00 midnight, + January 1, 1904. 64-bit integer */ + SHORT xMin; /* For all glyph bounding boxes. */ + SHORT yMin; /* For all glyph bounding boxes. */ + SHORT xMax; /* For all glyph bounding boxes. */ + SHORT yMax; /* For all glyph bounding boxes. */ + USHORT macStyle; /* Bit 0: Bold (if set to 1); + * Bit 1: Italic (if set to 1) + * Bit 2: Underline (if set to 1) + * Bit 3: Outline (if set to 1) + * Bit 4: Shadow (if set to 1) + * Bit 5: Condensed (if set to 1) + * Bit 6: Extended (if set to 1) + * Bits 7-15: Reserved (set to 0). */ + USHORT lowestRecPPEM; /* Smallest readable size in pixels. */ + SHORT fontDirectionHint; /* Deprecated (Set to 2). + * 0: Fully mixed directional glyphs; + * 1: Only strongly left to right; + * 2: Like 1 but also contains neutrals; + * -1: Only strongly right to left; + * -2: Like -1 but also contains neutrals. */ + public: + SHORT indexToLocFormat; /* 0 for short offsets, 1 for long. */ + SHORT glyphDataFormat; /* 0 for current format. */ + + DEFINE_SIZE_STATIC (54); +}; + + +} /* namespace OT */ + + +#endif /* HB_OT_HEAD_TABLE_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-hhea-table.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-hhea-table.hh new file mode 100644 index 00000000000..ed65934fae4 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-hhea-table.hh @@ -0,0 +1,103 @@ +/* + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_HHEA_TABLE_HH +#define HB_OT_HHEA_TABLE_HH + +#include "hb-open-type-private.hh" + + +namespace OT { + + +/* + * hhea -- The Horizontal Header Table + * vhea -- The Vertical Header Table + */ + +#define HB_OT_TAG_hhea HB_TAG('h','h','e','a') +#define HB_OT_TAG_vhea HB_TAG('v','h','e','a') + + +struct _hea +{ + static const hb_tag_t tableTag = HB_TAG('_','h','e','a'); + + static const hb_tag_t hheaTag = HB_OT_TAG_hhea; + static const hb_tag_t vheaTag = HB_OT_TAG_vhea; + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && likely (version.major == 1)); + } + + public: + FixedVersion version; /* 0x00010000u for version 1.0. */ + FWORD ascender; /* Typographic ascent. */ + FWORD descender; /* Typographic descent. */ + FWORD lineGap; /* Typographic line gap. */ + UFWORD advanceMax; /* Maximum advance width/height value in + * metrics table. */ + FWORD minLeadingBearing; /* Minimum left/top sidebearing value in + * metrics table. */ + FWORD minTrailingBearing; /* Minimum right/bottom sidebearing value; + * calculated as Min(aw - lsb - + * (xMax - xMin)) for horizontal. */ + FWORD maxExtent; /* horizontal: Max(lsb + (xMax - xMin)), + * vertical: minLeadingBearing+(yMax-yMin). */ + SHORT caretSlopeRise; /* Used to calculate the slope of the + * cursor (rise/run); 1 for vertical caret, + * 0 for horizontal.*/ + SHORT caretSlopeRun; /* 0 for vertical caret, 1 for horizontal. */ + SHORT caretOffset; /* The amount by which a slanted + * highlight on a glyph needs + * to be shifted to produce the + * best appearance. Set to 0 for + * non-slanted fonts. */ + SHORT reserved1; /* Set to 0. */ + SHORT reserved2; /* Set to 0. */ + SHORT reserved3; /* Set to 0. */ + SHORT reserved4; /* Set to 0. */ + SHORT metricDataFormat; /* 0 for current format. */ + USHORT numberOfLongMetrics; /* Number of LongMetric entries in metric + * table. */ + public: + DEFINE_SIZE_STATIC (36); +}; + +struct hhea : _hea { + static const hb_tag_t tableTag = HB_OT_TAG_hhea; +}; +struct vhea : _hea { + static const hb_tag_t tableTag = HB_OT_TAG_vhea; +}; + + +} /* namespace OT */ + + +#endif /* HB_OT_HHEA_TABLE_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-hmtx-table.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-hmtx-table.hh new file mode 100644 index 00000000000..cd266ffbee7 --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-hmtx-table.hh @@ -0,0 +1,104 @@ +/* + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_HMTX_TABLE_HH +#define HB_OT_HMTX_TABLE_HH + +#include "hb-open-type-private.hh" + + +namespace OT { + + +/* + * hmtx -- The Horizontal Metrics Table + * vmtx -- The Vertical Metrics Table + */ + +#define HB_OT_TAG_hmtx HB_TAG('h','m','t','x') +#define HB_OT_TAG_vmtx HB_TAG('v','m','t','x') + + +struct LongMetric +{ + USHORT advance; /* Advance width/height. */ + SHORT lsb; /* Leading (left/top) side bearing. */ + public: + DEFINE_SIZE_STATIC (4); +}; + +struct _mtx +{ + static const hb_tag_t tableTag = HB_TAG('_','m','t','x'); + + static const hb_tag_t hmtxTag = HB_OT_TAG_hmtx; + static const hb_tag_t vmtxTag = HB_OT_TAG_vmtx; + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + /* We don't check for anything specific here. The users of the + * struct do all the hard work... */ + return_trace (true); + } + + public: + LongMetric longMetric[VAR]; /* Paired advance width and leading + * bearing values for each glyph. The + * value numOfHMetrics comes from + * the 'hhea' table. If the font is + * monospaced, only one entry need + * be in the array, but that entry is + * required. The last entry applies to + * all subsequent glyphs. */ + SHORT leadingBearingX[VAR]; /* Here the advance is assumed + * to be the same as the advance + * for the last entry above. The + * number of entries in this array is + * derived from numGlyphs (from 'maxp' + * table) minus numberOfLongMetrics. + * This generally is used with a run + * of monospaced glyphs (e.g., Kanji + * fonts or Courier fonts). Only one + * run is allowed and it must be at + * the end. This allows a monospaced + * font to vary the side bearing + * values for each glyph. */ + public: + DEFINE_SIZE_ARRAY2 (0, longMetric, leadingBearingX); +}; + +struct hmtx : _mtx { + static const hb_tag_t tableTag = HB_OT_TAG_hmtx; +}; +struct vmtx : _mtx { + static const hb_tag_t tableTag = HB_OT_TAG_vmtx; +}; + +} /* namespace OT */ + + +#endif /* HB_OT_HMTX_TABLE_HH */ diff --git a/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-common-private.hh b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-common-private.hh new file mode 100644 index 00000000000..f087b2317cb --- /dev/null +++ b/jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-common-private.hh @@ -0,0 +1,1224 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2010,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH +#define HB_OT_LAYOUT_COMMON_PRIVATE_HH + +#include "hb-ot-layout-private.hh" +#include "hb-open-type-private.hh" +#include "hb-set-private.hh" + + +namespace OT { + + +#define TRACE_DISPATCH(this, format) \ + hb_auto_trace_t trace \ + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ + "format %d", (int) format); + + +#define NOT_COVERED ((unsigned int) -1) +#define MAX_NESTING_LEVEL 6 +#define MAX_CONTEXT_LENGTH 64 + + + +/* + * + * OpenType Layout Common Table Formats + * + */ + + +/* + * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList + */ + +template +struct Record +{ + inline int cmp (hb_tag_t a) const { + return tag.cmp (a); + } + + struct sanitize_closure_t { + hb_tag_t tag; + const void *list_base; + }; + inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + const sanitize_closure_t closure = {tag, base}; + return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure)); + } + + Tag tag; /* 4-byte Tag identifier */ + OffsetTo + offset; /* Offset from beginning of object holding + * the Record */ + public: + DEFINE_SIZE_STATIC (6); +}; + +template +struct RecordArrayOf : SortedArrayOf > { + inline const Tag& get_tag (unsigned int i) const + { + /* We cheat slightly and don't define separate Null objects + * for Record types. Instead, we return the correct Null(Tag) + * here. */ + if (unlikely (i >= this->len)) return Null(Tag); + return (*this)[i].tag; + } + inline unsigned int get_tags (unsigned int start_offset, + unsigned int *record_count /* IN/OUT */, + hb_tag_t *record_tags /* OUT */) const + { + if (record_count) { + const Record *arr = this->sub_array (start_offset, record_count); + unsigned int count = *record_count; + for (unsigned int i = 0; i < count; i++) + record_tags[i] = arr[i].tag; + } + return this->len; + } + inline bool find_index (hb_tag_t tag, unsigned int *index) const + { + /* If we want to allow non-sorted data, we can lsearch(). */ + int i = this->/*lsearch*/bsearch (tag); + if (i != -1) { + if (index) *index = i; + return true; + } else { + if (index) *index = Index::NOT_FOUND_INDEX; + return false; + } + } +}; + +template +struct RecordListOf : RecordArrayOf +{ + inline const Type& operator [] (unsigned int i) const + { return this+RecordArrayOf::operator [](i).offset; } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (RecordArrayOf::sanitize (c, this)); + } +}; + + +struct RangeRecord +{ + inline int cmp (hb_codepoint_t g) const { + return g < start ? -1 : g <= end ? 0 : +1 ; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + inline bool intersects (const hb_set_t *glyphs) const { + return glyphs->intersects (start, end); + } + + template + inline void add_coverage (set_t *glyphs) const { + glyphs->add_range (start, end); + } + + GlyphID start; /* First GlyphID in the range */ + GlyphID end; /* Last GlyphID in the range */ + USHORT value; /* Value */ + public: + DEFINE_SIZE_STATIC (6); +}; +DEFINE_NULL_DATA (RangeRecord, "\000\001"); + + +struct IndexArray : ArrayOf +{ + inline unsigned int get_indexes (unsigned int start_offset, + unsigned int *_count /* IN/OUT */, + unsigned int *_indexes /* OUT */) const + { + if (_count) { + const USHORT *arr = this->sub_array (start_offset, _count); + unsigned int count = *_count; + for (unsigned int i = 0; i < count; i++) + _indexes[i] = arr[i]; + } + return this->len; + } +}; + + +struct Script; +struct LangSys; +struct Feature; + + +struct LangSys +{ + inline unsigned int get_feature_count (void) const + { return featureIndex.len; } + inline hb_tag_t get_feature_index (unsigned int i) const + { return featureIndex[i]; } + inline unsigned int get_feature_indexes (unsigned int start_offset, + unsigned int *feature_count /* IN/OUT */, + unsigned int *feature_indexes /* OUT */) const + { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); } + + inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; } + inline unsigned int get_required_feature_index (void) const + { + if (reqFeatureIndex == 0xFFFFu) + return Index::NOT_FOUND_INDEX; + return reqFeatureIndex;; + } + + inline bool sanitize (hb_sanitize_context_t *c, + const Record::sanitize_closure_t * = NULL) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && featureIndex.sanitize (c)); + } + + Offset<> lookupOrderZ; /* = Null (reserved for an offset to a + * reordering table) */ + USHORT reqFeatureIndex;/* Index of a feature required for this + * language system--if no required features + * = 0xFFFFu */ + IndexArray featureIndex; /* Array of indices into the FeatureList */ + public: + DEFINE_SIZE_ARRAY (6, featureIndex); +}; +DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF"); + + +struct Script +{ + inline unsigned int get_lang_sys_count (void) const + { return langSys.len; } + inline const Tag& get_lang_sys_tag (unsigned int i) const + { return langSys.get_tag (i); } + inline unsigned int get_lang_sys_tags (unsigned int start_offset, + unsigned int *lang_sys_count /* IN/OUT */, + hb_tag_t *lang_sys_tags /* OUT */) const + { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); } + inline const LangSys& get_lang_sys (unsigned int i) const + { + if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys (); + return this+langSys[i].offset; + } + inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const + { return langSys.find_index (tag, index); } + + inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; } + inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } + + inline bool sanitize (hb_sanitize_context_t *c, + const Record