From 0e441f9177eb9852be6a47f8e7b0afcf39d89342 Mon Sep 17 00:00:00 2001 From: Pavel Punegov Date: Wed, 17 Feb 2016 17:48:56 +0300 Subject: [PATCH 001/129] 8144621: CompilerControl: inline tests timeout with Xcomp Restrict patterns that lead to timeout Reviewed-by: kvn, neliasso --- .../compiler/compilercontrol/share/AbstractTestBase.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java b/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java index 2e1c2013b43..04d8ada9319 100644 --- a/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java +++ b/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java @@ -51,8 +51,9 @@ public abstract class AbstractTestBase { for (int i = 0; !md.isValid() && i < ATTEMPTS; i++) { md = METHOD_GEN.generateRandomDescriptor(exec); } - if (!md.isValid()) { - System.out.println("WARN: Using predefined pattern"); + if (!md.isValid() || "any.method()".matches(md.getRegexp())) { + /* if we haven't got a valid pattern or it matches any method + leading to timeouts, then use plain standard descriptor */ md = MethodGenerator.commandDescriptor(exec); } return md; From b239e217b925411aa043d2022dad19a97fb892e7 Mon Sep 17 00:00:00 2001 From: Rahul Raghavan Date: Fri, 19 Feb 2016 10:06:19 +0100 Subject: [PATCH 002/129] 8145707: 4 Null pointer dereference defect groups in compileBroker.cpp Added explicit null checks to fix possible null pointer dereference errors for internal tests. Reviewed-by: kvn --- .../src/share/vm/compiler/compileBroker.cpp | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 117e7d130ba..44903801d83 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -2152,18 +2152,33 @@ void CompileBroker::collect_statistics(CompilerThread* thread, elapsedTimer time if (CITime) { int bytes_compiled = method->code_size() + task->num_inlined_bytecodes(); - JVMCI_ONLY(CompilerStatistics* stats = compiler(task->comp_level())->stats();) if (is_osr) { _t_osr_compilation.add(time); _sum_osr_bytes_compiled += bytes_compiled; - JVMCI_ONLY(stats->_osr.update(time, bytes_compiled);) } else { _t_standard_compilation.add(time); _sum_standard_bytes_compiled += method->code_size() + task->num_inlined_bytecodes(); - JVMCI_ONLY(stats->_standard.update(time, bytes_compiled);) } - JVMCI_ONLY(stats->_nmethods_size += code->total_size();) - JVMCI_ONLY(stats->_nmethods_code_size += code->insts_size();) + +#if INCLUDE_JVMCI + AbstractCompiler* comp = compiler(task->comp_level()); + if (comp) { + CompilerStatistics* stats = comp->stats(); + if (stats) { + if (is_osr) { + stats->_osr.update(time, bytes_compiled); + } else { + stats->_standard.update(time, bytes_compiled); + } + stats->_nmethods_size += code->total_size(); + stats->_nmethods_code_size += code->insts_size(); + } else { // if (!stats) + assert(false, "Compiler statistics object must exist"); + } + } else { // if (!comp) + assert(false, "Compiler object must exist"); + } +#endif // INCLUDE_JVMCI } if (UsePerfData) { @@ -2222,11 +2237,15 @@ const char* CompileBroker::compiler_name(int comp_level) { #if INCLUDE_JVMCI void CompileBroker::print_times(AbstractCompiler* comp) { CompilerStatistics* stats = comp->stats(); - tty->print_cr(" %s {speed: %d bytes/s; standard: %6.3f s, %d bytes, %d methods; osr: %6.3f s, %d bytes, %d methods; nmethods_size: %d bytes; nmethods_code_size: %d bytes}", + if (stats) { + tty->print_cr(" %s {speed: %d bytes/s; standard: %6.3f s, %d bytes, %d methods; osr: %6.3f s, %d bytes, %d methods; nmethods_size: %d bytes; nmethods_code_size: %d bytes}", comp->name(), stats->bytes_per_second(), stats->_standard._time.seconds(), stats->_standard._bytes, stats->_standard._count, stats->_osr._time.seconds(), stats->_osr._bytes, stats->_osr._count, stats->_nmethods_size, stats->_nmethods_code_size); + } else { // if (!stats) + assert(false, "Compiler statistics object must exist"); + } comp->print_timers(); } #endif // INCLUDE_JVMCI @@ -2260,17 +2279,21 @@ void CompileBroker::print_times(bool per_compiler, bool aggregate) { } CompilerStatistics* stats = comp->stats(); - standard_compilation.add(stats->_standard._time); - osr_compilation.add(stats->_osr._time); + if (stats) { + standard_compilation.add(stats->_standard._time); + osr_compilation.add(stats->_osr._time); - standard_bytes_compiled += stats->_standard._bytes; - osr_bytes_compiled += stats->_osr._bytes; + standard_bytes_compiled += stats->_standard._bytes; + osr_bytes_compiled += stats->_osr._bytes; - standard_compile_count += stats->_standard._count; - osr_compile_count += stats->_osr._count; + standard_compile_count += stats->_standard._count; + osr_compile_count += stats->_osr._count; - nmethods_size += stats->_nmethods_size; - nmethods_code_size += stats->_nmethods_code_size; + nmethods_size += stats->_nmethods_size; + nmethods_code_size += stats->_nmethods_code_size; + } else { // if (!stats) + assert(false, "Compiler statistics object must exist"); + } if (per_compiler) { print_times(comp); From 4532f543002d8093241791877e20333235790e4f Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 19 Feb 2016 20:40:20 +0300 Subject: [PATCH 003/129] 7177745: JSR292: Many Callsite relinkages cause target method to always run in interpreter mode Reviewed-by: jrose, kvn --- hotspot/src/share/vm/code/codeCache.cpp | 2 +- hotspot/src/share/vm/code/codeCache.hpp | 4 +- hotspot/src/share/vm/code/dependencies.hpp | 10 ++ .../src/share/vm/code/dependencyContext.cpp | 2 +- hotspot/src/share/vm/code/nmethod.cpp | 4 +- hotspot/src/share/vm/code/nmethod.hpp | 21 +++- hotspot/src/share/vm/oops/instanceKlass.cpp | 2 +- hotspot/src/share/vm/oops/instanceKlass.hpp | 4 +- hotspot/src/share/vm/runtime/vmStructs.cpp | 1 - .../ContinuousCallSiteTargetChange.java | 103 ++++++++++++++++++ 10 files changed, 140 insertions(+), 13 deletions(-) create mode 100644 hotspot/test/compiler/jsr292/ContinuousCallSiteTargetChange.java diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index c7c31c30d3b..0882ee82739 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -1023,7 +1023,7 @@ void CodeCache::clear_inline_caches() { // Keeps track of time spent for checking dependencies NOT_PRODUCT(static elapsedTimer dependentCheckTime;) -int CodeCache::mark_for_deoptimization(DepChange& changes) { +int CodeCache::mark_for_deoptimization(KlassDepChange& changes) { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); int number_of_marked_CodeBlobs = 0; diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp index a3da713c9e5..f07b4c940db 100644 --- a/hotspot/src/share/vm/code/codeCache.hpp +++ b/hotspot/src/share/vm/code/codeCache.hpp @@ -72,7 +72,7 @@ // Solaris and BSD. class OopClosure; -class DepChange; +class KlassDepChange; class CodeCache : AllStatic { friend class VMStructs; @@ -223,7 +223,7 @@ class CodeCache : AllStatic { // Deoptimization private: - static int mark_for_deoptimization(DepChange& changes); + static int mark_for_deoptimization(KlassDepChange& changes); #ifdef HOTSWAP static int mark_for_evol_deoptimization(instanceKlassHandle dependee); #endif // HOTSWAP diff --git a/hotspot/src/share/vm/code/dependencies.hpp b/hotspot/src/share/vm/code/dependencies.hpp index b62c6bf12ed..22a2fd2ce53 100644 --- a/hotspot/src/share/vm/code/dependencies.hpp +++ b/hotspot/src/share/vm/code/dependencies.hpp @@ -664,6 +664,8 @@ class DepChange : public StackObj { virtual bool is_klass_change() const { return false; } virtual bool is_call_site_change() const { return false; } + virtual void mark_for_deoptimization(nmethod* nm) = 0; + // Subclass casting with assertions. KlassDepChange* as_klass_change() { assert(is_klass_change(), "bad cast"); @@ -753,6 +755,10 @@ class KlassDepChange : public DepChange { // What kind of DepChange is this? virtual bool is_klass_change() const { return true; } + virtual void mark_for_deoptimization(nmethod* nm) { + nm->mark_for_deoptimization(/*inc_recompile_counts=*/true); + } + Klass* new_type() { return _new_type(); } // involves_context(k) is true if k is new_type or any of the super types @@ -772,6 +778,10 @@ class CallSiteDepChange : public DepChange { // What kind of DepChange is this? virtual bool is_call_site_change() const { return true; } + virtual void mark_for_deoptimization(nmethod* nm) { + nm->mark_for_deoptimization(/*inc_recompile_counts=*/false); + } + oop call_site() const { return _call_site(); } oop method_handle() const { return _method_handle(); } }; diff --git a/hotspot/src/share/vm/code/dependencyContext.cpp b/hotspot/src/share/vm/code/dependencyContext.cpp index dc19c4a0886..435fb0cdfb2 100644 --- a/hotspot/src/share/vm/code/dependencyContext.cpp +++ b/hotspot/src/share/vm/code/dependencyContext.cpp @@ -73,7 +73,7 @@ int DependencyContext::mark_dependent_nmethods(DepChange& changes) { nm->print(); nm->print_dependencies(); } - nm->mark_for_deoptimization(); + changes.mark_for_deoptimization(nm); found++; } } diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 63acd8f424d..46fe64850e4 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -536,7 +536,7 @@ void nmethod::init_defaults() { _has_method_handle_invokes = 0; _lazy_critical_native = 0; _has_wide_vectors = 0; - _marked_for_deoptimization = 0; + _mark_for_deoptimization_status = not_marked; _lock_count = 0; _stack_traversal_mark = 0; _unload_reported = false; // jvmti state @@ -1459,7 +1459,7 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { SharedRuntime::get_handle_wrong_method_stub()); } - if (is_in_use()) { + if (is_in_use() && update_recompile_counts()) { // It's a true state change, so mark the method as decompiled. // Do it only for transition from alive. inc_decompile_count(); diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 537a68ce566..6c0d9f839ac 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -107,6 +107,7 @@ class PcDescCache VALUE_OBJ_CLASS_SPEC { // [Implicit Null Pointer exception table] // - implicit null table array +class DepChange; class Dependencies; class ExceptionHandlerTable; class ImplicitExceptionTable; @@ -188,7 +189,13 @@ class nmethod : public CodeBlob { bool _has_flushed_dependencies; // Used for maintenance of dependencies (CodeCache_lock) bool _marked_for_reclamation; // Used by NMethodSweeper (set only by sweeper) - bool _marked_for_deoptimization; // Used for stack deoptimization + + enum MarkForDeoptimizationStatus { + not_marked, + deoptimize, + deoptimize_noupdate }; + + MarkForDeoptimizationStatus _mark_for_deoptimization_status; // Used for stack deoptimization // used by jvmti to track if an unload event has been posted for this nmethod. bool _unload_reported; @@ -462,8 +469,16 @@ class nmethod : public CodeBlob { void set_unloading_clock(unsigned char unloading_clock); unsigned char unloading_clock(); - bool is_marked_for_deoptimization() const { return _marked_for_deoptimization; } - void mark_for_deoptimization() { _marked_for_deoptimization = true; } + bool is_marked_for_deoptimization() const { return _mark_for_deoptimization_status != not_marked; } + void mark_for_deoptimization(bool inc_recompile_counts = true) { + _mark_for_deoptimization_status = (inc_recompile_counts ? deoptimize : deoptimize_noupdate); + } + bool update_recompile_counts() const { + // Update recompile counts when either the update is explicitly requested (deoptimize) + // or the nmethod is not marked for deoptimization at all (not_marked). + // The latter happens during uncommon traps when deoptimized nmethod is made not entrant. + return _mark_for_deoptimization_status != deoptimize_noupdate; + } void make_unloaded(BoolObjectClosure* is_alive, oop cause); diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 0ae310bdaf6..d1297af03df 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -1879,7 +1879,7 @@ inline DependencyContext InstanceKlass::dependencies() { return dep_context; } -int InstanceKlass::mark_dependent_nmethods(DepChange& changes) { +int InstanceKlass::mark_dependent_nmethods(KlassDepChange& changes) { return dependencies().mark_dependent_nmethods(changes); } diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index f7a3a24800f..aa3604f8997 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -56,7 +56,7 @@ // forward declaration for class -- see below for definition class BreakpointInfo; class ClassFileParser; -class DepChange; +class KlassDepChange; class DependencyContext; class fieldDescriptor; class jniIdMapBase; @@ -821,7 +821,7 @@ public: // maintenance of deoptimization dependencies inline DependencyContext dependencies(); - int mark_dependent_nmethods(DepChange& changes); + int mark_dependent_nmethods(KlassDepChange& changes); void add_dependent_nmethod(nmethod* nm); void remove_dependent_nmethod(nmethod* nm, bool delete_immediately); diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index c6519c03600..0778abc2f7a 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -960,7 +960,6 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(nmethod, _compile_id, int) \ nonstatic_field(nmethod, _comp_level, int) \ nonstatic_field(nmethod, _exception_cache, ExceptionCache*) \ - nonstatic_field(nmethod, _marked_for_deoptimization, bool) \ \ unchecked_c2_static_field(Deoptimization, _trap_reason_name, void*) \ \ diff --git a/hotspot/test/compiler/jsr292/ContinuousCallSiteTargetChange.java b/hotspot/test/compiler/jsr292/ContinuousCallSiteTargetChange.java new file mode 100644 index 00000000000..a59f962fd22 --- /dev/null +++ b/hotspot/test/compiler/jsr292/ContinuousCallSiteTargetChange.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /testlibrary + * @run main ContinuousCallSiteTargetChange + */ +import java.lang.invoke.*; +import jdk.test.lib.*; + +public class ContinuousCallSiteTargetChange { + static void testServer() throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", + "-server", "-XX:-TieredCompilation", "-Xbatch", + "-XX:PerBytecodeRecompilationCutoff=10", "-XX:PerMethodRecompilationCutoff=10", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "ContinuousCallSiteTargetChange$Test", "100"); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + analyzer.shouldNotContain("made not compilable"); + analyzer.shouldNotContain("decompile_count > PerMethodRecompilationCutoff"); + } + + static void testClient() throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", + "-client", "-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1", "-Xbatch", + "-XX:PerBytecodeRecompilationCutoff=10", "-XX:PerMethodRecompilationCutoff=10", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "ContinuousCallSiteTargetChange$Test", "100"); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + analyzer.shouldNotContain("made not compilable"); + analyzer.shouldNotContain("decompile_count > PerMethodRecompilationCutoff"); + } + + public static void main(String[] args) throws Exception { + testServer(); + testClient(); + } + + static class Test { + static final MethodType mt = MethodType.methodType(void.class); + static final CallSite cs = new MutableCallSite(mt); + + static final MethodHandle mh = cs.dynamicInvoker(); + + static void f() { + } + + static void test1() throws Throwable { + mh.invokeExact(); + } + + static void test2() throws Throwable { + cs.getTarget().invokeExact(); + } + + static void iteration() throws Throwable { + MethodHandle mh1 = MethodHandles.lookup().findStatic(ContinuousCallSiteTargetChange.Test.class, "f", mt); + cs.setTarget(mh1); + for (int i = 0; i < 20_000; i++) { + test1(); + test2(); + } + } + + public static void main(String[] args) throws Throwable { + int iterations = Integer.parseInt(args[0]); + for (int i = 0; i < iterations; i++) { + iteration(); + } + } + } +} From 78fbdd19fa16e09b06d694b77a3ea86e941e30a8 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 19 Feb 2016 20:41:36 +0300 Subject: [PATCH 004/129] 8149741: Don't refer to stub entry points by index in external_word relocations Reviewed-by: kvn --- .../vm/templateInterpreterGenerator_x86.cpp | 8 +-- .../windows_x86/vm/assembler_windows_x86.cpp | 5 +- hotspot/src/share/vm/code/relocInfo.cpp | 68 ++----------------- hotspot/src/share/vm/code/relocInfo.hpp | 11 +-- .../share/vm/prims/jvmtiCodeBlobEvents.cpp | 4 +- .../share/vm/runtime/stubCodeGenerator.cpp | 53 ++++----------- .../share/vm/runtime/stubCodeGenerator.hpp | 15 ++-- 7 files changed, 30 insertions(+), 134 deletions(-) diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp index eb155c20be9..fc69cb45e5b 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp @@ -161,13 +161,7 @@ address TemplateInterpreterGenerator::generate_exception_handler_common( create_klass_exception), rarg, rarg2); } else { - // kind of lame ExternalAddress can't take NULL because - // external_word_Relocation will assert. - if (message != NULL) { - __ lea(rarg2, ExternalAddress((address)message)); - } else { - __ movptr(rarg2, NULL_WORD); - } + __ lea(rarg2, ExternalAddress((address)message)); __ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), rarg, rarg2); diff --git a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp index 71e1e8b6aad..8045f792b76 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp +++ b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp @@ -51,11 +51,8 @@ void MacroAssembler::int3() { // movl reg, [reg + thread_ptr_offset] Load thread // void MacroAssembler::get_thread(Register thread) { - // can't use ExternalAddress because it can't take NULL - AddressLiteral null(0, relocInfo::none); - prefix(FS_segment); - movptr(thread, null); + movptr(thread, ExternalAddress(NULL)); assert(os::win32::get_thread_ptr_offset() != 0, "Thread Pointer Offset has not been initialized"); movl(thread, Address(thread, os::win32::get_thread_ptr_offset())); diff --git a/hotspot/src/share/vm/code/relocInfo.cpp b/hotspot/src/share/vm/code/relocInfo.cpp index ec83dad64a8..444c91c46be 100644 --- a/hotspot/src/share/vm/code/relocInfo.cpp +++ b/hotspot/src/share/vm/code/relocInfo.cpp @@ -457,49 +457,6 @@ RelocationHolder Relocation::spec_simple(relocInfo::relocType rtype) { return itr._rh; } -int32_t Relocation::runtime_address_to_index(address runtime_address) { - assert(!is_reloc_index((intptr_t)runtime_address), "must not look like an index"); - - if (runtime_address == NULL) return 0; - - StubCodeDesc* p = StubCodeDesc::desc_for(runtime_address); - if (p != NULL && p->begin() == runtime_address) { - assert(is_reloc_index(p->index()), "there must not be too many stubs"); - return (int32_t)p->index(); - } else { - // Known "miscellaneous" non-stub pointers: - // os::get_polling_page(), SafepointSynchronize::address_of_state() - if (PrintRelocations) { - tty->print_cr("random unregistered address in relocInfo: " INTPTR_FORMAT, p2i(runtime_address)); - } -#ifndef _LP64 - return (int32_t) (intptr_t)runtime_address; -#else - // didn't fit return non-index - return -1; -#endif /* _LP64 */ - } -} - - -address Relocation::index_to_runtime_address(int32_t index) { - if (index == 0) return NULL; - - if (is_reloc_index(index)) { - StubCodeDesc* p = StubCodeDesc::desc_for_index(index); - assert(p != NULL, "there must be a stub for this index"); - return p->begin(); - } else { -#ifndef _LP64 - // this only works on 32bit machines - return (address) ((intptr_t) index); -#else - fatal("Relocation::index_to_runtime_address, int32_t not pointer sized"); - return NULL; -#endif /* _LP64 */ - } -} - address Relocation::old_addr_for(address newa, const CodeBuffer* src, CodeBuffer* dest) { int sect = dest->section_index_of(newa); @@ -623,20 +580,13 @@ void trampoline_stub_Relocation::unpack_data() { void external_word_Relocation::pack_data_to(CodeSection* dest) { short* p = (short*) dest->locs_end(); - int32_t index = runtime_address_to_index(_target); #ifndef _LP64 - p = pack_1_int_to(p, index); + p = pack_1_int_to(p, (int32_t) (intptr_t)_target); #else - if (is_reloc_index(index)) { - p = pack_2_ints_to(p, index, 0); - } else { - jlong t = (jlong) _target; - int32_t lo = low(t); - int32_t hi = high(t); - p = pack_2_ints_to(p, lo, hi); - DEBUG_ONLY(jlong t1 = jlong_from(hi, lo)); - assert(!is_reloc_index(t1) && (address) t1 == _target, "not symmetric"); - } + jlong t = (jlong) _target; + int32_t lo = low(t); + int32_t hi = high(t); + p = pack_2_ints_to(p, lo, hi); #endif /* _LP64 */ dest->set_locs_end((relocInfo*) p); } @@ -644,16 +594,12 @@ void external_word_Relocation::pack_data_to(CodeSection* dest) { void external_word_Relocation::unpack_data() { #ifndef _LP64 - _target = index_to_runtime_address(unpack_1_int()); + _target = (address) (intptr_t)unpack_1_int(); #else int32_t lo, hi; unpack_2_ints(lo, hi); jlong t = jlong_from(hi, lo);; - if (is_reloc_index(t)) { - _target = index_to_runtime_address(t); - } else { - _target = (address) t; - } + _target = (address) t; #endif /* _LP64 */ } diff --git a/hotspot/src/share/vm/code/relocInfo.hpp b/hotspot/src/share/vm/code/relocInfo.hpp index a243bfdbee7..b399c093759 100644 --- a/hotspot/src/share/vm/code/relocInfo.hpp +++ b/hotspot/src/share/vm/code/relocInfo.hpp @@ -707,10 +707,6 @@ class Relocation VALUE_OBJ_CLASS_SPEC { assert(datalen()==0 || type()==relocInfo::none, "no data here"); } - static bool is_reloc_index(intptr_t index) { - return 0 < index && index < os::vm_page_size(); - } - protected: // Helper functions for pack_data_to() and unpack_data(). @@ -806,10 +802,6 @@ class Relocation VALUE_OBJ_CLASS_SPEC { return base + byte_offset; } - // these convert between indexes and addresses in the runtime system - static int32_t runtime_address_to_index(address runtime_address); - static address index_to_runtime_address(int32_t index); - // helpers for mapping between old and new addresses after a move or resize address old_addr_for(address newa, const CodeBuffer* src, CodeBuffer* dest); address new_addr_for(address olda, const CodeBuffer* src, CodeBuffer* dest); @@ -1253,7 +1245,8 @@ class external_word_Relocation : public DataRelocation { // Some address looking values aren't safe to treat as relocations // and should just be treated as constants. static bool can_be_relocated(address target) { - return target != NULL && !is_reloc_index((intptr_t)target); + assert(target == NULL || (uintptr_t)target >= (uintptr_t)os::vm_page_size(), INTPTR_FORMAT, (intptr_t)target); + return target != NULL; } private: diff --git a/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp b/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp index 3031f1c4e5b..975836cd32a 100644 --- a/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp +++ b/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp @@ -173,9 +173,7 @@ void CodeBlobCollector::collect() { _global_code_blobs = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(50,true); // iterate over the stub code descriptors and put them in the list first. - int index = 0; - StubCodeDesc* desc; - while ((desc = StubCodeDesc::desc_for_index(++index)) != NULL) { + for (StubCodeDesc* desc = StubCodeDesc::first(); desc != NULL; desc = StubCodeDesc::next(desc)) { _global_code_blobs->append(new JvmtiCodeBlobDesc(desc->name(), desc->begin(), desc->end())); } diff --git a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp index 5b9adc09776..db440291575 100644 --- a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp +++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp @@ -36,19 +36,13 @@ // Implementation of StubCodeDesc StubCodeDesc* StubCodeDesc::_list = NULL; -int StubCodeDesc::_count = 0; bool StubCodeDesc::_frozen = false; StubCodeDesc* StubCodeDesc::desc_for(address pc) { StubCodeDesc* p = _list; - while (p != NULL && !p->contains(pc)) p = p->_next; - // p == NULL || p->contains(pc) - return p; -} - -StubCodeDesc* StubCodeDesc::desc_for_index(int index) { - StubCodeDesc* p = _list; - while (p != NULL && p->index() != index) p = p->_next; + while (p != NULL && !p->contains(pc)) { + p = p->_next; + } return p; } @@ -73,43 +67,17 @@ void StubCodeDesc::print_on(outputStream* st) const { // Implementation of StubCodeGenerator StubCodeGenerator::StubCodeGenerator(CodeBuffer* code, bool print_code) { - _masm = new MacroAssembler(code); - _first_stub = _last_stub = NULL; - _print_code = print_code; -} - -extern "C" { - static int compare_cdesc(const void* void_a, const void* void_b) { - int ai = (*((StubCodeDesc**) void_a))->index(); - int bi = (*((StubCodeDesc**) void_b))->index(); - return ai - bi; - } + _masm = new MacroAssembler(code ); + _print_code = PrintStubCode || print_code; } StubCodeGenerator::~StubCodeGenerator() { - if (PrintStubCode || _print_code) { + if (_print_code) { CodeBuffer* cbuf = _masm->code(); CodeBlob* blob = CodeCache::find_blob_unsafe(cbuf->insts()->start()); if (blob != NULL) { blob->set_strings(cbuf->strings()); } - bool saw_first = false; - StubCodeDesc* toprint[1000]; - int toprint_len = 0; - for (StubCodeDesc* cdesc = _last_stub; cdesc != NULL; cdesc = cdesc->_next) { - toprint[toprint_len++] = cdesc; - if (cdesc == _first_stub) { saw_first = true; break; } - } - assert(toprint_len == 0 || saw_first, "must get both first & last"); - // Print in reverse order: - qsort(toprint, toprint_len, sizeof(toprint[0]), compare_cdesc); - for (int i = 0; i < toprint_len; i++) { - StubCodeDesc* cdesc = toprint[i]; - cdesc->print(); - tty->cr(); - Disassembler::decode(cdesc->begin(), cdesc->end()); - tty->cr(); - } } } @@ -118,9 +86,12 @@ void StubCodeGenerator::stub_prolog(StubCodeDesc* cdesc) { } void StubCodeGenerator::stub_epilog(StubCodeDesc* cdesc) { - // default implementation - record the cdesc - if (_first_stub == NULL) _first_stub = cdesc; - _last_stub = cdesc; + if (_print_code) { + cdesc->print(); + tty->cr(); + Disassembler::decode(cdesc->begin(), cdesc->end()); + tty->cr(); + } } diff --git a/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp b/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp index 13bb86e6396..4571e3ae667 100644 --- a/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp +++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp @@ -39,13 +39,11 @@ class StubCodeDesc: public CHeapObj { private: static StubCodeDesc* _list; // the list of all descriptors - static int _count; // length of list static bool _frozen; // determines whether _list modifications are allowed StubCodeDesc* _next; // the next element in the linked list const char* _group; // the group to which the stub code belongs const char* _name; // the name assigned to the stub code - int _index; // serial number assigned to the stub address _begin; // points to the first byte of the stub code (included) address _end; // points to the first byte after the stub code (excluded) @@ -64,8 +62,10 @@ class StubCodeDesc: public CHeapObj { friend class StubCodeGenerator; public: + static StubCodeDesc* first() { return _list; } + static StubCodeDesc* next(StubCodeDesc* desc) { return desc->_next; } + static StubCodeDesc* desc_for(address pc); // returns the code descriptor for the code containing pc or NULL - static StubCodeDesc* desc_for_index(int); // returns the code descriptor for the index or NULL static const char* name_for(address pc); // returns the name of the code containing pc or NULL StubCodeDesc(const char* group, const char* name, address begin, address end = NULL) { @@ -74,7 +74,6 @@ class StubCodeDesc: public CHeapObj { _next = _list; _group = group; _name = name; - _index = ++_count; // (never zero) _begin = begin; _end = end; _list = this; @@ -84,7 +83,6 @@ class StubCodeDesc: public CHeapObj { const char* group() const { return _group; } const char* name() const { return _name; } - int index() const { return _index; } address begin() const { return _begin; } address end() const { return _end; } int size_in_bytes() const { return _end - _begin; } @@ -97,13 +95,12 @@ class StubCodeDesc: public CHeapObj { // Provides utility functions. class StubCodeGenerator: public StackObj { + private: + bool _print_code; + protected: MacroAssembler* _masm; - StubCodeDesc* _first_stub; - StubCodeDesc* _last_stub; - bool _print_code; - public: StubCodeGenerator(CodeBuffer* code, bool print_code = false); ~StubCodeGenerator(); From a026f88a38d044a21f224897a21b3095e7d2f898 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 19 Feb 2016 20:45:26 +0300 Subject: [PATCH 005/129] 8067014: LinearScan::is_sorted significantly slows down fastdebug builds' performance Reviewed-by: vlivanov, shade --- hotspot/src/share/vm/c1/c1_CFGPrinter.hpp | 6 +- hotspot/src/share/vm/c1/c1_LinearScan.cpp | 119 ++++++++++++++-------- hotspot/src/share/vm/c1/c1_LinearScan.hpp | 6 +- 3 files changed, 83 insertions(+), 48 deletions(-) diff --git a/hotspot/src/share/vm/c1/c1_CFGPrinter.hpp b/hotspot/src/share/vm/c1/c1_CFGPrinter.hpp index 1cdde1186b2..00790396214 100644 --- a/hotspot/src/share/vm/c1/c1_CFGPrinter.hpp +++ b/hotspot/src/share/vm/c1/c1_CFGPrinter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,9 @@ // compilation for later analysis. class CFGPrinterOutput; -class IntervalList; +class Interval; + +typedef GrowableArray IntervalList; class CFGPrinter : public AllStatic { private: diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.cpp b/hotspot/src/share/vm/c1/c1_LinearScan.cpp index cda969cb4b8..eb49e97d896 100644 --- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp +++ b/hotspot/src/share/vm/c1/c1_LinearScan.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1434,42 +1434,74 @@ int LinearScan::interval_cmp(Interval** a, Interval** b) { } #ifndef PRODUCT -bool LinearScan::is_sorted(IntervalArray* intervals) { - int from = -1; - int i, j; - for (i = 0; i < intervals->length(); i ++) { - Interval* it = intervals->at(i); - if (it != NULL) { - if (from > it->from()) { - assert(false, ""); - return false; - } - from = it->from(); +int interval_cmp(Interval* const& l, Interval* const& r) { + return l->from() - r->from(); +} + +bool find_interval(Interval* interval, IntervalArray* intervals) { + bool found; + int idx = intervals->find_sorted(interval, found); + + if (!found) { + return false; + } + + int from = interval->from(); + + // The index we've found using binary search is pointing to an interval + // that is defined in the same place as the interval we were looking for. + // So now we have to look around that index and find exact interval. + for (int i = idx; i >= 0; i--) { + if (intervals->at(i) == interval) { + return true; + } + if (intervals->at(i)->from() != from) { + break; } } - // check in both directions if sorted list and unsorted list contain same intervals - for (i = 0; i < interval_count(); i++) { - if (interval_at(i) != NULL) { - int num_found = 0; - for (j = 0; j < intervals->length(); j++) { - if (interval_at(i) == intervals->at(j)) { - num_found++; - } - } - assert(num_found == 1, "lists do not contain same intervals"); + for (int i = idx + 1; i < intervals->length(); i++) { + if (intervals->at(i) == interval) { + return true; + } + if (intervals->at(i)->from() != from) { + break; } } - for (j = 0; j < intervals->length(); j++) { - int num_found = 0; - for (i = 0; i < interval_count(); i++) { - if (interval_at(i) == intervals->at(j)) { - num_found++; - } + + return false; +} + +bool LinearScan::is_sorted(IntervalArray* intervals) { + int from = -1; + int null_count = 0; + + for (int i = 0; i < intervals->length(); i++) { + Interval* it = intervals->at(i); + if (it != NULL) { + assert(from <= it->from(), "Intervals are unordered"); + from = it->from(); + } else { + null_count++; } - assert(num_found == 1, "lists do not contain same intervals"); } + assert(null_count == 0, "Sorted intervals should not contain nulls"); + + null_count = 0; + + for (int i = 0; i < interval_count(); i++) { + Interval* interval = interval_at(i); + if (interval != NULL) { + assert(find_interval(interval, intervals), "Lists do not contain same intervals"); + } else { + null_count++; + } + } + + assert(interval_count() - null_count == intervals->length(), + "Sorted list should contain the same amount of non-NULL intervals as unsorted list"); + return true; } #endif @@ -1536,7 +1568,7 @@ void LinearScan::sort_intervals_before_allocation() { sorted_len++; } } - IntervalArray* sorted_list = new IntervalArray(sorted_len); + IntervalArray* sorted_list = new IntervalArray(sorted_len, sorted_len, NULL); // special sorting algorithm: the original interval-list is almost sorted, // only some intervals are swapped. So this is much faster than a complete QuickSort @@ -1574,8 +1606,8 @@ void LinearScan::sort_intervals_after_allocation() { _needs_full_resort = false; } - IntervalArray* old_list = _sorted_intervals; - IntervalList* new_list = _new_intervals_from_allocation; + IntervalArray* old_list = _sorted_intervals; + IntervalList* new_list = _new_intervals_from_allocation; int old_len = old_list->length(); int new_len = new_list->length(); @@ -1589,7 +1621,8 @@ void LinearScan::sort_intervals_after_allocation() { new_list->sort(interval_cmp); // merge old and new list (both already sorted) into one combined list - IntervalArray* combined_list = new IntervalArray(old_len + new_len); + int combined_list_len = old_len + new_len; + IntervalArray* combined_list = new IntervalArray(combined_list_len, combined_list_len, NULL); int old_idx = 0; int new_idx = 0; @@ -3211,6 +3244,10 @@ void LinearScan::verify_intervals() { has_error = true; } + // special intervals that are created in MoveResolver + // -> ignore them because the range information has no meaning there + if (i1->from() == 1 && i1->to() == 2) continue; + if (i1->first() == Range::end()) { tty->print_cr("Interval %d has no Range", i1->reg_num()); i1->print(); tty->cr(); has_error = true; @@ -3225,18 +3262,13 @@ void LinearScan::verify_intervals() { for (int j = i + 1; j < len; j++) { Interval* i2 = interval_at(j); - if (i2 == NULL) continue; - - // special intervals that are created in MoveResolver - // -> ignore them because the range information has no meaning there - if (i1->from() == 1 && i1->to() == 2) continue; - if (i2->from() == 1 && i2->to() == 2) continue; + if (i2 == NULL || (i2->from() == 1 && i2->to() == 2)) continue; int r1 = i1->assigned_reg(); int r1Hi = i1->assigned_regHi(); int r2 = i2->assigned_reg(); int r2Hi = i2->assigned_regHi(); - if (i1->intersects(i2) && (r1 == r2 || r1 == r2Hi || (r1Hi != any_reg && (r1Hi == r2 || r1Hi == r2Hi)))) { + if ((r1 == r2 || r1 == r2Hi || (r1Hi != any_reg && (r1Hi == r2 || r1Hi == r2Hi))) && i1->intersects(i2)) { tty->print_cr("Intervals %d and %d overlap and have the same register assigned", i1->reg_num(), i2->reg_num()); i1->print(); tty->cr(); i2->print(); tty->cr(); @@ -3429,7 +3461,8 @@ void LinearScan::verify_registers() { void RegisterVerifier::verify(BlockBegin* start) { // setup input registers (method arguments) for first block - IntervalList* input_state = new IntervalList(state_size(), NULL); + int input_state_len = state_size(); + IntervalList* input_state = new IntervalList(input_state_len, input_state_len, NULL); CallingConvention* args = compilation()->frame_map()->incoming_arguments(); for (int n = 0; n < args->length(); n++) { LIR_Opr opr = args->at(n); @@ -3543,7 +3576,7 @@ void RegisterVerifier::process_successor(BlockBegin* block, IntervalList* input_ IntervalList* RegisterVerifier::copy(IntervalList* input_state) { IntervalList* copy_state = new IntervalList(input_state->length()); - copy_state->push_all(input_state); + copy_state->appendAll(input_state); return copy_state; } @@ -5506,7 +5539,7 @@ void LinearScanWalker::split_and_spill_intersecting_intervals(int reg, int regHi IntervalList* processed = _spill_intervals[reg]; for (int i = 0; i < _spill_intervals[regHi]->length(); i++) { Interval* it = _spill_intervals[regHi]->at(i); - if (processed->index_of(it) == -1) { + if (processed->find_from_end(it) == -1) { remove_from_list(it); split_and_spill_interval(it); } diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.hpp b/hotspot/src/share/vm/c1/c1_LinearScan.hpp index 8504cccedcd..7d296e3f674 100644 --- a/hotspot/src/share/vm/c1/c1_LinearScan.hpp +++ b/hotspot/src/share/vm/c1/c1_LinearScan.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,8 +42,8 @@ class LinearScan; class MoveResolver; class Range; -define_array(IntervalArray, Interval*) -define_stack(IntervalList, IntervalArray) +typedef GrowableArray IntervalArray; +typedef GrowableArray IntervalList; define_array(IntervalsArray, IntervalList*) define_stack(IntervalsList, IntervalsArray) From de01af89d88eeb3eb1dfa53e954605057f364d79 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Fri, 19 Feb 2016 11:09:59 +0100 Subject: [PATCH 006/129] 8149655: PPC64: Implement CompactString intrinsics Reviewed-by: goetz, kvn --- hotspot/src/cpu/ppc/vm/globals_ppc.hpp | 7 +- hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp | 552 +++++++++++++++ hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp | 38 +- hotspot/src/cpu/ppc/vm/ppc.ad | 632 +++++++++++++++++- hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp | 25 +- hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp | 20 +- hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp | 7 +- .../string/TestStringIntrinsics2.java | 23 + 8 files changed, 1261 insertions(+), 43 deletions(-) diff --git a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp index 695014fd836..d7bb3970582 100644 --- a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,8 +75,7 @@ define_pd_global(size_t, CMSYoungGenPerWorker, 16*M); // Default max size of CM define_pd_global(uintx, TypeProfileLevel, 111); -// No performance work done here yet. -define_pd_global(bool, CompactStrings, false); +define_pd_global(bool, CompactStrings, true); // Platform dependent flag handling: flags only defined on this platform. #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint) \ diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index e9da9714579..ce9d109dfdd 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -45,6 +45,9 @@ #include "gc/g1/g1SATBCardTableModRefBS.hpp" #include "gc/g1/heapRegion.hpp" #endif // INCLUDE_ALL_GCS +#ifdef COMPILER2 +#include "opto/intrinsicnode.hpp" +#endif #ifdef PRODUCT #define BLOCK_COMMENT(str) // nothing @@ -3168,6 +3171,553 @@ void MacroAssembler::clear_memory_doubleword(Register base_ptr, Register cnt_dwo /////////////////////////////////////////// String intrinsics //////////////////////////////////////////// +#ifdef COMPILER2 +// Intrinsics for CompactStrings + +// Compress char[] to byte[] by compressing 16 bytes at once. +void MacroAssembler::string_compress_16(Register src, Register dst, Register cnt, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, + Label& Lfailure) { + + const Register tmp0 = R0; + assert_different_registers(src, dst, cnt, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5); + Label Lloop, Lslow; + + // Check if cnt >= 8 (= 16 bytes) + lis(tmp1, 0xFF); // tmp1 = 0x00FF00FF00FF00FF + srwi_(tmp2, cnt, 3); + beq(CCR0, Lslow); + ori(tmp1, tmp1, 0xFF); + rldimi(tmp1, tmp1, 32, 0); + mtctr(tmp2); + + // 2x unrolled loop + bind(Lloop); + ld(tmp2, 0, src); // _0_1_2_3 (Big Endian) + ld(tmp4, 8, src); // _4_5_6_7 + + orr(tmp0, tmp2, tmp4); + rldicl(tmp3, tmp2, 6*8, 64-24); // _____1_2 + rldimi(tmp2, tmp2, 2*8, 2*8); // _0_2_3_3 + rldicl(tmp5, tmp4, 6*8, 64-24); // _____5_6 + rldimi(tmp4, tmp4, 2*8, 2*8); // _4_6_7_7 + + andc_(tmp0, tmp0, tmp1); + bne(CCR0, Lfailure); // Not latin1. + addi(src, src, 16); + + rlwimi(tmp3, tmp2, 0*8, 24, 31);// _____1_3 + srdi(tmp2, tmp2, 3*8); // ____0_2_ + rlwimi(tmp5, tmp4, 0*8, 24, 31);// _____5_7 + srdi(tmp4, tmp4, 3*8); // ____4_6_ + + orr(tmp2, tmp2, tmp3); // ____0123 + orr(tmp4, tmp4, tmp5); // ____4567 + + stw(tmp2, 0, dst); + stw(tmp4, 4, dst); + addi(dst, dst, 8); + bdnz(Lloop); + + bind(Lslow); // Fallback to slow version +} + +// Compress char[] to byte[]. cnt must be positive int. +void MacroAssembler::string_compress(Register src, Register dst, Register cnt, Register tmp, Label& Lfailure) { + Label Lloop; + mtctr(cnt); + + bind(Lloop); + lhz(tmp, 0, src); + cmplwi(CCR0, tmp, 0xff); + bgt(CCR0, Lfailure); // Not latin1. + addi(src, src, 2); + stb(tmp, 0, dst); + addi(dst, dst, 1); + bdnz(Lloop); +} + +// Inflate byte[] to char[] by inflating 16 bytes at once. +void MacroAssembler::string_inflate_16(Register src, Register dst, Register cnt, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5) { + const Register tmp0 = R0; + assert_different_registers(src, dst, cnt, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5); + Label Lloop, Lslow; + + // Check if cnt >= 8 + srwi_(tmp2, cnt, 3); + beq(CCR0, Lslow); + lis(tmp1, 0xFF); // tmp1 = 0x00FF00FF + ori(tmp1, tmp1, 0xFF); + mtctr(tmp2); + + // 2x unrolled loop + bind(Lloop); + lwz(tmp2, 0, src); // ____0123 (Big Endian) + lwz(tmp4, 4, src); // ____4567 + addi(src, src, 8); + + rldicl(tmp3, tmp2, 7*8, 64-8); // _______2 + rlwimi(tmp2, tmp2, 3*8, 16, 23);// ____0113 + rldicl(tmp5, tmp4, 7*8, 64-8); // _______6 + rlwimi(tmp4, tmp4, 3*8, 16, 23);// ____4557 + + andc(tmp0, tmp2, tmp1); // ____0_1_ + rlwimi(tmp2, tmp3, 2*8, 0, 23); // _____2_3 + andc(tmp3, tmp4, tmp1); // ____4_5_ + rlwimi(tmp4, tmp5, 2*8, 0, 23); // _____6_7 + + rldimi(tmp2, tmp0, 3*8, 0*8); // _0_1_2_3 + rldimi(tmp4, tmp3, 3*8, 0*8); // _4_5_6_7 + + std(tmp2, 0, dst); + std(tmp4, 8, dst); + addi(dst, dst, 16); + bdnz(Lloop); + + bind(Lslow); // Fallback to slow version +} + +// Inflate byte[] to char[]. cnt must be positive int. +void MacroAssembler::string_inflate(Register src, Register dst, Register cnt, Register tmp) { + Label Lloop; + mtctr(cnt); + + bind(Lloop); + lbz(tmp, 0, src); + addi(src, src, 1); + sth(tmp, 0, dst); + addi(dst, dst, 2); + bdnz(Lloop); +} + +void MacroAssembler::string_compare(Register str1, Register str2, + Register cnt1, Register cnt2, + Register tmp1, Register result, int ae) { + const Register tmp0 = R0, + diff = tmp1; + + assert_different_registers(str1, str2, cnt1, cnt2, tmp0, tmp1, result); + Label Ldone, Lslow, Lloop, Lreturn_diff; + + // Note: Making use of the fact that compareTo(a, b) == -compareTo(b, a) + // we interchange str1 and str2 in the UL case and negate the result. + // Like this, str1 is always latin1 encoded, except for the UU case. + // In addition, we need 0 (or sign which is 0) extend. + + if (ae == StrIntrinsicNode::UU) { + srwi(cnt1, cnt1, 1); + } else { + clrldi(cnt1, cnt1, 32); + } + + if (ae != StrIntrinsicNode::LL) { + srwi(cnt2, cnt2, 1); + } else { + clrldi(cnt2, cnt2, 32); + } + + // See if the lengths are different, and calculate min in cnt1. + // Save diff in case we need it for a tie-breaker. + subf_(diff, cnt2, cnt1); // diff = cnt1 - cnt2 + // if (diff > 0) { cnt1 = cnt2; } + if (VM_Version::has_isel()) { + isel(cnt1, CCR0, Assembler::greater, /*invert*/ false, cnt2); + } else { + Label Lskip; + blt(CCR0, Lskip); + mr(cnt1, cnt2); + bind(Lskip); + } + + // Rename registers + Register chr1 = result; + Register chr2 = tmp0; + + // Compare multiple characters in fast loop (only implemented for same encoding). + int stride1 = 8, stride2 = 8; + if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + int log2_chars_per_iter = (ae == StrIntrinsicNode::LL) ? 3 : 2; + Label Lfastloop, Lskipfast; + + srwi_(tmp0, cnt1, log2_chars_per_iter); + beq(CCR0, Lskipfast); + rldicl(cnt2, cnt1, 0, 64 - log2_chars_per_iter); // Remaining characters. + li(cnt1, 1 << log2_chars_per_iter); // Initialize for failure case: Rescan characters from current iteration. + mtctr(tmp0); + + bind(Lfastloop); + ld(chr1, 0, str1); + ld(chr2, 0, str2); + cmpd(CCR0, chr1, chr2); + bne(CCR0, Lslow); + addi(str1, str1, stride1); + addi(str2, str2, stride2); + bdnz(Lfastloop); + mr(cnt1, cnt2); // Remaining characters. + bind(Lskipfast); + } + + // Loop which searches the first difference character by character. + cmpwi(CCR0, cnt1, 0); + beq(CCR0, Lreturn_diff); + bind(Lslow); + mtctr(cnt1); + + switch (ae) { + case StrIntrinsicNode::LL: stride1 = 1; stride2 = 1; break; + case StrIntrinsicNode::UL: // fallthru (see comment above) + case StrIntrinsicNode::LU: stride1 = 1; stride2 = 2; break; + case StrIntrinsicNode::UU: stride1 = 2; stride2 = 2; break; + default: ShouldNotReachHere(); break; + } + + bind(Lloop); + if (stride1 == 1) { lbz(chr1, 0, str1); } else { lhz(chr1, 0, str1); } + if (stride2 == 1) { lbz(chr2, 0, str2); } else { lhz(chr2, 0, str2); } + subf_(result, chr2, chr1); // result = chr1 - chr2 + bne(CCR0, Ldone); + addi(str1, str1, stride1); + addi(str2, str2, stride2); + bdnz(Lloop); + + // If strings are equal up to min length, return the length difference. + bind(Lreturn_diff); + mr(result, diff); + + // Otherwise, return the difference between the first mismatched chars. + bind(Ldone); + if (ae == StrIntrinsicNode::UL) { + neg(result, result); // Negate result (see note above). + } +} + +void MacroAssembler::array_equals(bool is_array_equ, Register ary1, Register ary2, + Register limit, Register tmp1, Register result, bool is_byte) { + const Register tmp0 = R0; + assert_different_registers(ary1, ary2, limit, tmp0, tmp1, result); + Label Ldone, Lskiploop, Lloop, Lfastloop, Lskipfast; + bool limit_needs_shift = false; + + if (is_array_equ) { + const int length_offset = arrayOopDesc::length_offset_in_bytes(); + const int base_offset = arrayOopDesc::base_offset_in_bytes(is_byte ? T_BYTE : T_CHAR); + + // Return true if the same array. + cmpd(CCR0, ary1, ary2); + beq(CCR0, Lskiploop); + + // Return false if one of them is NULL. + cmpdi(CCR0, ary1, 0); + cmpdi(CCR1, ary2, 0); + li(result, 0); + cror(CCR0, Assembler::equal, CCR1, Assembler::equal); + beq(CCR0, Ldone); + + // Load the lengths of arrays. + lwz(limit, length_offset, ary1); + lwz(tmp0, length_offset, ary2); + + // Return false if the two arrays are not equal length. + cmpw(CCR0, limit, tmp0); + bne(CCR0, Ldone); + + // Load array addresses. + addi(ary1, ary1, base_offset); + addi(ary2, ary2, base_offset); + } else { + limit_needs_shift = !is_byte; + li(result, 0); // Assume not equal. + } + + // Rename registers + Register chr1 = tmp0; + Register chr2 = tmp1; + + // Compare 8 bytes per iteration in fast loop. + const int log2_chars_per_iter = is_byte ? 3 : 2; + + srwi_(tmp0, limit, log2_chars_per_iter + (limit_needs_shift ? 1 : 0)); + beq(CCR0, Lskipfast); + mtctr(tmp0); + + bind(Lfastloop); + ld(chr1, 0, ary1); + ld(chr2, 0, ary2); + addi(ary1, ary1, 8); + addi(ary2, ary2, 8); + cmpd(CCR0, chr1, chr2); + bne(CCR0, Ldone); + bdnz(Lfastloop); + + bind(Lskipfast); + rldicl_(limit, limit, limit_needs_shift ? 64 - 1 : 0, 64 - log2_chars_per_iter); // Remaining characters. + beq(CCR0, Lskiploop); + mtctr(limit); + + // Character by character. + bind(Lloop); + if (is_byte) { + lbz(chr1, 0, ary1); + lbz(chr2, 0, ary2); + addi(ary1, ary1, 1); + addi(ary2, ary2, 1); + } else { + lhz(chr1, 0, ary1); + lhz(chr2, 0, ary2); + addi(ary1, ary1, 2); + addi(ary2, ary2, 2); + } + cmpw(CCR0, chr1, chr2); + bne(CCR0, Ldone); + bdnz(Lloop); + + bind(Lskiploop); + li(result, 1); // All characters are equal. + bind(Ldone); +} + +void MacroAssembler::string_indexof(Register result, Register haystack, Register haycnt, + Register needle, ciTypeArray* needle_values, Register needlecnt, int needlecntval, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, int ae) { + + // Ensure 0=2, bail out otherwise. + // ************************************************************************************************** + + // Compute last haystack addr to use if no match gets found. + clrldi(haycnt, haycnt, 32); // Ensure positive int is valid as 64 bit value. + addi(addr, haystack, -h_csize); // Accesses use pre-increment. + if (needlecntval == 0) { // variable needlecnt + cmpwi(CCR6, needlecnt, 2); + clrldi(needlecnt, needlecnt, 32); // Ensure positive int is valid as 64 bit value. + blt(CCR6, L_TooShort); // Variable needlecnt: handle short needle separately. + } + + if (n_csize == 2) { lwz(n_start, 0, needle); } else { lhz(n_start, 0, needle); } // Load first 2 characters of needle. + + if (needlecntval == 0) { // variable needlecnt + subf(ch1, needlecnt, haycnt); // Last character index to compare is haycnt-needlecnt. + addi(needlecnt, needlecnt, -2); // Rest of needle. + } else { // constant needlecnt + guarantee(needlecntval != 1, "IndexOf with single-character needle must be handled separately"); + assert((needlecntval & 0x7fff) == needlecntval, "wrong immediate"); + addi(ch1, haycnt, -needlecntval); // Last character index to compare is haycnt-needlecnt. + if (needlecntval > 3) { li(needlecnt, needlecntval - 2); } // Rest of needle. + } + + if (h_csize == 2) { slwi(ch1, ch1, 1); } // Scale to number of bytes. + + if (ae ==StrIntrinsicNode::UL) { + srwi(tmp4, n_start, 1*8); // ___0 + rlwimi(n_start, tmp4, 2*8, 0, 23); // _0_1 + } + + add(last_addr, haystack, ch1); // Point to last address to compare (haystack+2*(haycnt-needlecnt)). + + // Main Loop (now we have at least 2 characters). + Label L_OuterLoop, L_InnerLoop, L_FinalCheck, L_Comp1, L_Comp2; + bind(L_OuterLoop); // Search for 1st 2 characters. + Register addr_diff = tmp4; + subf(addr_diff, addr, last_addr); // Difference between already checked address and last address to check. + addi(addr, addr, h_csize); // This is the new address we want to use for comparing. + srdi_(ch2, addr_diff, h_csize); + beq(CCR0, L_FinalCheck); // 2 characters left? + mtctr(ch2); // num of characters / 2 + bind(L_InnerLoop); // Main work horse (2x unrolled search loop) + if (h_csize == 2) { // Load 2 characters of haystack (ignore alignment). + lwz(ch1, 0, addr); + lwz(ch2, 2, addr); + } else { + lhz(ch1, 0, addr); + lhz(ch2, 1, addr); + } + cmpw(CCR0, ch1, n_start); // Compare 2 characters (1 would be sufficient but try to reduce branches to CompLoop). + cmpw(CCR1, ch2, n_start); + beq(CCR0, L_Comp1); // Did we find the needle start? + beq(CCR1, L_Comp2); + addi(addr, addr, 2 * h_csize); + bdnz(L_InnerLoop); + bind(L_FinalCheck); + andi_(addr_diff, addr_diff, h_csize); // Remaining characters not covered by InnerLoop: (num of characters) & 1. + beq(CCR0, L_NotFound); + if (h_csize == 2) { lwz(ch1, 0, addr); } else { lhz(ch1, 0, addr); } // One position left at which we have to compare. + cmpw(CCR1, ch1, n_start); + beq(CCR1, L_Comp1); + bind(L_NotFound); + li(result, -1); // not found + b(L_End); + + // ************************************************************************************************** + // Special Case: unfortunately, the variable needle case can be called with needlecnt<2 + // ************************************************************************************************** + if (needlecntval == 0) { // We have to handle these cases separately. + Label L_OneCharLoop; + bind(L_TooShort); + mtctr(haycnt); + if (n_csize == 2) { lhz(n_start, 0, needle); } else { lbz(n_start, 0, needle); } // First character of needle + bind(L_OneCharLoop); + if (h_csize == 2) { lhzu(ch1, 2, addr); } else { lbzu(ch1, 1, addr); } + cmpw(CCR1, ch1, n_start); + beq(CCR1, L_Found); // Did we find the one character needle? + bdnz(L_OneCharLoop); + li(result, -1); // Not found. + b(L_End); + } + + // ************************************************************************************************** + // Regular Case Part II: compare rest of needle (first 2 characters have been compared already) + // ************************************************************************************************** + + // Compare the rest + bind(L_Comp2); + addi(addr, addr, h_csize); // First comparison has failed, 2nd one hit. + bind(L_Comp1); // Addr points to possible needle start. + if (needlecntval != 2) { // Const needlecnt==2? + if (needlecntval != 3) { + if (needlecntval == 0) { beq(CCR6, L_Found); } // Variable needlecnt==2? + Register n_ind = tmp4, + h_ind = n_ind; + li(n_ind, 2 * n_csize); // First 2 characters are already compared, use index 2. + mtctr(needlecnt); // Decremented by 2, still > 0. + Label L_CompLoop; + bind(L_CompLoop); + if (ae ==StrIntrinsicNode::UL) { + h_ind = ch1; + sldi(h_ind, n_ind, 1); + } + if (n_csize == 2) { lhzx(ch2, needle, n_ind); } else { lbzx(ch2, needle, n_ind); } + if (h_csize == 2) { lhzx(ch1, addr, h_ind); } else { lbzx(ch1, addr, h_ind); } + cmpw(CCR1, ch1, ch2); + bne(CCR1, L_OuterLoop); + addi(n_ind, n_ind, n_csize); + bdnz(L_CompLoop); + } else { // No loop required if there's only one needle character left. + if (n_csize == 2) { lhz(ch2, 2 * 2, needle); } else { lbz(ch2, 2 * 1, needle); } + if (h_csize == 2) { lhz(ch1, 2 * 2, addr); } else { lbz(ch1, 2 * 1, addr); } + cmpw(CCR1, ch1, ch2); + bne(CCR1, L_OuterLoop); + } + } + // Return index ... + bind(L_Found); + subf(result, haystack, addr); // relative to haystack, ... + if (h_csize == 2) { srdi(result, result, 1); } // in characters. + bind(L_End); +} // string_indexof + +void MacroAssembler::string_indexof_char(Register result, Register haystack, Register haycnt, + Register needle, jchar needleChar, Register tmp1, Register tmp2, bool is_byte) { + assert_different_registers(haystack, haycnt, needle, tmp1, tmp2); + + Label L_InnerLoop, L_FinalCheck, L_Found1, L_Found2, L_NotFound, L_End; + Register addr = tmp1, + ch1 = tmp2, + ch2 = R0; + + const int h_csize = is_byte ? 1 : 2; + +//4: + srwi_(tmp2, haycnt, 1); // Shift right by exact_log2(UNROLL_FACTOR). + mr(addr, haystack); + beq(CCR0, L_FinalCheck); + mtctr(tmp2); // Move to count register. +//8: + bind(L_InnerLoop); // Main work horse (2x unrolled search loop). + if (!is_byte) { + lhz(ch1, 0, addr); + lhz(ch2, 2, addr); + } else { + lbz(ch1, 0, addr); + lbz(ch2, 1, addr); + } + (needle != R0) ? cmpw(CCR0, ch1, needle) : cmplwi(CCR0, ch1, (unsigned int)needleChar); + (needle != R0) ? cmpw(CCR1, ch2, needle) : cmplwi(CCR1, ch2, (unsigned int)needleChar); + beq(CCR0, L_Found1); // Did we find the needle? + beq(CCR1, L_Found2); + addi(addr, addr, 2 * h_csize); + bdnz(L_InnerLoop); +//16: + bind(L_FinalCheck); + andi_(R0, haycnt, 1); + beq(CCR0, L_NotFound); + if (!is_byte) { lhz(ch1, 0, addr); } else { lbz(ch1, 0, addr); } // One position left at which we have to compare. + (needle != R0) ? cmpw(CCR1, ch1, needle) : cmplwi(CCR1, ch1, (unsigned int)needleChar); + beq(CCR1, L_Found1); +//21: + bind(L_NotFound); + li(result, -1); // Not found. + b(L_End); + + bind(L_Found2); + addi(addr, addr, h_csize); +//24: + bind(L_Found1); // Return index ... + subf(result, haystack, addr); // relative to haystack, ... + if (!is_byte) { srdi(result, result, 1); } // in characters. + bind(L_End); +} // string_indexof_char + + +void MacroAssembler::has_negatives(Register src, Register cnt, Register result, + Register tmp1, Register tmp2) { + const Register tmp0 = R0; + assert_different_registers(src, result, cnt, tmp0, tmp1, tmp2); + Label Lfastloop, Lslow, Lloop, Lnoneg, Ldone; + + // Check if cnt >= 8 (= 16 bytes) + lis(tmp1, (int)(short)0x8080); // tmp1 = 0x8080808080808080 + srwi_(tmp2, cnt, 4); + li(result, 1); // Assume there's a negative byte. + beq(CCR0, Lslow); + ori(tmp1, tmp1, 0x8080); + rldimi(tmp1, tmp1, 32, 0); + mtctr(tmp2); + + // 2x unrolled loop + bind(Lfastloop); + ld(tmp2, 0, src); + ld(tmp0, 8, src); + + orr(tmp0, tmp2, tmp0); + + and_(tmp0, tmp0, tmp1); + bne(CCR0, Ldone); // Found negative byte. + addi(src, src, 16); + + bdnz(Lfastloop); + + bind(Lslow); // Fallback to slow version + rldicl_(tmp0, cnt, 0, 64-4); + beq(CCR0, Lnoneg); + mtctr(tmp0); + bind(Lloop); + lbz(tmp0, 0, src); + addi(src, src, 1); + andi_(tmp0, tmp0, 0x80); + bne(CCR0, Ldone); // Found negative byte. + bdnz(Lloop); + bind(Lnoneg); + li(result, 0); + + bind(Ldone); +} + + +// Intrinsics for non-CompactStrings + // Search for a single jchar in an jchar[]. // // Assumes that result differs from all other registers. @@ -3613,6 +4163,8 @@ void MacroAssembler::char_arrays_equalsImm(Register str1_reg, Register str2_reg, bind(Ldone_false); } +#endif // Compiler2 + // Helpers for Intrinsic Emitters // // Revert the byte order of a 32bit value in a register diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp index 925e73a82d1..53a269a83c2 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -679,6 +679,39 @@ class MacroAssembler: public Assembler { void clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp = R0); +#ifdef COMPILER2 + // Intrinsics for CompactStrings + // Compress char[] to byte[] by compressing 16 bytes at once. + void string_compress_16(Register src, Register dst, Register cnt, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, + Label& Lfailure); + + // Compress char[] to byte[]. cnt must be positive int. + void string_compress(Register src, Register dst, Register cnt, Register tmp, Label& Lfailure); + + // Inflate byte[] to char[] by inflating 16 bytes at once. + void string_inflate_16(Register src, Register dst, Register cnt, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5); + + // Inflate byte[] to char[]. cnt must be positive int. + void string_inflate(Register src, Register dst, Register cnt, Register tmp); + + void string_compare(Register str1, Register str2, Register cnt1, Register cnt2, + Register tmp1, Register result, int ae); + + void array_equals(bool is_array_equ, Register ary1, Register ary2, + Register limit, Register tmp1, Register result, bool is_byte); + + void string_indexof(Register result, Register haystack, Register haycnt, + Register needle, ciTypeArray* needle_values, Register needlecnt, int needlecntval, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, int ae); + + void string_indexof_char(Register result, Register haystack, Register haycnt, + Register needle, jchar needleChar, Register tmp1, Register tmp2, bool is_byte); + + void has_negatives(Register src, Register cnt, Register result, Register tmp1, Register tmp2); + + // Intrinsics for non-CompactStrings // Needle of length 1. void string_indexof_1(Register result, Register haystack, Register haycnt, Register needle, jchar needleChar, @@ -694,6 +727,7 @@ class MacroAssembler: public Assembler { Register tmp5_reg); void char_arrays_equalsImm(Register str1_reg, Register str2_reg, int cntval, Register result_reg, Register tmp1_reg, Register tmp2_reg); +#endif // Emitters for BigInteger.multiplyToLen intrinsic. inline void multiply64(Register dest_hi, Register dest_lo, diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index e9dfa9c5bf1..df119f8bdf1 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -1,6 +1,6 @@ // // Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2012, 2015 SAP SE. All rights reserved. +// Copyright (c) 2012, 2016 SAP SE. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -2024,13 +2024,13 @@ const bool Matcher::match_rule_supported(int opcode) { return (UsePopCountInstruction && VM_Version::has_popcntw()); case Op_StrComp: - return SpecialStringCompareTo && !CompactStrings; + return SpecialStringCompareTo; case Op_StrEquals: - return SpecialStringEquals && !CompactStrings; + return SpecialStringEquals; case Op_StrIndexOf: - return SpecialStringIndexOf && !CompactStrings; + return SpecialStringIndexOf; case Op_StrIndexOfChar: - return SpecialStringIndexOf && !CompactStrings; + return SpecialStringIndexOf; } return true; // Per default match rules are supported. @@ -11022,6 +11022,584 @@ instruct inlineCallClearArray(rarg1RegL cnt, rarg2RegP base, Universe dummy, reg ins_pipe(pipe_class_default); %} +instruct string_compareL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp); + ins_cost(300); + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + $tmp$$Register, + $result$$Register, StrIntrinsicNode::LL); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_compareU(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp); + ins_cost(300); + format %{ "String Compare char[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + $tmp$$Register, + $result$$Register, StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_compareLU(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp); + ins_cost(300); + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + $tmp$$Register, + $result$$Register, StrIntrinsicNode::LU); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_compareUL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp); + ins_cost(300); + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_compare($str2$$Register, $str1$$Register, + $cnt2$$Register, $cnt1$$Register, + $tmp$$Register, + $result$$Register, StrIntrinsicNode::UL); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_equalsL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP tmp, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "String Equals byte[] $str1,$str2,$cnt -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ array_equals(false, $str1$$Register, $str2$$Register, + $cnt$$Register, $tmp$$Register, + $result$$Register, true /* byte */); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_equalsU(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP tmp, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "String Equals char[] $str1,$str2,$cnt -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ array_equals(false, $str1$$Register, $str2$$Register, + $cnt$$Register, $tmp$$Register, + $result$$Register, false /* byte */); + %} + ins_pipe(pipe_class_default); +%} + +instruct array_equalsB(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result, + iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR0 cr1) %{ + predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (AryEq ary1 ary2)); + effect(TEMP_DEF result, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0, KILL cr1); + ins_cost(300); + format %{ "Array Equals $ary1,$ary2 -> $result \t// KILL $tmp1,$tmp2" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ array_equals(true, $ary1$$Register, $ary2$$Register, + $tmp1$$Register, $tmp2$$Register, + $result$$Register, true /* byte */); + %} + ins_pipe(pipe_class_default); +%} + +instruct array_equalsC(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result, + iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR0 cr1) %{ + predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (AryEq ary1 ary2)); + effect(TEMP_DEF result, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0, KILL cr1); + ins_cost(300); + format %{ "Array Equals $ary1,$ary2 -> $result \t// KILL $tmp1,$tmp2" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ array_equals(true, $ary1$$Register, $ary2$$Register, + $tmp1$$Register, $tmp2$$Register, + $result$$Register, false /* byte */); + %} + ins_pipe(pipe_class_default); +%} + +instruct indexOf_imm1_char_U(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + immP needleImm, immL offsetImm, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm))); + effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU); + ins_cost(150); + + format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]" + "-> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %} + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + immPOper *needleOper = (immPOper *)$needleImm; + const TypeOopPtr *t = needleOper->type()->isa_oopptr(); + ciTypeArray* needle_values = t->const_oop()->as_type_array(); // Pointer to live char * + jchar chr; +#ifdef VM_LITTLE_ENDIAN + chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(0).as_byte()); +#else + chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(1).as_byte()); +#endif + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_char_L(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + immP needleImm, immL offsetImm, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm))); + effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL); + ins_cost(150); + + format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]" + "-> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %} + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + immPOper *needleOper = (immPOper *)$needleImm; + const TypeOopPtr *t = needleOper->type()->isa_oopptr(); + ciTypeArray* needle_values = t->const_oop()->as_type_array(); // Pointer to live char * + jchar chr = (jchar)needle_values->element_value(0).as_byte(); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, true /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_char_UL(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + immP needleImm, immL offsetImm, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm))); + effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL); + ins_cost(150); + + format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]" + "-> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %} + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + immPOper *needleOper = (immPOper *)$needleImm; + const TypeOopPtr *t = needleOper->type()->isa_oopptr(); + ciTypeArray* needle_values = t->const_oop()->as_type_array(); // Pointer to live char * + jchar chr = (jchar)needle_values->element_value(0).as_byte(); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_U(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + rscratch2RegP needle, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL needle, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(180); + + format %{ "String IndexOf SCL1 $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $needle, $tmp1, $tmp2, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + guarantee(needle_values, "sanity"); + jchar chr; +#ifdef VM_LITTLE_ENDIAN + chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(0).as_byte()); +#else + chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(1).as_byte()); +#endif + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_L(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + rscratch2RegP needle, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL needle, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(180); + + format %{ "String IndexOf SCL1 $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $needle, $tmp1, $tmp2, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + guarantee(needle_values, "sanity"); + jchar chr = (jchar)needle_values->element_value(0).as_byte(); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, true /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_UL(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + rscratch2RegP needle, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL needle, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(180); + + format %{ "String IndexOf SCL1 $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $needle, $tmp1, $tmp2, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + guarantee(needle_values, "sanity"); + jchar chr = (jchar)needle_values->element_value(0).as_byte(); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOfChar_U(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + iRegIsrc ch, iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOfChar (Binary haystack haycnt) ch)); + effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + predicate(CompactStrings); + ins_cost(180); + + format %{ "String IndexOfChar $haystack[0..$haycnt], $ch" + " -> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + $ch$$Register, 0 /* this is not used if the character is already in a register */, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm_U(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, + iRegPsrc needle, uimmI15 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(250); + + format %{ "String IndexOf SCL $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $tmp1, $tmp2, $tmp3, $tmp4, $tmp5, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, needle_values, $tmp5$$Register, $needlecntImm$$constant, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm_L(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, + iRegPsrc needle, uimmI15 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(250); + + format %{ "String IndexOf SCL $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $tmp1, $tmp2, $tmp3, $tmp4, $tmp5, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, needle_values, $tmp5$$Register, $needlecntImm$$constant, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::LL); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm_UL(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, + iRegPsrc needle, uimmI15 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(250); + + format %{ "String IndexOf SCL $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $tmp1, $tmp2, $tmp3, $tmp4, $tmp5, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, needle_values, $tmp5$$Register, $needlecntImm$$constant, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UL); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_U(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iRegPsrc needle, rscratch2RegI needlecnt, + iRegLdst tmp1, iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt))); + effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/ + TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU); + ins_cost(300); + + format %{ "String IndexOf $haystack[0..$haycnt], $needle[0..$needlecnt]" + " -> $result \t// KILL $haycnt, $needlecnt, $tmp1, $tmp2, $tmp3, $tmp4, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant. + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_L(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iRegPsrc needle, rscratch2RegI needlecnt, + iRegLdst tmp1, iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt))); + effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/ + TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL); + ins_cost(300); + + format %{ "String IndexOf $haystack[0..$haycnt], $needle[0..$needlecnt]" + " -> $result \t// KILL $haycnt, $needlecnt, $tmp1, $tmp2, $tmp3, $tmp4, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant. + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::LL); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_UL(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iRegPsrc needle, rscratch2RegI needlecnt, + iRegLdst tmp1, iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt))); + effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/ + TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL); + ins_cost(300); + + format %{ "String IndexOf $haystack[0..$haycnt], $needle[0..$needlecnt]" + " -> $result \t// KILL $haycnt, $needlecnt, $tmp1, $tmp2, $tmp3, $tmp4, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant. + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UL); + %} + ins_pipe(pipe_class_compare); +%} + +// char[] to byte[] compression +instruct string_compress(rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegIdst result, iRegLdst tmp1, + iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, iRegLdst tmp5, regCTR ctr, flagsRegCR0 cr0) %{ + match(Set result (StrCompressedCopy src (Binary dst len))); + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, + USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "String Compress $src,$dst,$len -> $result \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Label Lskip, Ldone; + __ li($result$$Register, 0); + __ string_compress_16($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register, + $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register, Ldone); + __ rldicl_($tmp1$$Register, $len$$Register, 0, 64-3); // Remaining characters. + __ beq(CCR0, Lskip); + __ string_compress($src$$Register, $dst$$Register, $tmp1$$Register, $tmp2$$Register, Ldone); + __ bind(Lskip); + __ mr($result$$Register, $len$$Register); + __ bind(Ldone); + %} + ins_pipe(pipe_class_default); +%} + +// byte[] to char[] inflation +instruct string_inflate(Universe dummy, rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegLdst tmp1, + iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, iRegLdst tmp5, regCTR ctr, flagsRegCR0 cr0) %{ + match(Set dummy (StrInflatedCopy src (Binary dst len))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "String Inflate $src,$dst,$len \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Label Ldone; + __ string_inflate_16($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register, + $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register); + __ rldicl_($tmp1$$Register, $len$$Register, 0, 64-3); // Remaining characters. + __ beq(CCR0, Ldone); + __ string_inflate($src$$Register, $dst$$Register, $tmp1$$Register, $tmp2$$Register); + __ bind(Ldone); + %} + ins_pipe(pipe_class_default); +%} + +// StringCoding.java intrinsics +instruct has_negatives(rarg1RegP ary1, iRegIsrc len, iRegIdst result, iRegLdst tmp1, iRegLdst tmp2, + regCTR ctr, flagsRegCR0 cr0) +%{ + match(Set result (HasNegatives ary1 len)); + effect(TEMP_DEF result, USE_KILL ary1, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "has negatives byte[] $ary1,$len -> $result \t// KILL $tmp1, $tmp2" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ has_negatives($ary1$$Register, $len$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register); + %} + ins_pipe(pipe_class_default); +%} + +// encode char[] to byte[] in ISO_8859_1 +instruct encode_iso_array(rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegIdst result, iRegLdst tmp1, + iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, iRegLdst tmp5, regCTR ctr, flagsRegCR0 cr0) %{ + match(Set result (EncodeISOArray src (Binary dst len))); + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, + USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "Encode array $src,$dst,$len -> $result \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Label Lslow, Lfailure1, Lfailure2, Ldone; + __ string_compress_16($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register, + $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register, Lfailure1); + __ rldicl_($result$$Register, $len$$Register, 0, 64-3); // Remaining characters. + __ beq(CCR0, Ldone); + __ bind(Lslow); + __ string_compress($src$$Register, $dst$$Register, $result$$Register, $tmp2$$Register, Lfailure2); + __ li($result$$Register, 0); + __ b(Ldone); + + __ bind(Lfailure1); + __ mr($result$$Register, $len$$Register); + __ mfctr($tmp1$$Register); + __ rldimi_($result$$Register, $tmp1$$Register, 3, 0); // Remaining characters. + __ beq(CCR0, Ldone); + __ b(Lslow); + + __ bind(Lfailure2); + __ mfctr($result$$Register); // Remaining characters. + + __ bind(Ldone); + __ subf($result$$Register, $result$$Register, $len$$Register); + %} + ins_pipe(pipe_class_default); +%} + + // String_IndexOf for needle of length 1. // // Match needle into immediate operands: no loadConP node needed. Saves one @@ -11060,11 +11638,11 @@ instruct string_indexOf_imm1_char(iRegIdst result, iRegPsrc haystack, iRegIsrc h if (java_lang_String::has_coder_field()) { // New compact strings byte array strings #ifdef VM_LITTLE_ENDIAN - chr = (((jchar)needle_values->element_value(1).as_byte()) << 8) | - (jchar)needle_values->element_value(0).as_byte(); + chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(0).as_byte()); #else - chr = (((jchar)needle_values->element_value(0).as_byte()) << 8) | - (jchar)needle_values->element_value(1).as_byte(); + chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(1).as_byte()); #endif } else { // Old char array strings @@ -11115,11 +11693,11 @@ instruct string_indexOf_imm1(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt if (java_lang_String::has_coder_field()) { // New compact strings byte array strings #ifdef VM_LITTLE_ENDIAN - chr = (((jchar)needle_values->element_value(1).as_byte()) << 8) | - (jchar)needle_values->element_value(0).as_byte(); + chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(0).as_byte()); #else - chr = (((jchar)needle_values->element_value(0).as_byte()) << 8) | - (jchar)needle_values->element_value(1).as_byte(); + chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(1).as_byte()); #endif } else { // Old char array strings @@ -11321,6 +11899,20 @@ instruct minI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{ %} %} +instruct minI_reg_reg_isel(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ + match(Set dst (MinI src1 src2)); + effect(KILL cr0); + predicate(VM_Version::has_isel()); + ins_cost(DEFAULT_COST*2); + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ cmpw(CCR0, $src1$$Register, $src2$$Register); + __ isel($dst$$Register, CCR0, Assembler::less, /*invert*/false, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_class_default); +%} + instruct maxI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{ match(Set dst (MaxI src1 src2)); ins_cost(DEFAULT_COST*6); @@ -11341,6 +11933,20 @@ instruct maxI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{ %} %} +instruct maxI_reg_reg_isel(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ + match(Set dst (MaxI src1 src2)); + effect(KILL cr0); + predicate(VM_Version::has_isel()); + ins_cost(DEFAULT_COST*2); + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ cmpw(CCR0, $src1$$Register, $src2$$Register); + __ isel($dst$$Register, CCR0, Assembler::greater, /*invert*/false, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_class_default); +%} + //---------- Population Count Instructions ------------------------------------ // Popcnt for Power7. diff --git a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp index c3f6922fe2d..85a83c8179b 100644 --- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp @@ -2609,9 +2609,7 @@ class StubGenerator: public StubCodeGenerator { * R5_ARG3 - int length (of buffer) * * scratch: - * R6_ARG4 - crc table address - * R7_ARG5 - tmp1 - * R8_ARG6 - tmp2 + * R2, R6-R12 * * Ouput: * R3_RET - int crc result @@ -2623,22 +2621,25 @@ class StubGenerator: public StubCodeGenerator { address start = __ function_entry(); // Remember stub start address (is rtn value). // arguments to kernel_crc32: - Register crc = R3_ARG1; // Current checksum, preset by caller or result from previous call. - Register data = R4_ARG2; // source byte array - Register dataLen = R5_ARG3; // #bytes to process - Register table = R6_ARG4; // crc table address + const Register crc = R3_ARG1; // Current checksum, preset by caller or result from previous call. + const Register data = R4_ARG2; // source byte array + const Register dataLen = R5_ARG3; // #bytes to process + const Register table = R6_ARG4; // crc table address - Register t0 = R9; // work reg for kernel* emitters - Register t1 = R10; // work reg for kernel* emitters - Register t2 = R11; // work reg for kernel* emitters - Register t3 = R12; // work reg for kernel* emitters + const Register t0 = R2; + const Register t1 = R7; + const Register t2 = R8; + const Register t3 = R9; + const Register tc0 = R10; + const Register tc1 = R11; + const Register tc2 = R12; BLOCK_COMMENT("Stub body {"); assert_different_registers(crc, data, dataLen, table); StubRoutines::ppc64::generate_load_crc_table_addr(_masm, table); - __ kernel_crc32_1byte(crc, data, dataLen, table, t0, t1, t2, t3); + __ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, table); BLOCK_COMMENT("return"); __ mr_if_needed(R3_RET, crc); // Updated crc is function result. No copying required (R3_ARG1 == R3_RET). diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp index 51bc85d869d..63c0e30a913 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ void VM_Version::initialize() { // If PowerArchitecturePPC64 hasn't been specified explicitly determine from features. if (FLAG_IS_DEFAULT(PowerArchitecturePPC64)) { - if (VM_Version::has_tcheck() && VM_Version::has_lqarx()) { + if (VM_Version::has_lqarx()) { FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 8); } else if (VM_Version::has_popcntw()) { FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 7); @@ -68,8 +68,7 @@ void VM_Version::initialize() { bool PowerArchitecturePPC64_ok = false; switch (PowerArchitecturePPC64) { - case 8: if (!VM_Version::has_tcheck() ) break; - if (!VM_Version::has_lqarx() ) break; + case 8: if (!VM_Version::has_lqarx() ) break; case 7: if (!VM_Version::has_popcntw()) break; case 6: if (!VM_Version::has_cmpb() ) break; case 5: if (!VM_Version::has_popcntb()) break; @@ -80,7 +79,7 @@ void VM_Version::initialize() { UINTX_FORMAT " on this machine", PowerArchitecturePPC64); // Power 8: Configure Data Stream Control Register. - if (PowerArchitecturePPC64 >= 8) { + if (has_mfdscr()) { config_dscr(); } @@ -112,7 +111,7 @@ void VM_Version::initialize() { // Create and print feature-string. char buf[(num_features+1) * 16]; // Max 16 chars per feature. jio_snprintf(buf, sizeof(buf), - "ppc64%s%s%s%s%s%s%s%s%s%s%s%s", + "ppc64%s%s%s%s%s%s%s%s%s%s%s%s%s", (has_fsqrt() ? " fsqrt" : ""), (has_isel() ? " isel" : ""), (has_lxarxeh() ? " lxarxeh" : ""), @@ -125,7 +124,8 @@ void VM_Version::initialize() { (has_lqarx() ? " lqarx" : ""), (has_vcipher() ? " vcipher" : ""), (has_vpmsumb() ? " vpmsumb" : ""), - (has_tcheck() ? " tcheck" : "") + (has_tcheck() ? " tcheck" : ""), + (has_mfdscr() ? " mfdscr" : "") // Make sure number of %s matches num_features! ); _features_string = os::strdup(buf); @@ -610,6 +610,7 @@ void VM_Version::determine_features() { a->vcipher(VR0, VR1, VR2); // code[10] -> vcipher a->vpmsumb(VR0, VR1, VR2); // code[11] -> vpmsumb a->tcheck(0); // code[12] -> tcheck + a->mfdscr(R0); // code[13] -> mfdscr a->blr(); // Emit function to set one cache line to zero. Emit function descriptor and get pointer to it. @@ -657,6 +658,7 @@ void VM_Version::determine_features() { if (code[feature_cntr++]) features |= vcipher_m; if (code[feature_cntr++]) features |= vpmsumb_m; if (code[feature_cntr++]) features |= tcheck_m; + if (code[feature_cntr++]) features |= mfdscr_m; // Print the detection code. if (PrintAssembly) { @@ -670,8 +672,6 @@ void VM_Version::determine_features() { // Power 8: Configure Data Stream Control Register. void VM_Version::config_dscr() { - assert(has_tcheck(), "Only execute on Power 8 or later!"); - // 7 InstWords for each call (function descriptor + blr instruction). const int code_size = (2+2*7)*BytesPerInstWord; diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp index 46fdd6b6470..fccb4e21874 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ protected: vcipher, vpmsumb, tcheck, + mfdscr, num_features // last entry to count features }; enum Feature_Flag_Set { @@ -62,6 +63,7 @@ protected: vcipher_m = (1 << vcipher), vpmsumb_m = (1 << vpmsumb), tcheck_m = (1 << tcheck ), + mfdscr_m = (1 << mfdscr ), all_features_m = (unsigned long)-1 }; @@ -94,6 +96,7 @@ public: static bool has_vcipher() { return (_features & vcipher_m) != 0; } static bool has_vpmsumb() { return (_features & vpmsumb_m) != 0; } static bool has_tcheck() { return (_features & tcheck_m) != 0; } + static bool has_mfdscr() { return (_features & mfdscr_m) != 0; } // Assembler testing static void allow_all(); diff --git a/hotspot/test/compiler/intrinsics/string/TestStringIntrinsics2.java b/hotspot/test/compiler/intrinsics/string/TestStringIntrinsics2.java index a59e412bc96..7bba5308971 100644 --- a/hotspot/test/compiler/intrinsics/string/TestStringIntrinsics2.java +++ b/hotspot/test/compiler/intrinsics/string/TestStringIntrinsics2.java @@ -494,6 +494,29 @@ public class TestStringIntrinsics2 { return s.indexOf("1"); } + static String text1UTF16 = "A" + "\u05d0" + "\u05d1" + "B"; + + @Test(role = Role.TEST_ENTRY) + public static void test_indexOf_immUTF16() { + assertEquals( 3, indexOf_imm1Latin1_needle(text1UTF16), "test_indexOf_immUTF16"); + assertEquals( 1, indexOf_imm1UTF16_needle(text1UTF16), "test_indexOf_immUTF16"); + assertEquals( 1, indexOf_immUTF16_needle(text1UTF16), "test_indexOf_immUTF16"); + } + + @Test(role = Role.TEST_HELPER, compileAt = 4, warmup = 1, warmupArgs = { "A" + "\u05d0" + "\u05d1" + "B" }) + static int indexOf_imm1Latin1_needle(String s) { + return s.indexOf("B"); + } + + @Test(role = Role.TEST_HELPER, compileAt = 4, warmup = 1, warmupArgs = { "A" + "\u05d0" + "\u05d1" + "B" }) + static int indexOf_imm1UTF16_needle(String s) { + return s.indexOf("\u05d0"); + } + + @Test(role = Role.TEST_HELPER, compileAt = 4, warmup = 1, warmupArgs = { "A" + "\u05d0" + "\u05d1" + "B" }) + static int indexOf_immUTF16_needle(String s) { + return s.indexOf("\u05d0" + "\u05d1"); + } @Test(role = Role.TEST_HELPER, compileAt = 4, warmup = 1, warmupArgs = { "abc", "abcd" }) public static int asmStringCompareTo(String a, String b) { From 30e4522d2fef451699796ab994681a0e3ca9c0ad Mon Sep 17 00:00:00 2001 From: Konstantin Shefov Date: Sat, 20 Feb 2016 11:44:14 +0300 Subject: [PATCH 007/129] 8141616: Add new methods to the java Whitebox API Reviewed-by: kvn, dpochepk --- hotspot/src/share/vm/prims/whitebox.cpp | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index 51750b8338e..407d7249125 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -34,6 +34,7 @@ #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" #include "memory/universe.hpp" +#include "oops/constantPool.hpp" #include "oops/oop.inline.hpp" #include "prims/wbtestmethods/parserTests.hpp" #include "prims/whitebox.hpp" @@ -1305,6 +1306,38 @@ WB_ENTRY(jlong, WB_GetConstantPool(JNIEnv* env, jobject wb, jclass klass)) return (jlong) ikh->constants(); WB_END +WB_ENTRY(jint, WB_GetConstantPoolCacheIndexTag(JNIEnv* env, jobject wb)) + return ConstantPool::CPCACHE_INDEX_TAG; +WB_END + +WB_ENTRY(jint, WB_GetConstantPoolCacheLength(JNIEnv* env, jobject wb, jclass klass)) + instanceKlassHandle ikh(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + ConstantPool* cp = ikh->constants(); + if (cp->cache() == NULL) { + return -1; + } + return cp->cache()->length(); +WB_END + +WB_ENTRY(jint, WB_ConstantPoolRemapInstructionOperandFromCache(JNIEnv* env, jobject wb, jclass klass, jint index)) + instanceKlassHandle ikh(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + ConstantPool* cp = ikh->constants(); + if (cp->cache() == NULL) { + THROW_MSG_0(vmSymbols::java_lang_IllegalStateException(), "Constant pool does not have a cache"); + } + jint cpci = index; + jint cpciTag = ConstantPool::CPCACHE_INDEX_TAG; + if (cpciTag > cpci || cpci >= cp->cache()->length() + cpciTag) { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Constant pool cache index is out of range"); + } + jint cpi = cp->remap_instruction_operand_from_cache(cpci); + return cpi; +WB_END + +WB_ENTRY(jint, WB_ConstantPoolEncodeIndyIndex(JNIEnv* env, jobject wb, jint index)) + return ConstantPool::encode_invokedynamic_index(index); +WB_END + WB_ENTRY(void, WB_ClearInlineCaches(JNIEnv* env, jobject wb)) VM_ClearICs clear_ics; VMThread::execute(&clear_ics); @@ -1620,6 +1653,12 @@ static JNINativeMethod methods[] = { {CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated }, {CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint }, {CC"getConstantPool0", CC"(Ljava/lang/Class;)J", (void*)&WB_GetConstantPool }, + {CC"getConstantPoolCacheIndexTag0", CC"()I", (void*)&WB_GetConstantPoolCacheIndexTag}, + {CC"getConstantPoolCacheLength0", CC"(Ljava/lang/Class;)I", (void*)&WB_GetConstantPoolCacheLength}, + {CC"remapInstructionOperandFromCPCache0", + CC"(Ljava/lang/Class;I)I", (void*)&WB_ConstantPoolRemapInstructionOperandFromCache}, + {CC"encodeConstantPoolIndyIndex0", + CC"(I)I", (void*)&WB_ConstantPoolEncodeIndyIndex}, {CC"getMethodBooleanOption", CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)Ljava/lang/Boolean;", (void*)&WB_GetMethodBooleaneOption}, From ac6fe07b0509bd72b2821b9b8926dfc3759e4100 Mon Sep 17 00:00:00 2001 From: Konstantin Shefov Date: Sat, 20 Feb 2016 11:49:02 +0300 Subject: [PATCH 008/129] 8141618: Change JVMCI compilerToVM constant pool tests to support CP cache Reviewed-by: twisti, dpochepk --- .../MultipleAbstractImplementer.java | 82 ++- .../testcases/MultipleImplementer2.java | 68 ++- .../MultipleImplementersInterface.java | 33 +- .../compilerToVM/ConstantPoolTestCase.java | 282 ++++++---- .../compilerToVM/ConstantPoolTestsHelper.java | 504 +++++++++++++++--- .../compilerToVM/LookupKlassInPoolTest.java | 75 +-- .../ResolveConstantInPoolTest.java | 88 +-- .../compilerToVM/ResolveTypeInPoolTest.java | 64 ++- 8 files changed, 920 insertions(+), 276 deletions(-) diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java b/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java index d90b5285c02..3e090394bbc 100644 --- a/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,13 +23,93 @@ package compiler.jvmci.common.testcases; +import java.util.HashMap; +import java.util.Map; + public abstract class MultipleAbstractImplementer implements MultipleImplementersInterface { + // Different access levels on the fields of this class are used on purpose. + // It is needed to verify jdk.vm.ci.CompilerToVM constant pool related + // methods, e.g. resolveFieldInPool. + + private static int intStaticField = INT_CONSTANT; + final static long longStaticField = LONG_CONSTANT; + volatile static float floatStaticField = FLOAT_CONSTANT; + static double doubleStaticField = DOUBLE_CONSTANT; + public static String stringStaticField = STRING_CONSTANT; + protected static Object objectStaticField = OBJECT_CONSTANT; + + public int intField = INT_CONSTANT; + private long longField = LONG_CONSTANT; + protected float floatField = FLOAT_CONSTANT; + transient double doubleField = DOUBLE_CONSTANT; + volatile String stringField = STRING_CONSTANT; + String stringFieldEmpty = ""; + final Object objectField; + + public MultipleAbstractImplementer() { + intField = Integer.MAX_VALUE; + longField = Long.MAX_VALUE; + floatField = Float.MAX_VALUE; + doubleField = Double.MAX_VALUE; + stringField = "Message"; + objectField = new Object(); + } + public abstract void abstractMethod(); @Override public void finalize() throws Throwable { super.finalize(); } + + public void lambdaUsingMethod2() { + Thread t = new Thread(this::testMethod); + t.start(); + } + + /** + * This method is needed to have "getstatic" and "getfield" instructions + * in the class. These instructions are needed to test + * resolveFieldInPool method, because it needs a bytecode as one of its arguments. + */ + public void printFileds() { + System.out.println(intStaticField); + System.out.println(longStaticField); + System.out.println(floatStaticField); + System.out.println(doubleStaticField); + System.out.println(stringStaticField); + System.out.println(objectStaticField); + System.out.println(intField); + System.out.println(longField); + System.out.println(floatField); + System.out.println(doubleField); + System.out.println(stringField); + System.out.println(stringFieldEmpty); + System.out.println(objectField); + } + + public static void staticMethod() { + System.getProperties(); // calling some static method + Map map = new HashMap(); // calling some constructor + map.put(OBJECT_CONSTANT, OBJECT_CONSTANT); // calling some interface method + map.remove(OBJECT_CONSTANT); // calling some default interface method + } + + @Override + public void instanceMethod() { + toString(); // calling some virtual method + super.toString(); // calling some special method + } + + @Override + public void anonClassMethod() { + new Runnable() { + @Override + public void run() { + System.out.println("Running"); + } + }.run(); + } } diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java index 274df6b5c0f..e7a7b3cc0c3 100644 --- a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,18 @@ package compiler.jvmci.common.testcases; +import java.util.HashMap; +import java.util.Map; + public class MultipleImplementer2 implements MultipleImplementersInterface { + // Different access levels on the fields of this class are used on purpose. + // It is needed to verify jdk.vm.ci.CompilerToVM constant pool related + // methods, e.g. resolveFieldInPool. + private static int intStaticField = INT_CONSTANT; - static long longStaticField = LONG_CONSTANT; - static float floatStaticField = FLOAT_CONSTANT; + final static long longStaticField = LONG_CONSTANT; + volatile static float floatStaticField = FLOAT_CONSTANT; static double doubleStaticField = DOUBLE_CONSTANT; public static String stringStaticField = STRING_CONSTANT; protected static Object objectStaticField = OBJECT_CONSTANT; @@ -35,9 +42,10 @@ public class MultipleImplementer2 implements MultipleImplementersInterface { public int intField = INT_CONSTANT; private long longField = LONG_CONSTANT; protected float floatField = FLOAT_CONSTANT; - double doubleField = DOUBLE_CONSTANT; - String stringField = STRING_CONSTANT; - Object objectField = OBJECT_CONSTANT; + transient double doubleField = DOUBLE_CONSTANT; + volatile String stringField = STRING_CONSTANT; + String stringFieldEmpty = ""; + final Object objectField; public MultipleImplementer2() { intField = Integer.MAX_VALUE; @@ -58,12 +66,52 @@ public class MultipleImplementer2 implements MultipleImplementersInterface { super.finalize(); } - public void interfaceMethodReferral2(MultipleImplementersInterface obj) { - obj.interfaceMethodReferral(obj); - } - public void lambdaUsingMethod2() { Thread t = new Thread(this::testMethod); t.start(); } + + /** + * This method is needed to have "getstatic" and "getfield" instructions + * in the class. These instructions are needed to test + * resolveFieldInPool method, because it needs a bytecode as one of its arguments. + */ + public void printFileds() { + System.out.println(intStaticField); + System.out.println(longStaticField); + System.out.println(floatStaticField); + System.out.println(doubleStaticField); + System.out.println(stringStaticField); + System.out.println(objectStaticField); + System.out.println(intField); + System.out.println(longField); + System.out.println(floatField); + System.out.println(doubleField); + System.out.println(stringField); + System.out.println(stringFieldEmpty); + System.out.println(objectField); + } + + public static void staticMethod() { + System.getProperties(); // calling some static method + Map map = new HashMap(); // calling some constructor + map.put(OBJECT_CONSTANT, OBJECT_CONSTANT); // calling some interface method + map.remove(OBJECT_CONSTANT); // calling some default interface method + } + + @Override + public void instanceMethod() { + toString(); // calling some virtual method + super.toString(); // calling some special method + } + + @Override + public void anonClassMethod() { + new Runnable() { + @Override + public void run() { + System.out.println("Running"); + } + }.run(); + } } diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java index 9ce4e792bc6..5257e592c6e 100644 --- a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java @@ -23,6 +23,9 @@ package compiler.jvmci.common.testcases; +import java.util.HashMap; +import java.util.Map; + public interface MultipleImplementersInterface { int INT_CONSTANT = Integer.MAX_VALUE; @@ -42,12 +45,34 @@ public interface MultipleImplementersInterface { // empty } - default void interfaceMethodReferral(MultipleImplementersInterface obj) { - obj.defaultMethod(); - } - default void lambdaUsingMethod() { Thread t = new Thread(this::defaultMethod); t.start(); } + + default void printFields() { + System.out.println(OBJECT_CONSTANT); + String s = ""; + System.out.println(s); + } + + static void staticMethod() { + System.getProperties(); // calling some static method + Map map = new HashMap(); // calling some constructor + map.put(OBJECT_CONSTANT, OBJECT_CONSTANT); // calling some interface method + map.remove(OBJECT_CONSTANT); // calling some default interface method + } + + default void instanceMethod() { + toString(); // calling some virtual method + } + + default void anonClassMethod() { + new Runnable() { + @Override + public void run() { + System.out.println("Running"); + } + }.run(); + } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java index b9716cca2a2..df4046d889f 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,118 +27,214 @@ package compiler.jvmci.compilerToVM; import java.util.HashMap; import java.util.Map; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import jdk.internal.misc.SharedSecrets; +import sun.hotspot.WhiteBox; import sun.reflect.ConstantPool; +import sun.reflect.ConstantPool.Tag; +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; /** * Common class for jdk.vm.ci.hotspot.CompilerToVM constant pool tests */ public class ConstantPoolTestCase { - private final Map typeTests; + + private static final Map TAG_TO_TYPE_MAP; + static { + TAG_TO_TYPE_MAP = new HashMap<>(); + TAG_TO_TYPE_MAP.put(Tag.CLASS, CONSTANT_CLASS); + TAG_TO_TYPE_MAP.put(Tag.FIELDREF, CONSTANT_FIELDREF); + TAG_TO_TYPE_MAP.put(Tag.METHODREF, CONSTANT_METHODREF); + TAG_TO_TYPE_MAP.put(Tag.INTERFACEMETHODREF, CONSTANT_INTERFACEMETHODREF); + TAG_TO_TYPE_MAP.put(Tag.STRING, CONSTANT_STRING); + TAG_TO_TYPE_MAP.put(Tag.INTEGER, CONSTANT_INTEGER); + TAG_TO_TYPE_MAP.put(Tag.FLOAT, CONSTANT_FLOAT); + TAG_TO_TYPE_MAP.put(Tag.LONG, CONSTANT_LONG); + TAG_TO_TYPE_MAP.put(Tag.DOUBLE, CONSTANT_DOUBLE); + TAG_TO_TYPE_MAP.put(Tag.NAMEANDTYPE, CONSTANT_NAMEANDTYPE); + TAG_TO_TYPE_MAP.put(Tag.UTF8, CONSTANT_UTF8); + TAG_TO_TYPE_MAP.put(Tag.METHODHANDLE, CONSTANT_METHODHANDLE); + TAG_TO_TYPE_MAP.put(Tag.METHODTYPE, CONSTANT_METHODTYPE); + TAG_TO_TYPE_MAP.put(Tag.INVOKEDYNAMIC, CONSTANT_INVOKEDYNAMIC); + TAG_TO_TYPE_MAP.put(Tag.INVALID, CONSTANT_INVALID); + } + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private final Map typeTests; + + public static enum ConstantTypes { + CONSTANT_CLASS { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + checkIndex(constantPoolSS, index); + Class klass = constantPoolSS.getClassAt(index); + String klassName = klass.getName(); + TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this); + for (TestedCPEntry entry : testedEntries) { + if (entry.klass.replaceAll("/", "\\.").equals(klassName)) { + return entry; + } + } + return null; + } + }, + CONSTANT_FIELDREF { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + return this.getTestedCPEntryForMethodAndField(dummyClass, index); + } + }, + CONSTANT_METHODREF { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + return this.getTestedCPEntryForMethodAndField(dummyClass, index); + } + }, + CONSTANT_INTERFACEMETHODREF { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + return this.getTestedCPEntryForMethodAndField(dummyClass, index); + } + }, + CONSTANT_STRING { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + checkIndex(constantPoolSS, index); + String value = constantPoolSS.getStringAt(index); + TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this); + for (TestedCPEntry entry : testedEntries) { + if (entry.name.equals(value)) { + return entry; + } + } + return null; + } + }, + CONSTANT_INTEGER, + CONSTANT_FLOAT, + CONSTANT_LONG, + CONSTANT_DOUBLE, + CONSTANT_NAMEANDTYPE, + CONSTANT_UTF8, + CONSTANT_METHODHANDLE, + CONSTANT_METHODTYPE, + CONSTANT_INVOKEDYNAMIC { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + checkIndex(constantPoolSS, index); + int nameAndTypeIndex = constantPoolSS.getNameAndTypeRefIndexAt(index); + String[] info = constantPoolSS.getNameAndTypeRefInfoAt(nameAndTypeIndex); + TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this); + for (TestedCPEntry entry : testedEntries) { + if (info[0].equals(entry.name) && info[1].equals(entry.type)) { + return entry; + } + } + return null; + } + }, + CONSTANT_INVALID; + + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + return null; // returning null by default + } + + public TestedCPEntry[] getAllCPEntriesForType(DummyClasses dummyClass) { + TestedCPEntry[] toReturn = dummyClass.testedCP.get(this); + if (toReturn == null) { + return new TestedCPEntry[0]; + } + return dummyClass.testedCP.get(this); + } + + protected TestedCPEntry getTestedCPEntryForMethodAndField(DummyClasses dummyClass, int index) { + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + checkIndex(constantPoolSS, index); + String[] info = constantPoolSS.getMemberRefInfoAt(index); + TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this); + for (TestedCPEntry entry : testedEntries) { + if (info[0].equals(entry.klass) && info[1].equals(entry.name) && info[2].equals(entry.type)) { + return entry; + } + } + return null; + } + + protected void checkIndex(ConstantPool constantPoolSS, int index) { + ConstantPool.Tag tag = constantPoolSS.getTagAt(index); + ConstantTypes type = mapTagToCPType(tag); + if (!this.equals(type)) { + String msg = String.format("TESTBUG: CP tag should be a %s, but is %s", + this.name(), + type.name()); + throw new Error(msg); + } + } + } public static interface Validator { void validate(jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int index); + ConstantTypes cpType, + DummyClasses dummyClass, + int index); } - public ConstantPoolTestCase(Map typeTests) { + public static class TestedCPEntry { + public final String klass; + public final String name; + public final String type; + public final byte[] opcodes; + public final long accFlags; + + public TestedCPEntry(String klass, String name, String type, byte[] opcodes, long accFlags) { + this.klass = klass; + this.name = name; + this.type = type; + if (opcodes != null) { + this.opcodes = new byte[opcodes.length]; + System.arraycopy(opcodes, 0, this.opcodes, 0, opcodes.length); + } else { + this.opcodes = null; + } + this.accFlags = accFlags; + } + + public TestedCPEntry(String klass, String name, String type, byte[] opcodes) { + this(klass, name, type, opcodes, 0); + } + + public TestedCPEntry(String klass, String name, String type) { + this(klass, name, type, null, 0); + } + } + + public static ConstantTypes mapTagToCPType(Tag tag) { + return TAG_TO_TYPE_MAP.get(tag); + } + + public ConstantPoolTestCase(Map typeTests) { this.typeTests = new HashMap<>(); this.typeTests.putAll(typeTests); } - private void messageOnFail(Throwable t, - ConstantPoolTestsHelper.ConstantTypes cpType, - ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { - ConstantPool constantPoolSS = SharedSecrets.getJavaLangAccess(). - getConstantPool(dummyClass.klass); - String msg = String.format("Test for %s constant pool entry of" - + " type %s", - dummyClass.klass, cpType.name()); - switch (cpType) { - case CONSTANT_CLASS: - case CONSTANT_STRING: - case CONSTANT_METHODTYPE: - String utf8 = constantPoolSS - .getUTF8At((int) dummyClass.cp.get(index).value); - msg = String.format("%s (%s) failed with %s", msg, utf8, t); - break; - case CONSTANT_INTEGER: - int intValue = constantPoolSS.getIntAt(index); - msg = String.format("%s (%d) failed with %s", msg, intValue, t); - break; - case CONSTANT_LONG: - long longValue = constantPoolSS.getLongAt(index); - msg = String.format("%s (%d) failed with %s", msg, longValue, t); - break; - case CONSTANT_FLOAT: - float floatValue = constantPoolSS.getFloatAt(index); - msg = String.format("%s (%E) failed with %s", msg, floatValue, t); - break; - case CONSTANT_DOUBLE: - double doubleValue = constantPoolSS.getDoubleAt(index); - msg = String.format("%s (%E) failed with %s", msg, doubleValue, t); - break; - case CONSTANT_UTF8: - String utf8Value = constantPoolSS.getUTF8At(index); - msg = String.format("%s (%s) failed with %s", msg, utf8Value, t); - break; - case CONSTANT_INVOKEDYNAMIC: - index = ((int[]) dummyClass.cp.get(index).value)[1]; - case CONSTANT_NAMEANDTYPE: - String name = constantPoolSS - .getUTF8At(((int[]) dummyClass.cp.get(index).value)[0]); - String type = constantPoolSS - .getUTF8At(((int[]) dummyClass.cp.get(index).value)[1]); - msg = String.format("%s (%s:%s) failed with %s", - msg, name, type, t); - break; - case CONSTANT_METHODHANDLE: - index = ((int[]) dummyClass.cp.get(index).value)[1]; - case CONSTANT_METHODREF: - case CONSTANT_INTERFACEMETHODREF: - case CONSTANT_FIELDREF: - int classIndex = ((int[]) dummyClass.cp.get(index).value)[0]; - int nameAndTypeIndex = ((int[]) dummyClass.cp.get(index).value)[1]; - String cName = constantPoolSS - .getUTF8At((int) dummyClass.cp.get(classIndex).value); - String mName = constantPoolSS - .getUTF8At(((int[]) dummyClass.cp.get(nameAndTypeIndex).value)[0]); - String mType = constantPoolSS - .getUTF8At(((int[]) dummyClass.cp.get(nameAndTypeIndex).value)[1]); - msg = String.format("%s (%s.%s:%s) failed with %s ", - msg, cName, mName, mType, t); - break; - default: - msg = String.format("Test bug: unknown constant type %s ", cpType); - } - throw new Error(msg + t.getMessage(), t); - } - public void test() { - for (ConstantPoolTestsHelper.DummyClasses dummyClass - : ConstantPoolTestsHelper.DummyClasses.values()) { - System.out.printf("%nTesting dummy %s%n", dummyClass.klass); - HotSpotResolvedObjectType holder = HotSpotResolvedObjectType - .fromObjectClass(dummyClass.klass); - jdk.vm.ci.meta.ConstantPool constantPoolCTVM - = holder.getConstantPool(); - ConstantPool constantPoolSS = SharedSecrets.getJavaLangAccess(). - getConstantPool(dummyClass.klass); - for (Integer i : dummyClass.cp.keySet()) { - ConstantPoolTestsHelper.ConstantTypes cpType - = dummyClass.cp.get(i).type; + for (DummyClasses dummyClass : DummyClasses.values()) { + boolean isCPCached = WB.getConstantPoolCacheLength(dummyClass.klass) > -1; + System.out.printf("Testing dummy %s with constant pool cached = %b%n", + dummyClass.klass, + isCPCached); + HotSpotResolvedObjectType holder = HotSpotResolvedObjectType.fromObjectClass(dummyClass.klass); + jdk.vm.ci.meta.ConstantPool constantPoolCTVM = holder.getConstantPool(); + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + for (int i = 0; i < constantPoolSS.getSize(); i++) { + Tag tag = constantPoolSS.getTagAt(i); + ConstantTypes cpType = mapTagToCPType(tag); if (!typeTests.keySet().contains(cpType)) { continue; } - try { - typeTests.get(cpType).validate(constantPoolCTVM, - constantPoolSS, dummyClass, i); - } catch (Throwable t) { - messageOnFail(t, cpType, dummyClass, i); - } + typeTests.get(cpType).validate(constantPoolCTVM, cpType, dummyClass, i); } } } } - diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java index 777b848fd8b..783b26188e9 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,19 @@ */ package compiler.jvmci.compilerToVM; +import compiler.jvmci.common.testcases.MultipleAbstractImplementer; import compiler.jvmci.common.testcases.MultipleImplementer2; import compiler.jvmci.common.testcases.MultipleImplementersInterface; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; import java.util.HashMap; import java.util.Map; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.org.objectweb.asm.Opcodes; +import sun.hotspot.WhiteBox; +import sun.reflect.ConstantPool; +import sun.reflect.ConstantPool.Tag; /** * Class contains hard-coded constant pool tables for dummy classes used for @@ -34,104 +43,437 @@ import java.util.Map; */ public class ConstantPoolTestsHelper { - public enum ConstantTypes { - CONSTANT_CLASS, - CONSTANT_FIELDREF, - CONSTANT_METHODREF, - CONSTANT_INTERFACEMETHODREF, - CONSTANT_STRING, - CONSTANT_INTEGER, - CONSTANT_FLOAT, - CONSTANT_LONG, - CONSTANT_DOUBLE, - CONSTANT_NAMEANDTYPE, - CONSTANT_UTF8, - CONSTANT_METHODHANDLE, - CONSTANT_METHODTYPE, - CONSTANT_INVOKEDYNAMIC; - } + public static final int NO_CP_CACHE_PRESENT = Integer.MAX_VALUE; public enum DummyClasses { DUMMY_CLASS(MultipleImplementer2.class, CP_MAP_FOR_CLASS), + DUMMY_ABS_CLASS(MultipleAbstractImplementer.class, CP_MAP_FOR_ABS_CLASS), DUMMY_INTERFACE(MultipleImplementersInterface.class, CP_MAP_FOR_INTERFACE); + private static final WhiteBox WB = WhiteBox.getWhiteBox(); public final Class klass; - public final Map cp; + public final ConstantPool constantPoolSS; + public final Map testedCP; - DummyClasses(Class klass, Map cp) { + DummyClasses(Class klass, Map testedCP) { this.klass = klass; - this.cp = cp; + this.constantPoolSS = SharedSecrets.getJavaLangAccess().getConstantPool(klass); + this.testedCP = testedCP; + } + + public int getCPCacheIndex(int cpi) { + int cacheLength = WB.getConstantPoolCacheLength(this.klass); + int indexTag = WB.getConstantPoolCacheIndexTag(); + for (int cpci = indexTag; cpci < cacheLength + indexTag; cpci++) { + if (WB.remapInstructionOperandFromCPCache(this.klass, cpci) == cpi) { + if (constantPoolSS.getTagAt(cpi).equals(Tag.INVOKEDYNAMIC)) { + return WB.encodeConstantPoolIndyIndex(cpci) + indexTag; + } + return cpci; + } + } + return NO_CP_CACHE_PRESENT; } } - public static class ConstantPoolEntry { - - public final ConstantTypes type; - public final Object value; - - public ConstantPoolEntry(ConstantTypes type, Object value) { - this.type = type; - this.value = value; - } + private static final Map CP_MAP_FOR_CLASS = new HashMap<>(); + static { + CP_MAP_FOR_CLASS.put(CONSTANT_CLASS, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2$1", null, null), + new TestedCPEntry("java/lang/invoke/MethodHandles$Lookup", null, null), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_FIELDREF, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "intStaticField", + "I", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "longStaticField", + "J", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_FINAL | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "floatStaticField", + "F", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_VOLATILE | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "doubleStaticField", + "D", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "stringStaticField", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "objectStaticField", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "intField", + "I", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PUBLIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "longField", + "J", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PRIVATE), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "floatField", + "F", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PROTECTED), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "doubleField", + "D", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_TRANSIENT), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "objectField", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_FINAL), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "stringField", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_VOLATILE), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "stringFieldEmpty", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + 0L), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_METHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/System", + "getProperties", + "()Ljava/util/Properties;", + new byte[] {(byte) Opcodes.INVOKESTATIC}), + new TestedCPEntry("java/util/HashMap", + "", + "()V", + new byte[] {(byte) Opcodes.INVOKESPECIAL}), + new TestedCPEntry("java/lang/Object", + "toString", + "()Ljava/lang/String;", + new byte[] {(byte) Opcodes.INVOKESPECIAL, + (byte) Opcodes.INVOKEVIRTUAL}), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2$1", + "", + "(Lcompiler/jvmci/common/testcases/MultipleImplementer2;)V", + new byte[0]), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "run", + "()V", + new byte[0]), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_INTERFACEMETHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/util/Map", + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + new TestedCPEntry("java/util/Map", + "remove", + "(Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_STRING, + new TestedCPEntry[] { + new TestedCPEntry(null, "Message", null), + new TestedCPEntry(null, "", null), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_METHODHANDLE, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/invoke/LambdaMetafactory", + "metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;" + + "Ljava/lang/String;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodHandle;" + + "Ljava/lang/invoke/MethodType;)" + + "Ljava/lang/invoke/CallSite;", + null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "testMethod", + "()V"), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_METHODTYPE, + new TestedCPEntry[] { + new TestedCPEntry(null, null, "()V"), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_INVOKEDYNAMIC, + new TestedCPEntry[] { + new TestedCPEntry(null, + "run", + "(Lcompiler/jvmci/common/testcases/MultipleImplementer2;)" + + "Ljava/lang/Runnable;"), + } + ); } - private static final Map CP_MAP_FOR_CLASS + private static final Map CP_MAP_FOR_ABS_CLASS = new HashMap<>(); static { - CP_MAP_FOR_CLASS.put(1, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{22, 68})); - CP_MAP_FOR_CLASS.put(2, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 69)); - CP_MAP_FOR_CLASS.put(3, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTEGER, 2147483647)); - CP_MAP_FOR_CLASS.put(4, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{35, 70})); - CP_MAP_FOR_CLASS.put(5, new ConstantPoolEntry(ConstantTypes.CONSTANT_LONG, 9223372036854775807L)); - CP_MAP_FOR_CLASS.put(8, new ConstantPoolEntry(ConstantTypes.CONSTANT_FLOAT, 3.4028235E38F)); - CP_MAP_FOR_CLASS.put(10, new ConstantPoolEntry(ConstantTypes.CONSTANT_DOUBLE, 1.7976931348623157E308D)); - CP_MAP_FOR_CLASS.put(13, new ConstantPoolEntry(ConstantTypes.CONSTANT_STRING, 74)); - CP_MAP_FOR_CLASS.put(22, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 83)); - CP_MAP_FOR_CLASS.put(23, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{22, 84})); - CP_MAP_FOR_CLASS.put(24, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTERFACEMETHODREF, new int[]{2, 85})); - CP_MAP_FOR_CLASS.put(26, new ConstantPoolEntry(ConstantTypes.CONSTANT_INVOKEDYNAMIC, new int[]{0, 91})); - CP_MAP_FOR_CLASS.put(29, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{35, 94})); - CP_MAP_FOR_CLASS.put(35, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 100)); - CP_MAP_FOR_CLASS.put(68, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{54, 55})); - CP_MAP_FOR_CLASS.put(70, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{48, 37})); - CP_MAP_FOR_CLASS.put(84, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{59, 55})); - CP_MAP_FOR_CLASS.put(85, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{103, 63})); - CP_MAP_FOR_CLASS.put(91, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{106, 107})); - CP_MAP_FOR_CLASS.put(94, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{36, 37})); - CP_MAP_FOR_CLASS.put(104, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{110, 111})); - CP_MAP_FOR_CLASS.put(105, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{35, 112})); - CP_MAP_FOR_CLASS.put(110, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 113)); - CP_MAP_FOR_CLASS.put(111, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{114, 118})); - CP_MAP_FOR_CLASS.put(112, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{58, 55})); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_CLASS, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", null, null), + new TestedCPEntry("java/lang/invoke/MethodHandles$Lookup", null, null), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_FIELDREF, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "intStaticField", + "I", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "longStaticField", + "J", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_FINAL | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "floatStaticField", + "F", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_VOLATILE | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "doubleStaticField", + "D", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "stringStaticField", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "objectStaticField", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "intField", + "I", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PUBLIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "longField", + "J", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PRIVATE), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "floatField", + "F", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PROTECTED), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "doubleField", + "D", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_TRANSIENT), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "objectField", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_FINAL), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "stringField", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_VOLATILE), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "stringFieldEmpty", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + 0L), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_METHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/System", + "getProperties", + "()Ljava/util/Properties;", + new byte[] {(byte) Opcodes.INVOKESTATIC}), + new TestedCPEntry("java/util/HashMap", + "", + "()V", + new byte[] {(byte) Opcodes.INVOKESPECIAL}), + new TestedCPEntry("java/lang/Object", + "toString", + "()Ljava/lang/String;", + new byte[] {(byte) Opcodes.INVOKESPECIAL, + (byte) Opcodes.INVOKEVIRTUAL}), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "", + "(Lcompiler/jvmci/common/testcases/MultipleAbstractImplementer;)V", + new byte[0]), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "run", + "()V", + new byte[0]), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_INTERFACEMETHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/util/Map", + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + new TestedCPEntry("java/util/Map", + "remove", + "(Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_STRING, + new TestedCPEntry[] { + new TestedCPEntry(null, "Message", null), + new TestedCPEntry(null, "", null), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_METHODHANDLE, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/invoke/LambdaMetafactory", + "metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;" + + "Ljava/lang/String;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodHandle;" + + "Ljava/lang/invoke/MethodType;)" + + "Ljava/lang/invoke/CallSite;", + null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "testMethod", + "()V"), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_METHODTYPE, + new TestedCPEntry[] { + new TestedCPEntry(null, null, "()V"), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_INVOKEDYNAMIC, + new TestedCPEntry[] { + new TestedCPEntry(null, + "run", + "(Lcompiler/jvmci/common/testcases/MultipleAbstractImplementer;)" + + "Ljava/lang/Runnable;"), + } + ); } - private static final Map CP_MAP_FOR_INTERFACE + private static final Map CP_MAP_FOR_INTERFACE = new HashMap<>(); static { - CP_MAP_FOR_INTERFACE.put(1, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 48)); - CP_MAP_FOR_INTERFACE.put(5, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTERFACEMETHODREF, new int[]{13, 52})); - CP_MAP_FOR_INTERFACE.put(6, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 53)); - CP_MAP_FOR_INTERFACE.put(7, new ConstantPoolEntry(ConstantTypes.CONSTANT_INVOKEDYNAMIC, new int[]{0, 58})); - CP_MAP_FOR_INTERFACE.put(8, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{6, 59})); - CP_MAP_FOR_INTERFACE.put(9, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{6, 60})); - CP_MAP_FOR_INTERFACE.put(12, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{13, 63})); - CP_MAP_FOR_INTERFACE.put(13, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 64)); - CP_MAP_FOR_INTERFACE.put(17, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTEGER, 2147483647)); - CP_MAP_FOR_INTERFACE.put(20, new ConstantPoolEntry(ConstantTypes.CONSTANT_LONG, 9223372036854775807l)); - CP_MAP_FOR_INTERFACE.put(24, new ConstantPoolEntry(ConstantTypes.CONSTANT_FLOAT, 3.4028235E38f)); - CP_MAP_FOR_INTERFACE.put(27, new ConstantPoolEntry(ConstantTypes.CONSTANT_DOUBLE, 1.7976931348623157E308d)); - CP_MAP_FOR_INTERFACE.put(31, new ConstantPoolEntry(ConstantTypes.CONSTANT_STRING, 65)); - CP_MAP_FOR_INTERFACE.put(52, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{34, 35})); - CP_MAP_FOR_INTERFACE.put(55, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODHANDLE, new int[]{6, 67})); - CP_MAP_FOR_INTERFACE.put(56, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODTYPE, 35)); - CP_MAP_FOR_INTERFACE.put(57, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODHANDLE, new int[]{9, 5})); - CP_MAP_FOR_INTERFACE.put(58, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{68, 69})); - CP_MAP_FOR_INTERFACE.put(59, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{70, 71})); - CP_MAP_FOR_INTERFACE.put(60, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{72, 35})); - CP_MAP_FOR_INTERFACE.put(63, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{32, 33})); - CP_MAP_FOR_INTERFACE.put(67, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{73, 74})); - CP_MAP_FOR_INTERFACE.put(73, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 75)); - CP_MAP_FOR_INTERFACE.put(74, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{76, 80})); - CP_MAP_FOR_INTERFACE.put(77, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 82)); + CP_MAP_FOR_INTERFACE.put(CONSTANT_CLASS, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface$1", null, null), + new TestedCPEntry("java/lang/Object", null, null), + new TestedCPEntry("java/lang/invoke/MethodHandles$Lookup", null, null), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_FIELDREF, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", + "OBJECT_CONSTANT", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_PUBLIC), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_METHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/System", + "getProperties", + "()Ljava/util/Properties;", + new byte[] {(byte) Opcodes.INVOKESTATIC}), + new TestedCPEntry("java/util/HashMap", + "", + "()V", + new byte[] {(byte) Opcodes.INVOKESPECIAL}), + new TestedCPEntry("java/lang/Object", + "toString", + "()Ljava/lang/String;", + new byte[] {(byte) Opcodes.INVOKEVIRTUAL}), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "", + "(Lcompiler/jvmci/common/testcases/MultipleAbstractImplementer;)V", + new byte[0]), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "run", + "()V", + new byte[0]), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_INTERFACEMETHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/util/Map", + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + new TestedCPEntry("java/util/Map", + "remove", + "(Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_STRING, + new TestedCPEntry[] { + new TestedCPEntry(null, "Hello", null), + new TestedCPEntry(null, "", null), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_METHODHANDLE, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/invoke/LambdaMetafactory", + "metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;" + + "Ljava/lang/String;Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodHandle;" + + "Ljava/lang/invoke/MethodType;)" + + "Ljava/lang/invoke/CallSite;"), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", + "defaultMethod", + "()V"), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_METHODTYPE, + new TestedCPEntry[] { + new TestedCPEntry(null, null, "()V"), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_INVOKEDYNAMIC, + new TestedCPEntry[] { + new TestedCPEntry(null, + "run", + "(Lcompiler/jvmci/common/testcases/MultipleImplementersInterface;)" + + "Ljava/lang/Runnable;"), + } + ); } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java index b3fb21028af..09893c05008 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,58 +29,73 @@ * @summary Testing compiler.jvmci.CompilerToVM.lookupKlassInPool method * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java - * @build compiler.jvmci.common.testcases.MultipleImplementersInterface - * compiler.jvmci.common.testcases.MultipleImplementer2 - * compiler.jvmci.compilerToVM.ConstantPoolTestsHelper - * compiler.jvmci.compilerToVM.ConstantPoolTestCase + * @build sun.hotspot.WhiteBox * compiler.jvmci.compilerToVM.LookupKlassInPoolTest - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.LookupKlassInPoolTest */ package compiler.jvmci.compilerToVM; +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; import java.util.HashMap; import java.util.Map; import jdk.vm.ci.hotspot.CompilerToVMHelper; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import sun.reflect.ConstantPool; +import jdk.vm.ci.meta.ConstantPool; /** - * Test for {@code compiler.jvmci.CompilerToVM.lookupKlassInPool} method + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupKlassInPool} method */ public class LookupKlassInPoolTest { - public static void main(String[] args) { - Map typeTests = new HashMap<>(1); - typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_CLASS, - LookupKlassInPoolTest::validate); + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_CLASS, LookupKlassInPoolTest::validate); ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); } - public static void validate(jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int i) { - Object classToVerify = CompilerToVMHelper - .lookupKlassInPool(constantPoolCTVM, i); - if (!(classToVerify instanceof HotSpotResolvedObjectType) - && !(classToVerify instanceof String)) { - String msg = String.format("Output of method" - + " CTVM.lookupKlassInPool is neither" - + " a HotSpotResolvedObjectType, nor a String"); + public static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int i) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, i); + if (entry == null) { + return; + } + Object classToVerify = CompilerToVMHelper.lookupKlassInPool(constantPoolCTVM, i); + if (!(classToVerify instanceof HotSpotResolvedObjectType) && !(classToVerify instanceof String)) { + String msg = String.format("Output of method CTVM.lookupKlassInPool is neither" + + " a HotSpotResolvedObjectType, nor a String"); throw new AssertionError(msg); } - int classNameIndex = (int) dummyClass.cp.get(i).value; - String classNameToRefer - = constantPoolSS.getUTF8At(classNameIndex); + String classNameToRefer = entry.klass; String outputToVerify = classToVerify.toString(); if (!outputToVerify.contains(classNameToRefer)) { - String msg = String.format("Wrong class accessed by constant" - + " pool index %d: %s, but should be %s", - i, outputToVerify, classNameToRefer); + String msg = String.format("Wrong class accessed by constant pool index %d: %s, but should be %s", + i, + outputToVerify, + classNameToRefer); throw new AssertionError(msg); } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java index e72240e0316..2c37309923d 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,66 +28,86 @@ * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java - * @build compiler.jvmci.compilerToVM.ResolveConstantInPoolTest - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.ResolveConstantInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI * compiler.jvmci.compilerToVM.ResolveConstantInPoolTest */ package compiler.jvmci.compilerToVM; +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import java.util.HashMap; import java.util.Map; -import jdk.vm.ci.hotspot.CompilerToVMHelper; import jdk.test.lib.Asserts; -import sun.reflect.ConstantPool; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; /** - * Test for {@code compiler.jvmci.CompilerToVM.resolveConstantInPool} method + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.resolveConstantInPool} method */ public class ResolveConstantInPoolTest { + private static final String NOT_NULL_MSG + = "Object returned by resolveConstantInPool method should not be null"; + public static void main(String[] args) throws Exception { - Map typeTests = new HashMap<>(2); - typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_METHODHANDLE, - ResolveConstantInPoolTest::validateMethodHandle); - typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_METHODTYPE, - ResolveConstantInPoolTest::validateMethodType); + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODHANDLE, ResolveConstantInPoolTest::validateMethodHandle); + typeTests.put(CONSTANT_METHODTYPE, ResolveConstantInPoolTest::validateMethodType); ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); } - private static void validateMethodHandle( - jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { - Object constantInPool = CompilerToVMHelper - .resolveConstantInPool(constantPoolCTVM, index); + private static void validateMethodHandle(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int index) { + Object constantInPool = CompilerToVMHelper.resolveConstantInPool(constantPoolCTVM, index); + String msg = String.format("%s for index %d", NOT_NULL_MSG, index); + Asserts.assertNotNull(constantInPool, msg); if (!(constantInPool instanceof MethodHandle)) { - String msg = String.format( - "Wrong constant pool entry accessed by index" - + " %d: %s, but should be subclass of %s", - index + 1, constantInPool.getClass(), - MethodHandle.class.getName()); + msg = String.format("Wrong constant pool entry accessed by index" + + " %d: %s, but should be subclass of %s", + index, + constantInPool.getClass(), + MethodHandle.class.getName()); throw new AssertionError(msg); } } - private static void validateMethodType( - jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { - Object constantInPool = CompilerToVMHelper - .resolveConstantInPool(constantPoolCTVM, index); + private static void validateMethodType(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int index) { + Object constantInPool = CompilerToVMHelper.resolveConstantInPool(constantPoolCTVM, index); + String msg = String.format("%s for index %d", NOT_NULL_MSG, index); + Asserts.assertNotNull(constantInPool, msg); Class mtToVerify = constantInPool.getClass(); Class mtToRefer = MethodType.class; - String msg = String.format("Wrong %s accessed by constant pool index" - + " %d: %s, but should be %s", "method type class", - index, mtToVerify, mtToRefer); + msg = String.format("Wrong method type class accessed by" + + " constant pool index %d", + index); Asserts.assertEQ(mtToRefer, mtToVerify, msg); } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java index 9b205e347ad..1e5fe57f369 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,51 +29,69 @@ * @summary Testing compiler.jvmci.CompilerToVM.resolveTypeInPool method * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java - * @build compiler.jvmci.common.testcases.MultipleImplementersInterface - * compiler.jvmci.common.testcases.MultipleImplementer2 - * compiler.jvmci.compilerToVM.ConstantPoolTestsHelper - * compiler.jvmci.compilerToVM.ConstantPoolTestCase + * @build sun.hotspot.WhiteBox * compiler.jvmci.compilerToVM.ResolveTypeInPoolTest - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.ResolveTypeInPoolTest */ package compiler.jvmci.compilerToVM; +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; import java.util.HashMap; import java.util.Map; import jdk.vm.ci.hotspot.CompilerToVMHelper; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import sun.reflect.ConstantPool; +import jdk.vm.ci.meta.ConstantPool; /** - * Test for {@code compiler.jvmci.CompilerToVM.resolveTypeInPool} method + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.resolveTypeInPool} method */ public class ResolveTypeInPoolTest { public static void main(String[] args) throws Exception { - Map typeTests = new HashMap<>(1); - typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_CLASS, - ResolveTypeInPoolTest::validate); + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_CLASS, ResolveTypeInPoolTest::validate); ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); } - public static void validate( - jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int i) { - HotSpotResolvedObjectType typeToVerify = CompilerToVMHelper - .resolveTypeInPool(constantPoolCTVM, i); - int classNameIndex = (int) dummyClass.cp.get(i).value; - String classNameToRefer = constantPoolSS.getUTF8At(classNameIndex); + public static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int i) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, i); + if (entry == null) { + return; + } + HotSpotResolvedObjectType typeToVerify = CompilerToVMHelper.resolveTypeInPool(constantPoolCTVM, i); + String classNameToRefer = entry.klass; String outputToVerify = typeToVerify.toString(); if (!outputToVerify.contains(classNameToRefer)) { String msg = String.format("Wrong class accessed by constant" - + " pool index %d: %s, but should be %s", - i, outputToVerify, classNameToRefer); + + " pool index %d: %s, but should be %s", + i, + outputToVerify, + classNameToRefer); throw new AssertionError(msg); } } From 719c07ec100c07433f22a887670f657abf705841 Mon Sep 17 00:00:00 2001 From: Konstantin Shefov Date: Sat, 20 Feb 2016 11:49:45 +0300 Subject: [PATCH 009/129] 8141619: Develop new tests for JVMCI compilerToVM class' CP related methods Reviewed-by: twisti, dpochepk --- .../LookupKlassRefIndexInPoolTest.java | 102 +++++++++++ .../compilerToVM/LookupMethodInPoolTest.java | 120 +++++++++++++ .../LookupNameAndTypeRefIndexInPoolTest.java | 103 ++++++++++++ .../compilerToVM/LookupNameInPoolTest.java | 100 +++++++++++ .../LookupSignatureInPoolTest.java | 102 +++++++++++ .../compilerToVM/ResolveFieldInPoolTest.java | 159 ++++++++++++++++++ ...solvePossiblyCachedConstantInPoolTest.java | 96 +++++++++++ 7 files changed, 782 insertions(+) create mode 100644 hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java create mode 100644 hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java create mode 100644 hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java create mode 100644 hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java create mode 100644 hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java create mode 100644 hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java create mode 100644 hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java new file mode 100644 index 00000000000..e1dbe9f9494 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupKlassRefIndexInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupKlassRefIndexInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupKlassRefIndexInPool} method + */ +public class LookupKlassRefIndexInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupKlassRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupKlassRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_FIELDREF, LookupKlassRefIndexInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + int indexToVerify = CompilerToVMHelper.lookupKlassRefIndexInPool(constantPoolCTVM, index); + int indexToRefer = dummyClass.constantPoolSS.getClassRefIndexAt(cpi); + String msg = String.format("Wrong class index returned by lookupKlassRefIndexInPool method " + + "applied to %sconstant pool index %d", + cached, + index); + Asserts.assertEQ(indexToRefer, indexToVerify, msg); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java new file mode 100644 index 00000000000..a1e71bb2b3a --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupMethodInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupMethodInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupMethodInPool} method + */ +public class LookupMethodInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupMethodInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupMethodInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + for (int j = 0; j < entry.opcodes.length; j++) { + HotSpotResolvedJavaMethod methodToVerify = CompilerToVMHelper + .lookupMethodInPool(constantPoolCTVM, index, entry.opcodes[j]); + String msg = String.format("Object returned by lookupMethodInPool method" + + " for %sindex %d should not be null", + cached, + index); + Asserts.assertNotNull(methodToVerify, msg); + String[] classNameSplit = entry.klass.split("/"); + String classNameToRefer = classNameSplit[classNameSplit.length - 1]; + String methodNameToRefer = entry.name; + String methodToVerifyToString = methodToVerify.toString(); + if (!methodToVerifyToString.contains(classNameToRefer) + || !methodToVerifyToString.contains(methodNameToRefer)) { + msg = String.format("String representation \"%s\" of the object" + + " returned by lookupMethodInPool method" + + " for index %d does not contain a method's class name" + + " or method's name, should contain %s.%s", + methodToVerifyToString, + index, + classNameToRefer, + methodNameToRefer); + throw new AssertionError(msg); + } + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java new file mode 100644 index 00000000000..0eea14aa8d4 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupNameAndTypeRefIndexInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupNameAndTypeRefIndexInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupNameAndTypeRefIndexInPool} method + */ +public class LookupNameAndTypeRefIndexInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupNameAndTypeRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupNameAndTypeRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_FIELDREF, LookupNameAndTypeRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_INVOKEDYNAMIC, LookupNameAndTypeRefIndexInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + int indexToVerify = CompilerToVMHelper.lookupNameAndTypeRefIndexInPool(constantPoolCTVM, index); + int indexToRefer = dummyClass.constantPoolSS.getNameAndTypeRefIndexAt(cpi); + String msg = String.format("Wrong nameAndType index returned by lookupNameAndTypeRefIndexInPool" + + " method applied to %sconstant pool index %d", + cached, + index); + Asserts.assertEQ(indexToRefer, indexToVerify, msg); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java new file mode 100644 index 00000000000..09db06c8a77 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupNameInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupNameInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; +import jdk.test.lib.Asserts; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupNameInPool} method + */ +public class LookupNameInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupNameInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupNameInPoolTest::validate); + typeTests.put(CONSTANT_FIELDREF, LookupNameInPoolTest::validate); + typeTests.put(CONSTANT_INVOKEDYNAMIC, LookupNameInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + String nameToVerify = CompilerToVMHelper.lookupNameInPool(constantPoolCTVM, index); + String nameToRefer = entry.name; + String msg = String.format("Wrong name accessed by %sconstant pool index %d", cached, index); + Asserts.assertEQ(nameToVerify, nameToRefer, msg); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java new file mode 100644 index 00000000000..00f55833891 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupSignatureInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupSignatureInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupSignatureInPool} method + */ +public class LookupSignatureInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupSignatureInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupSignatureInPoolTest::validate); + typeTests.put(CONSTANT_FIELDREF, LookupSignatureInPoolTest::validate); + typeTests.put(CONSTANT_INVOKEDYNAMIC, LookupSignatureInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + String sigToVerify = CompilerToVMHelper.lookupSignatureInPool(constantPoolCTVM, index); + String sigToRefer = entry.type; + String msg = String.format("Wrong signature accessed by %sconstant pool index %d", + cached, + index); + Asserts.assertEQ(sigToVerify, sigToRefer, msg); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java new file mode 100644 index 00000000000..9e99842110f --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.ResolveFieldInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.ResolveFieldInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.ConstantPool; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.misc.Unsafe; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.resolveFieldInPool} method + */ +public class ResolveFieldInPoolTest { + + private static final Unsafe UNSAFE = Utils.getUnsafe(); + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_FIELDREF, ResolveFieldInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + for (int j = 0; j < entry.opcodes.length; j++) { + long[] info = new long[2]; + HotSpotResolvedObjectType fieldToVerify + = CompilerToVMHelper.resolveFieldInPool(constantPoolCTVM, + index, + entry.opcodes[j], + info); + String msg = String.format("Object returned by resolveFieldInPool method" + + " for %sindex %d should not be null", + cached, + index); + Asserts.assertNotNull(fieldToVerify, msg); + String classNameToRefer = entry.klass; + String fieldToVerifyKlassToString = fieldToVerify.klass().toValueString(); + if (!fieldToVerifyKlassToString.contains(classNameToRefer)) { + msg = String.format("String representation \"%s\" of the object" + + " returned by resolveFieldInPool method" + + " for index %d does not contain a field's class name," + + " should contain %s", + fieldToVerifyKlassToString, + index, + classNameToRefer); + throw new AssertionError(msg); + } + msg = String.format("Access flags returned by resolveFieldInPool" + + " method are wrong for the field %s.%s" + + " at %sindex %d", + entry.klass, + entry.name, + cached, + index); + Asserts.assertEQ(info[0], entry.accFlags, msg); + if (cpci == -1) { + return; + } + Class classOfTheField = null; + Field fieldToRefer = null; + try { + classOfTheField = Class.forName(classNameToRefer.replaceAll("/", "\\.")); + fieldToRefer = classOfTheField.getDeclaredField(entry.name); + fieldToRefer.setAccessible(true); + } catch (Exception ex) { + throw new Error("Unexpected exception", ex); + } + long offsetToRefer; + if ((entry.accFlags & Opcodes.ACC_STATIC) != 0) { + offsetToRefer = UNSAFE.staticFieldOffset(fieldToRefer); + } else { + offsetToRefer = UNSAFE.objectFieldOffset(fieldToRefer); + } + msg = String.format("Field offset returned by resolveFieldInPool" + + " method is wrong for the field %s.%s" + + " at %sindex %d", + entry.klass, + entry.name, + cached, + index); + Asserts.assertEQ(info[1], offsetToRefer, msg); + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java new file mode 100644 index 00000000000..6f0af4c2ce1 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.ResolvePossiblyCachedConstantInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.ResolvePossiblyCachedConstantInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.resolvePossiblyCachedConstantInPool} method + */ +public class ResolvePossiblyCachedConstantInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_STRING, ResolvePossiblyCachedConstantInPoolTest::validateString); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + // The next "Class.forName" is here for the following reason. + // When class is initialized, constant pool cache is available. + // This method works only with cached constant pool. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validateString(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + Object constantInPool = CompilerToVMHelper.resolvePossiblyCachedConstantInPool(constantPoolCTVM, index); + String stringToVerify = (String) constantInPool; + String stringToRefer = entry.name; + if (stringToRefer.equals("") && cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + stringToRefer = null; // tested method returns null for cached empty strings + } + String msg = String.format("Wrong string accessed by %sconstant pool index %d", cached, index); + Asserts.assertEQ(stringToRefer, stringToVerify, msg); + } +} From 78d37841efc43504081d6a439b99a4aa0fda84b9 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Mon, 15 Feb 2016 10:14:33 +0100 Subject: [PATCH 010/129] 8087341: C2 doesn't optimize redundant memory operations with G1 Effect of memory barrier in post barrier is too wide Reviewed-by: kvn, aph --- hotspot/src/cpu/aarch64/vm/aarch64.ad | 1162 +++++++++++------------- hotspot/src/share/vm/opto/graphKit.cpp | 18 +- hotspot/src/share/vm/opto/graphKit.hpp | 1 + 3 files changed, 533 insertions(+), 648 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index e94d23c150e..18ba1e44cf3 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -1041,10 +1041,8 @@ class HandlerImpl { bool is_card_mark_membar(const MemBarNode *barrier); bool is_CAS(int opcode); - MemBarNode *leading_to_normal(MemBarNode *leading); - MemBarNode *normal_to_leading(const MemBarNode *barrier); - MemBarNode *card_mark_to_trailing(const MemBarNode *barrier); - MemBarNode *trailing_to_card_mark(const MemBarNode *trailing); + MemBarNode *leading_to_trailing(MemBarNode *leading); + MemBarNode *card_mark_to_leading(const MemBarNode *barrier); MemBarNode *trailing_to_leading(const MemBarNode *trailing); // predicates controlling emit of ldr/ldar and associated dmb @@ -1418,23 +1416,28 @@ source %{ // leading MemBarRelease and a trailing MemBarVolatile as follows // // MemBarRelease - // { || } -- optional + // { || } -- optional // {MemBarCPUOrder} - // || \\ - // || StoreX[mo_release] - // | \ / - // | MergeMem - // | / + // || \\ + // || StoreX[mo_release] + // | \ Bot / ??? + // | MergeMem + // | / // MemBarVolatile // // where // || and \\ represent Ctl and Mem feeds via Proj nodes // | \ and / indicate further routing of the Ctl and Mem feeds // - // this is the graph we see for non-object stores. however, for a - // volatile Object store (StoreN/P) we may see other nodes below the - // leading membar because of the need for a GC pre- or post-write - // barrier. + // Note that the memory feed from the CPUOrder membar to the + // MergeMem node is an AliasIdxBot slice while the feed from the + // StoreX is for a slice determined by the type of value being + // written. + // + // the diagram above shows the graph we see for non-object stores. + // for a volatile Object store (StoreN/P) we may see other nodes + // below the leading membar because of the need for a GC pre- or + // post-write barrier. // // with most GC configurations we with see this simple variant which // includes a post-write barrier card mark. @@ -1442,7 +1445,7 @@ source %{ // MemBarRelease______________________________ // || \\ Ctl \ \\ // || StoreN/P[mo_release] CastP2X StoreB/CM - // | \ / . . . / + // | \ Bot / oop . . . / // | MergeMem // | / // || / @@ -1452,152 +1455,142 @@ source %{ // the object address to an int used to compute the card offset) and // Ctl+Mem to a StoreB node (which does the actual card mark). // - // n.b. a StoreCM node will only appear in this configuration when - // using CMS. StoreCM differs from a normal card mark write (StoreB) - // because it implies a requirement to order visibility of the card - // mark (StoreCM) relative to the object put (StoreP/N) using a - // StoreStore memory barrier (arguably this ought to be represented - // explicitly in the ideal graph but that is not how it works). This - // ordering is required for both non-volatile and volatile - // puts. Normally that means we need to translate a StoreCM using - // the sequence + // n.b. a StoreCM node is only ever used when CMS (with or without + // CondCardMark) or G1 is configured. This abstract instruction + // differs from a normal card mark write (StoreB) because it implies + // a requirement to order visibility of the card mark (StoreCM) + // after that of the object put (StoreP/N) using a StoreStore memory + // barrier. Note that this is /not/ a requirement to order the + // instructions in the generated code (that is already guaranteed by + // the order of memory dependencies). Rather it is a requirement to + // ensure visibility order which only applies on architectures like + // AArch64 which do not implement TSO. This ordering is required for + // both non-volatile and volatile puts. + // + // That implies that we need to translate a StoreCM using the + // sequence // // dmb ishst // stlrb // - // However, in the case of a volatile put if we can recognise this - // configuration and plant an stlr for the object write then we can - // omit the dmb and just plant an strb since visibility of the stlr - // is ordered before visibility of subsequent stores. StoreCM nodes - // also arise when using G1 or using CMS with conditional card - // marking. In these cases (as we shall see) we don't need to insert - // the dmb when translating StoreCM because there is already an - // intervening StoreLoad barrier between it and the StoreP/N. - // - // It is also possible to perform the card mark conditionally on it - // currently being unmarked in which case the volatile put graph - // will look slightly different + // This dmb cannot be omitted even when the associated StoreX or + // CompareAndSwapX is implemented using stlr. However, as described + // below there are circumstances where a specific GC configuration + // requires a stronger barrier in which case it can be omitted. + // + // With the Serial or Parallel GC using +CondCardMark the card mark + // is performed conditionally on it currently being unmarked in + // which case the volatile put graph looks slightly different // // MemBarRelease____________________________________________ // || \\ Ctl \ Ctl \ \\ Mem \ // || StoreN/P[mo_release] CastP2X If LoadB | - // | \ / \ | + // | \ Bot / oop \ | // | MergeMem . . . StoreB // | / / // || / // MemBarVolatile // - // It is worth noting at this stage that both the above + // It is worth noting at this stage that all the above // configurations can be uniquely identified by checking that the // memory flow includes the following subgraph: // // MemBarRelease // {MemBarCPUOrder} - // | \ . . . - // | StoreX[mo_release] . . . - // | / - // MergeMem - // | + // | \ . . . + // | StoreX[mo_release] . . . + // Bot | / oop + // MergeMem + // | // MemBarVolatile // - // This is referred to as a *normal* subgraph. It can easily be - // detected starting from any candidate MemBarRelease, - // StoreX[mo_release] or MemBarVolatile. + // This is referred to as a *normal* volatile store subgraph. It can + // easily be detected starting from any candidate MemBarRelease, + // StoreX[mo_release] or MemBarVolatile node. // - // A simple variation on this normal case occurs for an unsafe CAS - // operation. The basic graph for a non-object CAS is + // A small variation on this normal case occurs for an unsafe CAS + // operation. The basic memory flow subgraph for a non-object CAS is + // as follows // // MemBarRelease // || // MemBarCPUOrder - // || \\ . . . - // || CompareAndSwapX - // || | - // || SCMemProj - // | \ / - // | MergeMem - // | / + // | \\ . . . + // | CompareAndSwapX + // | | + // Bot | SCMemProj + // \ / Bot + // MergeMem + // / // MemBarCPUOrder // || // MemBarAcquire // // The same basic variations on this arrangement (mutatis mutandis) - // occur when a card mark is introduced. i.e. we se the same basic - // shape but the StoreP/N is replaced with CompareAndSawpP/N and the - // tail of the graph is a pair comprising a MemBarCPUOrder + - // MemBarAcquire. + // occur when a card mark is introduced. i.e. the CPUOrder MemBar + // feeds the extra CastP2X, LoadB etc nodes but the above memory + // flow subgraph is still present. + // + // This is referred to as a *normal* CAS subgraph. It can easily be + // detected starting from any candidate MemBarRelease, + // StoreX[mo_release] or MemBarAcquire node. // - // So, in the case of a CAS the normal graph has the variant form + // The code below uses two helper predicates, leading_to_trailing + // and trailing_to_leading to identify these normal graphs, one + // validating the layout starting from the top membar and searching + // down and the other validating the layout starting from the lower + // membar and searching up. // - // MemBarRelease - // MemBarCPUOrder - // | \ . . . - // | CompareAndSwapX . . . - // | | - // | SCMemProj - // | / . . . - // MergeMem - // | - // MemBarCPUOrder - // MemBarAcquire + // There are two special case GC configurations when the simple + // normal graphs above may not be generated: when using G1 (which + // always employs a conditional card mark); and when using CMS with + // conditional card marking (+CondCardMark) configured. These GCs + // are both concurrent rather than stop-the world GCs. So they + // introduce extra Ctl+Mem flow into the graph between the leading + // and trailing membar nodes, in particular enforcing stronger + // memory serialisation beween the object put and the corresponding + // conditional card mark. CMS employs a post-write GC barrier while + // G1 employs both a pre- and post-write GC barrier. // - // This graph can also easily be detected starting from any - // candidate MemBarRelease, CompareAndSwapX or MemBarAcquire. + // The post-write barrier subgraph for these configurations includes + // a MemBarVolatile node -- referred to as a card mark membar -- + // which is needed to order the card write (StoreCM) operation in + // the barrier, the preceding StoreX (or CompareAndSwapX) and Store + // operations performed by GC threads i.e. a card mark membar + // constitutes a StoreLoad barrier hence must be translated to a dmb + // ish (whether or not it sits inside a volatile store sequence). // - // the code below uses two helper predicates, leading_to_normal and - // normal_to_leading to identify these normal graphs, one validating - // the layout starting from the top membar and searching down and - // the other validating the layout starting from the lower membar - // and searching up. + // Of course, the use of the dmb ish for the card mark membar also + // implies theat the StoreCM which follows can omit the dmb ishst + // instruction. The necessary visibility ordering will already be + // guaranteed by the dmb ish. In sum, the dmb ishst instruction only + // needs to be generated for as part of the StoreCM sequence with GC + // configuration +CMS -CondCardMark. + // + // Of course all these extra barrier nodes may well be absent -- + // they are only inserted for object puts. Their potential presence + // significantly complicates the task of identifying whether a + // MemBarRelease, StoreX[mo_release], MemBarVolatile or + // MemBarAcquire forms part of a volatile put or CAS when using + // these GC configurations (see below) and also complicates the + // decision as to how to translate a MemBarVolatile and StoreCM. // - // There are two special case GC configurations when a normal graph - // may not be generated: when using G1 (which always employs a - // conditional card mark); and when using CMS with conditional card - // marking configured. These GCs are both concurrent rather than - // stop-the world GCs. So they introduce extra Ctl+Mem flow into the - // graph between the leading and trailing membar nodes, in - // particular enforcing stronger memory serialisation beween the - // object put and the corresponding conditional card mark. CMS - // employs a post-write GC barrier while G1 employs both a pre- and - // post-write GC barrier. Of course the extra nodes may be absent -- - // they are only inserted for object puts. This significantly - // complicates the task of identifying whether a MemBarRelease, - // StoreX[mo_release] or MemBarVolatile forms part of a volatile put - // when using these GC configurations (see below). It adds similar - // complexity to the task of identifying whether a MemBarRelease, - // CompareAndSwapX or MemBarAcquire forms part of a CAS. - // - // In both cases the post-write subtree includes an auxiliary - // MemBarVolatile (StoreLoad barrier) separating the object put and - // the read of the corresponding card. This poses two additional - // problems. - // - // Firstly, a card mark MemBarVolatile needs to be distinguished - // from a normal trailing MemBarVolatile. Resolving this first - // problem is straightforward: a card mark MemBarVolatile always - // projects a Mem feed to a StoreCM node and that is a unique marker + // So, thjis means that a card mark MemBarVolatile occurring in the + // post-barrier graph it needs to be distinguished from a normal + // trailing MemBarVolatile. Resolving this is straightforward: a + // card mark MemBarVolatile always projects a Mem feed to a StoreCM + // node and that is a unique marker // // MemBarVolatile (card mark) // C | \ . . . // | StoreCM . . . // . . . // - // The second problem is how the code generator is to translate the - // card mark barrier? It always needs to be translated to a "dmb - // ish" instruction whether or not it occurs as part of a volatile - // put. A StoreLoad barrier is needed after the object put to ensure - // i) visibility to GC threads of the object put and ii) visibility - // to the mutator thread of any card clearing write by a GC - // thread. Clearly a normal store (str) will not guarantee this - // ordering but neither will a releasing store (stlr). The latter - // guarantees that the object put is visible but does not guarantee - // that writes by other threads have also been observed. - // - // So, returning to the task of translating the object put and the - // leading/trailing membar nodes: what do the non-normal node graph - // look like for these 2 special cases? and how can we determine the - // status of a MemBarRelease, StoreX[mo_release] or MemBarVolatile - // in both normal and non-normal cases? + // Returning to the task of translating the object put and the + // leading/trailing membar nodes: what do the node graphs look like + // for these 2 special cases? and how can we determine the status of + // a MemBarRelease, StoreX[mo_release] or MemBarVolatile in both + // normal and non-normal cases? // // A CMS GC post-barrier wraps its card write (StoreCM) inside an If // which selects conditonal execution based on the value loaded @@ -1608,91 +1601,117 @@ source %{ // which looks like this // // MemBarRelease - // MemBarCPUOrder_(leading)__________________ - // C | M \ \\ C \ - // | \ StoreN/P[mo_release] CastP2X - // | Bot \ / - // | MergeMem - // | / - // MemBarVolatile (card mark) - // C | || M | - // | LoadB | - // | | | - // | Cmp |\ - // | / | \ - // If | \ - // | \ | \ - // IfFalse IfTrue | \ - // \ / \ | \ - // \ / StoreCM | - // \ / | | - // Region . . . | - // | \ / - // | . . . \ / Bot + // MemBarCPUOrder_(leading)____________________ + // C | | M \ \\ M | C \ + // | | \ StoreN/P[mo_release] | CastP2X + // | | Bot \ / oop \ | + // | | MergeMem \ / + // | | / | / + // MemBarVolatile (card mark) | / + // C | || M | | / + // | LoadB | Bot oop | / Bot + // | | | / / + // | Cmp |\ / / + // | / | \ / / + // If | \ / / + // | \ | \ / / + // IfFalse IfTrue | \ / / + // \ / \ | | / / + // \ / StoreCM | / / + // \ / \ / / / + // Region Phi / / + // | \ Raw | / / + // | . . . | / / // | MergeMem - // | | + // | | // MemBarVolatile (trailing) // - // The first MergeMem merges the AliasIdxBot Mem slice from the - // leading membar and the oopptr Mem slice from the Store into the - // card mark membar. The trailing MergeMem merges the AliasIdxBot - // Mem slice from the card mark membar and the AliasIdxRaw slice - // from the StoreCM into the trailing membar (n.b. the latter - // proceeds via a Phi associated with the If region). + // Notice that there are two MergeMem nodes below the leading + // membar. The first MergeMem merges the AliasIdxBot Mem slice from + // the leading membar and the oopptr Mem slice from the Store into + // the card mark membar. The trailing MergeMem merges the + // AliasIdxBot Mem slice from the leading membar, the AliasIdxRaw + // slice from the StoreCM and an oop slice from the StoreN/P node + // into the trailing membar (n.b. the raw slice proceeds via a Phi + // associated with the If region). // - // The graph for a CAS varies slightly, the obvious difference being - // that the StoreN/P node is replaced by a CompareAndSwapP/N node - // and the trailing MemBarVolatile by a MemBarCPUOrder + - // MemBarAcquire pair. The other important difference is that the - // CompareAndSwap node's SCMemProj is not merged into the card mark - // membar - it still feeds the trailing MergeMem. This also means - // that the card mark membar receives its Mem feed directly from the - // leading membar rather than via a MergeMem. + // So, in the case of CMS + CondCardMark the volatile object store + // graph still includes a normal volatile store subgraph from the + // leading membar to the trailing membar. However, it also contains + // the same shape memory flow to the card mark membar. The two flows + // can be distinguished by testing whether or not the downstream + // membar is a card mark membar. + // + // The graph for a CAS also varies with CMS + CondCardMark, in + // particular employing a control feed from the CompareAndSwapX node + // through a CmpI and If to the card mark membar and StoreCM which + // updates the associated card. This avoids executing the card mark + // if the CAS fails. However, it can be seen from the diagram below + // that the presence of the barrier does not alter the normal CAS + // memory subgraph where the leading membar feeds a CompareAndSwapX, + // an SCMemProj, a MergeMem then a final trailing MemBarCPUOrder and + // MemBarAcquire pair. // // MemBarRelease - // MemBarCPUOrder__(leading)_________________________ - // || \\ C \ - // MemBarVolatile (card mark) CompareAndSwapN/P CastP2X - // C | || M | | - // | LoadB | ______/| - // | | | / | - // | Cmp | / SCMemProj - // | / | / | - // If | / / - // | \ | / / - // IfFalse IfTrue | / / - // \ / \ |/ prec / - // \ / StoreCM / - // \ / | / - // Region . . . / - // | \ / - // | . . . \ / Bot - // | MergeMem - // | | - // MemBarCPUOrder - // MemBarAcquire (trailing) + // MemBarCPUOrder__(leading)_______________________ + // C / M | \\ C \ + // . . . | Bot CompareAndSwapN/P CastP2X + // | C / M | + // | CmpI | + // | / | + // | . . . | + // | IfTrue | + // | / | + // MemBarVolatile (card mark) | + // C | || M | | + // | LoadB | Bot ______/| + // | | | / | + // | Cmp | / SCMemProj + // | / | / | + // If | / / + // | \ | / / Bot + // IfFalse IfTrue | / / + // | / \ / / prec / + // . . . | / StoreCM / + // \ | / | raw / + // Region . . . / + // | \ / + // | . . . \ / Bot + // | MergeMem + // | / + // MemBarCPUOrder + // MemBarAcquire (trailing) // // This has a slightly different memory subgraph to the one seen - // previously but the core of it is the same as for the CAS normal - // sungraph + // previously but the core of it has a similar memory flow to the + // CAS normal subgraph: // // MemBarRelease // MemBarCPUOrder____ - // || \ . . . - // MemBarVolatile CompareAndSwapX . . . - // | \ | - // . . . SCMemProj - // | / . . . - // MergeMem - // | + // | \ . . . + // | CompareAndSwapX . . . + // | C / M | + // | CmpI | + // | / | + // | . . / + // Bot | IfTrue / + // | / / + // MemBarVolatile / + // | ... / + // StoreCM ... / + // | / + // . . . SCMemProj + // Raw \ / Bot + // MergeMem + // | // MemBarCPUOrder // MemBarAcquire // - // - // G1 is quite a lot more complicated. The nodes inserted on behalf - // of G1 may comprise: a pre-write graph which adds the old value to - // the SATB queue; the releasing store itself; and, finally, a - // post-write graph which performs a card mark. + // The G1 graph for a volatile object put is a lot more complicated. + // Nodes inserted on behalf of G1 may comprise: a pre-write graph + // which adds the old value to the SATB queue; the releasing store + // itself; and, finally, a post-write graph which performs a card + // mark. // // The pre-write graph may be omitted, but only when the put is // writing to a newly allocated (young gen) object and then only if @@ -1730,25 +1749,60 @@ source %{ // | CastP2X | StoreN/P[mo_release] | // | | | | // C | M | M | M | - // \ | | / + // \ | Raw | oop / Bot // . . . // (post write subtree elided) // . . . // C \ M / // MemBarVolatile (trailing) // + // Note that the three memory feeds into the post-write tree are an + // AliasRawIdx slice associated with the writes in the pre-write + // tree, an oop type slice from the StoreX specific to the type of + // the volatile field and the AliasBotIdx slice emanating from the + // leading membar. + // // n.b. the LoadB in this subgraph is not the card read -- it's a // read of the SATB queue active flag. // - // Once again the CAS graph is a minor variant on the above with the - // expected substitutions of CompareAndSawpX for StoreN/P and - // MemBarCPUOrder + MemBarAcquire for trailing MemBarVolatile. + // The CAS graph is once again a variant of the above with a + // CompareAndSwapX node and SCMemProj in place of the StoreX. The + // value from the CompareAndSwapX node is fed into the post-write + // graph aling with the AliasIdxRaw feed from the pre-barrier and + // the AliasIdxBot feeds from the leading membar and the ScMemProj. + // + // MemBarRelease (leading)____________ + // C | || M \ M \ M \ M \ . . . + // | LoadB \ LoadL LoadN \ + // | / \ \ + // If |\ \ + // | \ | \ \ + // IfFalse IfTrue | \ \ + // | | | \ \ + // | If | \ | + // | | \ | + // | \ | + // | . . . \ | + // | / | / \ | + // Region Phi[M] \ | + // | \ | \ | + // | \_____ | | | + // C | C \ | | | + // | CastP2X | CompareAndSwapX | + // | | res | | | + // C | M | | SCMemProj M | + // \ | Raw | | Bot / Bot + // . . . + // (post write subtree elided) + // . . . + // C \ M / + // MemBarVolatile (trailing) // // The G1 post-write subtree is also optional, this time when the // new value being written is either null or can be identified as a // newly allocated (young gen) object with no intervening control // flow. The latter cannot happen but the former may, in which case - // the card mark membar is omitted and the memory feeds form the + // the card mark membar is omitted and the memory feeds from the // leading membar and the SToreN/P are merged direct into the // trailing membar as per the normal subgraph. So, the only special // case which arises is when the post-write subgraph is generated. @@ -1770,94 +1824,106 @@ source %{ // // (pre-write subtree elided) // . . . . . . . . . . . . - // C | M | M | M | - // Region Phi[M] StoreN | - // | / \ | | - // / \_______ / \ | | - // C / C \ . . . \ | | - // If CastP2X . . . | | | - // / \ | | | - // / \ | | | - // IfFalse IfTrue | | | - // | | | | /| - // | If | | / | - // | / \ | | / | - // | / \ \ | / | - // | IfFalse IfTrue MergeMem | - // | . . . / \ / | - // | / \ / | - // | IfFalse IfTrue / | - // | . . . | / | - // | If / | - // | / \ / | - // | / \ / | - // | IfFalse IfTrue / | - // | . . . | / | - // | \ / | - // | \ / | - // | MemBarVolatile__(card mark) | - // | || C | M \ M \ | - // | LoadB If | | | - // | / \ | | | - // | . . . | | | - // | \ | | / - // | StoreCM | / - // | . . . | / - // | _________/ / - // | / _____________/ - // | . . . . . . | / / - // | | | / _________/ - // | | Phi[M] / / - // | | | / / - // | | | / / - // | Region . . . Phi[M] _____/ - // | / | / - // | | / - // | . . . . . . | / - // | / | / - // Region | | Phi[M] - // | | | / Bot - // \ MergeMem - // \ / - // MemBarVolatile + // C | M | M | M | + // Region Phi[M] StoreN | + // | Raw | oop | Bot | + // / \_______ |\ |\ |\ + // C / C \ . . . | \ | \ | \ + // If CastP2X . . . | \ | \ | \ + // / \ | \ | \ | \ + // / \ | \ | \ | \ + // IfFalse IfTrue | | | \ + // | | \ | / | + // | If \ | \ / \ | + // | / \ \ | / \ | + // | / \ \ | / \ | | + // | IfFalse IfTrue MergeMem \ | | + // | . . . / \ | \ | | + // | / \ | | | | + // | IfFalse IfTrue | | | | + // | . . . | | | | | + // | If / | | | + // | / \ / | | | + // | / \ / | | | + // | IfFalse IfTrue / | | | + // | . . . | / | | | + // | \ / | | | + // | \ / | | | + // | MemBarVolatile__(card mark ) | | | + // | || C | \ | | | + // | LoadB If | / | | + // | / \ Raw | / / / + // | . . . | / / / + // | \ | / / / + // | StoreCM / / / + // | | / / / + // | . . . / / + // | / / + // | . . . / / + // | | | / / / + // | | Phi[M] / / / + // | | | / / / + // | | | / / / + // | Region . . . Phi[M] / / + // | | | / / + // \ | | / / + // \ | . . . | / / + // \ | | / / + // Region Phi[M] / / + // | \ / / + // \ MergeMem + // \ / + // MemBarVolatile // - // As with CMS the initial MergeMem merges the AliasIdxBot Mem slice - // from the leading membar and the oopptr Mem slice from the Store - // into the card mark membar i.e. the memory flow to the card mark - // membar still looks like a normal graph. + // As with CMS + CondCardMark the first MergeMem merges the + // AliasIdxBot Mem slice from the leading membar and the oopptr Mem + // slice from the Store into the card mark membar. However, in this + // case it may also merge an AliasRawIdx mem slice from the pre + // barrier write. // - // The trailing MergeMem merges an AliasIdxBot Mem slice with other - // Mem slices (from the StoreCM and other card mark queue stores). - // However in this case the AliasIdxBot Mem slice does not come - // direct from the card mark membar. It is merged through a series - // of Phi nodes. These are needed to merge the AliasIdxBot Mem flow - // from the leading membar with the Mem feed from the card mark - // membar. Each Phi corresponds to one of the Ifs which may skip - // around the card mark membar. So when the If implementing the NULL - // value check has been elided the total number of Phis is 2 - // otherwise it is 3. + // The trailing MergeMem merges an AliasIdxBot Mem slice from the + // leading membar with an oop slice from the StoreN and an + // AliasRawIdx slice from the post barrier writes. In this case the + // AliasIdxRaw Mem slice is merged through a series of Phi nodes + // which combine feeds from the If regions in the post barrier + // subgraph. // - // The CAS graph when using G1GC also includes a pre-write subgraph - // and an optional post-write subgraph. Teh sam evarioations are - // introduced as for CMS with conditional card marking i.e. the - // StoreP/N is swapped for a CompareAndSwapP/N, the tariling - // MemBarVolatile for a MemBarCPUOrder + MemBarAcquire pair and the - // Mem feed from the CompareAndSwapP/N includes a precedence - // dependency feed to the StoreCM and a feed via an SCMemProj to the - // trailing membar. So, as before the configuration includes the - // normal CAS graph as a subgraph of the memory flow. + // So, for G1 the same characteristic subgraph arises as for CMS + + // CondCardMark. There is a normal subgraph feeding the card mark + // membar and a normal subgraph feeding the trailing membar. // - // So, the upshot is that in all cases the volatile put graph will - // include a *normal* memory subgraph betwen the leading membar and - // its child membar, either a volatile put graph (including a - // releasing StoreX) or a CAS graph (including a CompareAndSwapX). - // When that child is not a card mark membar then it marks the end - // of the volatile put or CAS subgraph. If the child is a card mark - // membar then the normal subgraph will form part of a volatile put - // subgraph if and only if the child feeds an AliasIdxBot Mem feed - // to a trailing barrier via a MergeMem. That feed is either direct - // (for CMS) or via 2 or 3 Phi nodes merging the leading barrier - // memory flow (for G1). + // The CAS graph when using G1GC also includes an optional + // post-write subgraph. It is very similar to the above graph except + // for a few details. + // + // - The control flow is gated by an additonal If which tests the + // result from the CompareAndSwapX node + // + // - The MergeMem which feeds the card mark membar only merges the + // AliasIdxBot slice from the leading membar and the AliasIdxRaw + // slice from the pre-barrier. It does not merge the SCMemProj + // AliasIdxBot slice. So, this subgraph does not look like the + // normal CAS subgraph. + // + // - The MergeMem which feeds the trailing membar merges the + // AliasIdxBot slice from the leading membar, the AliasIdxRaw slice + // from the post-barrier and the SCMemProj AliasIdxBot slice i.e. it + // has two AliasIdxBot input slices. However, this subgraph does + // still look like the normal CAS subgraph. + // + // So, the upshot is: + // + // In all cases a volatile put graph will include a *normal* + // volatile store subgraph betwen the leading membar and the + // trailing membar. It may also include a normal volatile store + // subgraph betwen the leading membar and the card mark membar. + // + // In all cases a CAS graph will contain a unique normal CAS graph + // feeding the trailing membar. + // + // In all cases where there is a card mark membar (either as part of + // a volatile object put or CAS) it will be fed by a MergeMem whose + // AliasIdxBot slice feed will be a leading membar. // // The predicates controlling generation of instructions for store // and barrier nodes employ a few simple helper functions (described @@ -1878,24 +1944,24 @@ source %{ opcode == Op_CompareAndSwapP); } - // leading_to_normal + // leading_to_trailing // //graph traversal helper which detects the normal case Mem feed from // a release membar (or, optionally, its cpuorder child) to a // dependent volatile membar i.e. it ensures that one or other of // the following Mem flow subgraph is present. // - // MemBarRelease - // MemBarCPUOrder {leading} - // | \ . . . - // | StoreN/P[mo_release] . . . - // | / - // MergeMem - // | - // MemBarVolatile {trailing or card mark} + // MemBarRelease {leading} + // {MemBarCPUOrder} {optional} + // Bot | \ . . . + // | StoreN/P[mo_release] . . . + // | / + // MergeMem + // | + // MemBarVolatile {not card mark} // - // MemBarRelease - // MemBarCPUOrder {leading} + // MemBarRelease {leading} + // {MemBarCPUOrder} {optional} // | \ . . . // | CompareAndSwapX . . . // | @@ -1906,6 +1972,23 @@ source %{ // MemBarCPUOrder // MemBarAcquire {trailing} // + // the predicate needs to be capable of distinguishing the following + // volatile put graph which may arises when a GC post barrier + // inserts a card mark membar + // + // MemBarRelease {leading} + // {MemBarCPUOrder}__ + // Bot | \ \ + // | StoreN/P \ + // | / \ | + // MergeMem \ | + // | \ | + // MemBarVolatile \ | + // {card mark} \ | + // MergeMem + // | + // {not card mark} MemBarVolatile + // // if the correct configuration is present returns the trailing // membar otherwise NULL. // @@ -1916,7 +1999,7 @@ source %{ // the returned value may be a card mark or trailing membar // - MemBarNode *leading_to_normal(MemBarNode *leading) + MemBarNode *leading_to_trailing(MemBarNode *leading) { assert((leading->Opcode() == Op_MemBarRelease || leading->Opcode() == Op_MemBarCPUOrder), @@ -1933,15 +2016,21 @@ source %{ StoreNode * st = NULL; LoadStoreNode *cas = NULL; MergeMemNode *mm = NULL; + MergeMemNode *mm2 = NULL; for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { x = mem->fast_out(i); if (x->is_MergeMem()) { if (mm != NULL) { - return NULL; + if (mm2 != NULL) { + // should not see more than 2 merge mems + return NULL; + } else { + mm2 = x->as_MergeMem(); + } + } else { + mm = x->as_MergeMem(); } - // two merge mems is one too many - mm = x->as_MergeMem(); } else if (x->is_Store() && x->as_Store()->is_release() && x->Opcode() != Op_StoreCM) { // two releasing stores/CAS nodes is one too many if (st != NULL || cas != NULL) { @@ -1961,13 +2050,13 @@ source %{ return NULL; } - // must have a merge if we also have st + // must have at least one merge if we also have st if (st && !mm) { return NULL; } - Node *y = NULL; if (cas) { + Node *y = NULL; // look for an SCMemProj for (DUIterator_Fast imax, i = cas->fast_outs(imax); i < imax; i++) { x = cas->fast_out(i); @@ -1987,10 +2076,29 @@ source %{ break; } } - if (mm == NULL) + if (mm == NULL) { return NULL; + } + MemBarNode *mbar = NULL; + // ensure the merge feeds a trailing membar cpuorder + acquire pair + for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { + x = mm->fast_out(i); + if (x->is_MemBar()) { + int opcode = x->Opcode(); + if (opcode == Op_MemBarCPUOrder) { + MemBarNode *z = x->as_MemBar(); + z = child_membar(z); + if (z != NULL && z->Opcode() == Op_MemBarAcquire) { + mbar = z; + } + } + break; + } + } + return mbar; } else { - // ensure the store feeds the existing mergemem; + Node *y = NULL; + // ensure the store feeds the first mergemem; for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { if (st->fast_out(i) == mm) { y = st; @@ -2000,55 +2108,89 @@ source %{ if (y == NULL) { return NULL; } - } - - MemBarNode *mbar = NULL; - // ensure the merge feeds to the expected type of membar - for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { - x = mm->fast_out(i); - if (x->is_MemBar()) { - int opcode = x->Opcode(); - if (opcode == Op_MemBarVolatile && st) { - mbar = x->as_MemBar(); - } else if (cas && opcode == Op_MemBarCPUOrder) { - MemBarNode *y = x->as_MemBar(); - y = child_membar(y); - if (y != NULL && y->Opcode() == Op_MemBarAcquire) { - mbar = y; + if (mm2 != NULL) { + // ensure the store feeds the second mergemem; + y = NULL; + for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { + if (st->fast_out(i) == mm2) { + y = st; } } - break; + if (y == NULL) { + return NULL; + } + } + + MemBarNode *mbar = NULL; + // ensure the first mergemem feeds a volatile membar + for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { + x = mm->fast_out(i); + if (x->is_MemBar()) { + int opcode = x->Opcode(); + if (opcode == Op_MemBarVolatile) { + mbar = x->as_MemBar(); + } + break; + } + } + if (mm2 == NULL) { + // this is our only option for a trailing membar + return mbar; + } + // ensure the second mergemem feeds a volatile membar + MemBarNode *mbar2 = NULL; + for (DUIterator_Fast imax, i = mm2->fast_outs(imax); i < imax; i++) { + x = mm2->fast_out(i); + if (x->is_MemBar()) { + int opcode = x->Opcode(); + if (opcode == Op_MemBarVolatile) { + mbar2 = x->as_MemBar(); + } + break; + } + } + // if we have two merge mems we must have two volatile membars + if (mbar == NULL || mbar2 == NULL) { + return NULL; + } + // return the trailing membar + if (is_card_mark_membar(mbar2)) { + return mbar; + } else { + if (is_card_mark_membar(mbar)) { + return mbar2; + } else { + return NULL; + } } } - - return mbar; } - // normal_to_leading + // trailing_to_leading // // graph traversal helper which detects the normal case Mem feed - // from either a card mark or a trailing membar to a preceding - // release membar (optionally its cpuorder child) i.e. it ensures - // that one or other of the following Mem flow subgraphs is present. + // from a trailing membar to a preceding release membar (optionally + // its cpuorder child) i.e. it ensures that one or other of the + // following Mem flow subgraphs is present. // - // MemBarRelease - // MemBarCPUOrder {leading} - // | \ . . . - // | StoreN/P[mo_release] . . . - // | / - // MergeMem - // | - // MemBarVolatile {card mark or trailing} + // MemBarRelease {leading} + // MemBarCPUOrder {optional} + // | Bot | \ . . . + // | | StoreN/P[mo_release] . . . + // | | / + // | MergeMem + // | | + // MemBarVolatile {not card mark} // - // MemBarRelease - // MemBarCPUOrder {leading} + // MemBarRelease {leading} + // MemBarCPUOrder {optional} // | \ . . . // | CompareAndSwapX . . . // | // . . . SCMemProj // \ | // | MergeMem - // | / + // | | // MemBarCPUOrder // MemBarAcquire {trailing} // @@ -2058,15 +2200,20 @@ source %{ // if the configuration is present returns the cpuorder member for // preference or when absent the release membar otherwise NULL. // - // n.b. the input membar is expected to be a MemBarVolatile but - // need not be a card mark membar. + // n.b. the input membar is expected to be a MemBarVolatile or + // MemBarAcquire. if it is a MemBarVolatile it must *not* be a card + // mark membar. - MemBarNode *normal_to_leading(const MemBarNode *barrier) + MemBarNode *trailing_to_leading(const MemBarNode *barrier) { // input must be a volatile membar assert((barrier->Opcode() == Op_MemBarVolatile || barrier->Opcode() == Op_MemBarAcquire), "expecting a volatile or an acquire membar"); + + assert((barrier->Opcode() != Op_MemBarVolatile) || + !is_card_mark_membar(barrier), + "not expecting a card mark membar"); Node *x; bool is_cas = barrier->Opcode() == Op_MemBarAcquire; @@ -2179,169 +2326,35 @@ source %{ return NULL; } - // card_mark_to_trailing + // card_mark_to_leading // - // graph traversal helper which detects extra, non-normal Mem feed - // from a card mark volatile membar to a trailing membar i.e. it - // ensures that one of the following three GC post-write Mem flow - // subgraphs is present. + // graph traversal helper which traverses from a card mark volatile + // membar to a leading membar i.e. it ensures that the following Mem + // flow subgraph is present. // - // 1) - // . . . - // | - // MemBarVolatile (card mark) - // | | - // | StoreCM - // | | - // | . . . - // Bot | / - // MergeMem - // | - // | - // MemBarVolatile {trailing} - // - // 2) - // MemBarRelease/CPUOrder (leading) - // | - // | - // |\ . . . - // | \ | - // | \ MemBarVolatile (card mark) - // | \ | | - // \ \ | StoreCM . . . - // \ \ | - // \ Phi - // \ / - // Phi . . . + // MemBarRelease {leading} + // {MemBarCPUOrder} {optional} + // | . . . // Bot | / - // MergeMem + // MergeMem // | - // MemBarVolatile {trailing} + // MemBarVolatile (card mark) + // | \ + // . . . StoreCM // + // if the configuration is present returns the cpuorder member for + // preference or when absent the release membar otherwise NULL. // - // 3) - // MemBarRelease/CPUOrder (leading) - // | - // |\ - // | \ - // | \ . . . - // | \ | - // |\ \ MemBarVolatile (card mark) - // | \ \ | | - // | \ \ | StoreCM . . . - // | \ \ | - // \ \ Phi - // \ \ / - // \ Phi - // \ / - // Phi . . . - // Bot | / - // MergeMem - // | - // | - // MemBarVolatile {trailing} - // - // configuration 1 is only valid if UseConcMarkSweepGC && - // UseCondCardMark - // - // configurations 2 and 3 are only valid if UseG1GC. - // - // if a valid configuration is present returns the trailing membar - // otherwise NULL. - // - // n.b. the supplied membar is expected to be a card mark - // MemBarVolatile i.e. the caller must ensure the input node has the - // correct operand and feeds Mem to a StoreCM node + // n.b. the input membar is expected to be a MemBarVolatile amd must + // be a card mark membar. - MemBarNode *card_mark_to_trailing(const MemBarNode *barrier) + MemBarNode *card_mark_to_leading(const MemBarNode *barrier) { // input must be a card mark volatile membar assert(is_card_mark_membar(barrier), "expecting a card mark membar"); - Node *feed = barrier->proj_out(TypeFunc::Memory); - Node *x; - MergeMemNode *mm = NULL; - - const int MAX_PHIS = 3; // max phis we will search through - int phicount = 0; // current search count - - bool retry_feed = true; - while (retry_feed) { - // see if we have a direct MergeMem feed - for (DUIterator_Fast imax, i = feed->fast_outs(imax); i < imax; i++) { - x = feed->fast_out(i); - // the correct Phi will be merging a Bot memory slice - if (x->is_MergeMem()) { - mm = x->as_MergeMem(); - break; - } - } - if (mm) { - retry_feed = false; - } else if (UseG1GC & phicount++ < MAX_PHIS) { - // the barrier may feed indirectly via one or two Phi nodes - PhiNode *phi = NULL; - for (DUIterator_Fast imax, i = feed->fast_outs(imax); i < imax; i++) { - x = feed->fast_out(i); - // the correct Phi will be merging a Bot memory slice - if (x->is_Phi() && x->adr_type() == TypePtr::BOTTOM) { - phi = x->as_Phi(); - break; - } - } - if (!phi) { - return NULL; - } - // look for another merge below this phi - feed = phi; - } else { - // couldn't find a merge - return NULL; - } - } - - // sanity check this feed turns up as the expected slice - assert(mm->as_MergeMem()->in(Compile::AliasIdxBot) == feed, "expecting membar to feed AliasIdxBot slice to Merge"); - - MemBarNode *trailing = NULL; - // be sure we have a trailing membar the merge - for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { - x = mm->fast_out(i); - if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) { - trailing = x->as_MemBar(); - break; - } - } - - return trailing; - } - - // trailing_to_card_mark - // - // graph traversal helper which detects extra, non-normal Mem feed - // from a trailing volatile membar to a preceding card mark volatile - // membar i.e. it identifies whether one of the three possible extra - // GC post-write Mem flow subgraphs is present - // - // this predicate checks for the same flow as the previous predicate - // but starting from the bottom rather than the top. - // - // if the configuration is present returns the card mark membar - // otherwise NULL - // - // n.b. the supplied membar is expected to be a trailing - // MemBarVolatile i.e. the caller must ensure the input node has the - // correct opcode - - MemBarNode *trailing_to_card_mark(const MemBarNode *trailing) - { - assert(trailing->Opcode() == Op_MemBarVolatile, - "expecting a volatile membar"); - assert(!is_card_mark_membar(trailing), - "not expecting a card mark membar"); - // the Mem feed to the membar should be a merge - Node *x = trailing->in(TypeFunc::Memory); + Node *x = barrier->in(TypeFunc::Memory); if (!x->is_MergeMem()) { return NULL; } @@ -2349,118 +2362,20 @@ source %{ MergeMemNode *mm = x->as_MergeMem(); x = mm->in(Compile::AliasIdxBot); - // with G1 we may possibly see a Phi or two before we see a Memory - // Proj from the card mark membar - const int MAX_PHIS = 3; // max phis we will search through - int phicount = 0; // current search count - - bool retry_feed = !x->is_Proj(); - - while (retry_feed) { - if (UseG1GC && x->is_Phi() && phicount++ < MAX_PHIS) { - PhiNode *phi = x->as_Phi(); - ProjNode *proj = NULL; - PhiNode *nextphi = NULL; - bool found_leading = false; - for (uint i = 1; i < phi->req(); i++) { - x = phi->in(i); - if (x->is_Phi()) { - nextphi = x->as_Phi(); - } else if (x->is_Proj()) { - int opcode = x->in(0)->Opcode(); - if (opcode == Op_MemBarVolatile) { - proj = x->as_Proj(); - } else if (opcode == Op_MemBarRelease || - opcode == Op_MemBarCPUOrder) { - // probably a leading membar - found_leading = true; - } - } - } - // if we found a correct looking proj then retry from there - // otherwise we must see a leading and a phi or this the - // wrong config - if (proj != NULL) { - x = proj; - retry_feed = false; - } else if (found_leading && nextphi != NULL) { - // retry from this phi to check phi2 - x = nextphi; - } else { - // not what we were looking for - return NULL; - } - } else { - return NULL; - } - } - // the proj has to come from the card mark membar - x = x->in(0); if (!x->is_MemBar()) { return NULL; } - MemBarNode *card_mark_membar = x->as_MemBar(); + MemBarNode *leading = x->as_MemBar(); - if (!is_card_mark_membar(card_mark_membar)) { - return NULL; - } - - return card_mark_membar; - } - - // trailing_to_leading - // - // graph traversal helper which checks the Mem flow up the graph - // from a (non-card mark) trailing membar attempting to locate and - // return an associated leading membar. it first looks for a - // subgraph in the normal configuration (relying on helper - // normal_to_leading). failing that it then looks for one of the - // possible post-write card mark subgraphs linking the trailing node - // to a the card mark membar (relying on helper - // trailing_to_card_mark), and then checks that the card mark membar - // is fed by a leading membar (once again relying on auxiliary - // predicate normal_to_leading). - // - // if the configuration is valid returns the cpuorder member for - // preference or when absent the release membar otherwise NULL. - // - // n.b. the input membar is expected to be either a volatile or - // acquire membar but in the former case must *not* be a card mark - // membar. - - MemBarNode *trailing_to_leading(const MemBarNode *trailing) - { - assert((trailing->Opcode() == Op_MemBarAcquire || - trailing->Opcode() == Op_MemBarVolatile), - "expecting an acquire or volatile membar"); - assert((trailing->Opcode() != Op_MemBarVolatile || - !is_card_mark_membar(trailing)), - "not expecting a card mark membar"); - - MemBarNode *leading = normal_to_leading(trailing); - - if (leading) { + if (leading_membar(leading)) { return leading; } - // nothing more to do if this is an acquire - if (trailing->Opcode() == Op_MemBarAcquire) { - return NULL; - } - - MemBarNode *card_mark_membar = trailing_to_card_mark(trailing); - - if (!card_mark_membar) { - return NULL; - } - - return normal_to_leading(card_mark_membar); + return NULL; } - // predicates controlling emit of ldr/ldar and associated dmb - bool unnecessary_acquire(const Node *barrier) { assert(barrier->is_MemBar(), "expecting a membar"); @@ -2675,19 +2590,8 @@ bool unnecessary_release(const Node *n) } // must start with a normal feed - MemBarNode *child_barrier = leading_to_normal(barrier); + MemBarNode *trailing = leading_to_trailing(barrier); - if (!child_barrier) { - return false; - } - - if (!is_card_mark_membar(child_barrier)) { - // this is the trailing membar and we are done - return true; - } - - // must be sure this card mark feeds a trailing membar - MemBarNode *trailing = card_mark_to_trailing(child_barrier); return (trailing != NULL); } @@ -2709,7 +2613,7 @@ bool unnecessary_volatile(const Node *n) } // ok, if it's not a card mark then we still need to check if it is - // a trailing membar of a volatile put hgraph. + // a trailing membar of a volatile put graph. return (trailing_to_leading(mbvol) != NULL); } @@ -2759,20 +2663,9 @@ bool needs_releasing_store(const Node *n) } // does this lead a normal subgraph? - MemBarNode *mbvol = leading_to_normal(barrier); + MemBarNode *trailing = leading_to_trailing(barrier); - if (!mbvol) { - return false; - } - - // all done unless this is a card mark - if (!is_card_mark_membar(mbvol)) { - return true; - } - - // we found a card mark -- just make sure we have a trailing barrier - - return (card_mark_to_trailing(mbvol) != NULL); + return (trailing != NULL); } // predicate controlling translation of CAS @@ -2814,7 +2707,7 @@ bool needs_acquiring_load_exclusive(const Node *n) "CAS not fed by cpuorder+release membar pair!"); // does this lead a normal subgraph? - MemBarNode *mbar = leading_to_normal(barrier); + MemBarNode *mbar = leading_to_trailing(barrier); assert(mbar != NULL, "CAS not embedded in normal graph!"); @@ -2835,48 +2728,27 @@ bool unnecessary_storestore(const Node *storecm) // we only ever need to generate a dmb ishst between an object put // and the associated card mark when we are using CMS without - // conditional card marking + // conditional card marking. Any other occurence will happen when + // performing a card mark using CMS with conditional card marking or + // G1. In those cases the preceding MamBarVolatile will be + // translated to a dmb ish which guarantes visibility of the + // preceding StoreN/P before this StoreCM if (!UseConcMarkSweepGC || UseCondCardMark) { return true; } - // if we are implementing volatile puts using barriers then the - // object put as an str so we must insert the dmb ishst + // if we are implementing volatile puts using barriers then we must + // insert the dmb ishst if (UseBarriersForVolatile) { return false; } - // we can omit the dmb ishst if this StoreCM is part of a volatile - // put because in thta case the put will be implemented by stlr - // - // we need to check for a normal subgraph feeding this StoreCM. - // that means the StoreCM must be fed Memory from a leading membar, - // either a MemBarRelease or its dependent MemBarCPUOrder, and the - // leading membar must be part of a normal subgraph + // we must be using CMS with conditional card marking so we ahve to + // generate the StoreStore - Node *x = storecm->in(StoreNode::Memory); - - if (!x->is_Proj()) { - return false; - } - - x = x->in(0); - - if (!x->is_MemBar()) { - return false; - } - - MemBarNode *leading = x->as_MemBar(); - - // reject invalid candidates - if (!leading_membar(leading)) { - return false; - } - - // we can omit the StoreStore if it is the head of a normal subgraph - return (leading_to_normal(leading) != NULL); + return false; } diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index f3389bd969b..a47897db8c1 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -3149,6 +3149,19 @@ Node* GraphKit::insert_mem_bar_volatile(int opcode, int alias_idx, Node* precede return membar; } +void GraphKit::insert_store_load_for_barrier() { + Node* mem = reset_memory(); + MemBarNode* mb = MemBarNode::make(C, Op_MemBarVolatile, Compile::AliasIdxBot); + mb->init_req(TypeFunc::Control, control()); + mb->init_req(TypeFunc::Memory, mem); + Node* membar = _gvn.transform(mb); + set_control(_gvn.transform(new ProjNode(membar, TypeFunc::Control))); + Node* newmem = _gvn.transform(new ProjNode(membar, TypeFunc::Memory)); + set_all_memory(mem); + set_memory(newmem, Compile::AliasIdxRaw); +} + + //------------------------------shared_lock------------------------------------ // Emit locking code. FastLockNode* GraphKit::shared_lock(Node* obj) { @@ -3840,7 +3853,7 @@ void GraphKit::write_barrier_post(Node* oop_store, BasicType bt = T_BYTE; if (UseConcMarkSweepGC && UseCondCardMark) { - insert_mem_bar(Op_MemBarVolatile); // StoreLoad barrier + insert_store_load_for_barrier(); __ sync_kit(this); } @@ -4280,8 +4293,7 @@ void GraphKit::g1_write_barrier_post(Node* oop_store, __ if_then(card_val, BoolTest::ne, young_card); { sync_kit(ideal); - // Use Op_MemBarVolatile to achieve the effect of a StoreLoad barrier. - insert_mem_bar(Op_MemBarVolatile, oop_store); + insert_store_load_for_barrier(); __ sync_kit(this); Node* card_val_reload = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp index 7bb1f6946db..218e937818b 100644 --- a/hotspot/src/share/vm/opto/graphKit.hpp +++ b/hotspot/src/share/vm/opto/graphKit.hpp @@ -834,6 +834,7 @@ class GraphKit : public Phase { int next_monitor(); Node* insert_mem_bar(int opcode, Node* precedent = NULL); Node* insert_mem_bar_volatile(int opcode, int alias_idx, Node* precedent = NULL); + void insert_store_load_for_barrier(); // Optional 'precedent' is appended as an extra edge, to force ordering. FastLockNode* shared_lock(Node* obj); void shared_unlock(Node* box, Node* obj); From db36e29ab02080fa72d210f6e69cee857870fc7a Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 16 Feb 2016 12:54:20 +0100 Subject: [PATCH 011/129] 8149916: Test case for 8149797 Reviewed-by: kvn --- .../c2/TestDominatingDeadCheckCast.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 hotspot/test/compiler/c2/TestDominatingDeadCheckCast.java diff --git a/hotspot/test/compiler/c2/TestDominatingDeadCheckCast.java b/hotspot/test/compiler/c2/TestDominatingDeadCheckCast.java new file mode 100644 index 00000000000..3c8f153a17c --- /dev/null +++ b/hotspot/test/compiler/c2/TestDominatingDeadCheckCast.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8149797 + * @summary node replaced by dominating dead cast during parsing + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:TypeProfileLevel=200 -XX:CompileCommand=dontinline,TestDominatingDeadCheckCast::not_inlined TestDominatingDeadCheckCast + * + */ + +public class TestDominatingDeadCheckCast { + + static class A { + int f; + } + + static class B extends A { + } + + static A not_inlined() { + return new A(); + } + + static void inlined(A param) { + param.f = 42; + } + + static A field; + + static void test(boolean flag1, boolean flag2, boolean flag3, boolean flag4, boolean flag5) { + // Go through memory rather than through a local to defeat C2's replace_in_map + field = not_inlined(); + // Speculation adds a CheckCast on entry of this inlined + // method for the parameter + inlined(field); + // Walk up the dominators is depth limited, make the CheckCast + // above unreachable from the last inlined call + if (flag1) { + if (flag2) { + if (flag3) { + // Speculation adds a CheckCast on entry of this + // inlined method for the parameter. This + // CheckCast is replaced by the CheckCast of the + // first inlined method call but the replaced + // CheckCast is still around during parsing. + inlined(field); + // Same as above, some useless control + if (flag4) { + if (flag5) { + // Speculation adds a CheckCast on entry + // of this inlined method for the + // parameter. This CheckCast is replaced + // by the dead CheckCast of the previous + // inlined() call. + inlined(field); + } + } + } + } + } + } + + static public void main(String[] args) { + field = new A(); + for (int i = 0; i < 20000; i++) { + test(true, true, true, true, true); + } + } +} From 98eca9ebe8872f0e2227893a8aa4f19d8f74974d Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 17 Feb 2016 10:59:04 +0100 Subject: [PATCH 012/129] 8148786: xml.tranform fails on x86-64 CCP computes wrong type for CountedLoop iv Phi Reviewed-by: kvn --- hotspot/src/share/vm/opto/loopnode.hpp | 17 +++++++-- hotspot/src/share/vm/opto/phaseX.cpp | 52 ++++++++++++++++++++------ hotspot/src/share/vm/opto/phaseX.hpp | 2 +- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp index b0f3ad5d2a5..c853a2a6145 100644 --- a/hotspot/src/share/vm/opto/loopnode.hpp +++ b/hotspot/src/share/vm/opto/loopnode.hpp @@ -285,20 +285,29 @@ public: Node *incr() const { Node *tmp = cmp_node(); return (tmp && tmp->req()==3) ? tmp->in(1) : NULL; } Node *limit() const { Node *tmp = cmp_node(); return (tmp && tmp->req()==3) ? tmp->in(2) : NULL; } Node *stride() const { Node *tmp = incr (); return (tmp && tmp->req()==3) ? tmp->in(2) : NULL; } - Node *phi() const { Node *tmp = incr (); return (tmp && tmp->req()==3) ? tmp->in(1) : NULL; } Node *init_trip() const { Node *tmp = phi (); return (tmp && tmp->req()==3) ? tmp->in(1) : NULL; } int stride_con() const; bool stride_is_con() const { Node *tmp = stride (); return (tmp != NULL && tmp->is_Con()); } BoolTest::mask test_trip() const { return in(TestValue)->as_Bool()->_test._test; } + PhiNode *phi() const { + Node *tmp = incr(); + if (tmp && tmp->req() == 3) { + Node* phi = tmp->in(1); + if (phi->is_Phi()) { + return phi->as_Phi(); + } + } + return NULL; + } CountedLoopNode *loopnode() const { // The CountedLoopNode that goes with this CountedLoopEndNode may // have been optimized out by the IGVN so be cautious with the // pattern matching on the graph - if (phi() == NULL) { + PhiNode* iv_phi = phi(); + if (iv_phi == NULL) { return NULL; } - assert(phi()->is_Phi(), "should be PhiNode"); - Node *ln = phi()->in(0); + Node *ln = iv_phi->in(0); if (ln->is_CountedLoop() && ln->as_CountedLoop()->loopexit() == this) { return (CountedLoopNode*)ln; } diff --git a/hotspot/src/share/vm/opto/phaseX.cpp b/hotspot/src/share/vm/opto/phaseX.cpp index 1f6de0d1700..f925cd5ef27 100644 --- a/hotspot/src/share/vm/opto/phaseX.cpp +++ b/hotspot/src/share/vm/opto/phaseX.cpp @@ -1471,6 +1471,27 @@ void PhaseIterGVN::add_users_to_worklist0( Node *n ) { } } +// Return counted loop Phi if as a counted loop exit condition, cmp +// compares the the induction variable with n +static PhiNode* countedloop_phi_from_cmp(CmpINode* cmp, Node* n) { + for (DUIterator_Fast imax, i = cmp->fast_outs(imax); i < imax; i++) { + Node* bol = cmp->fast_out(i); + for (DUIterator_Fast i2max, i2 = bol->fast_outs(i2max); i2 < i2max; i2++) { + Node* iff = bol->fast_out(i2); + if (iff->is_CountedLoopEnd()) { + CountedLoopEndNode* cle = iff->as_CountedLoopEnd(); + if (cle->limit() == n) { + PhiNode* phi = cle->phi(); + if (phi != NULL) { + return phi; + } + } + } + } + } + return NULL; +} + void PhaseIterGVN::add_users_to_worklist( Node *n ) { add_users_to_worklist0(n); @@ -1500,18 +1521,7 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) { Node* bol = use->raw_out(0); if (bol->outcnt() > 0) { Node* iff = bol->raw_out(0); - if (use_op == Op_CmpI && - iff->is_CountedLoopEnd()) { - CountedLoopEndNode* cle = iff->as_CountedLoopEnd(); - if (cle->limit() == n && cle->phi() != NULL) { - // If an opaque node feeds into the limit condition of a - // CountedLoop, we need to process the Phi node for the - // induction variable when the opaque node is removed: - // the range of values taken by the Phi is now known and - // so its type is also known. - _worklist.push(cle->phi()); - } - } else if (iff->outcnt() == 2) { + if (iff->outcnt() == 2) { // Look for the 'is_x2logic' pattern: "x ? : 0 : 1" and put the // phi merging either 0 or 1 onto the worklist Node* ifproj0 = iff->raw_out(0); @@ -1526,6 +1536,15 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) { } } if (use_op == Op_CmpI) { + Node* phi = countedloop_phi_from_cmp((CmpINode*)use, n); + if (phi != NULL) { + // If an opaque node feeds into the limit condition of a + // CountedLoop, we need to process the Phi node for the + // induction variable when the opaque node is removed: + // the range of values taken by the Phi is now known and + // so its type is also known. + _worklist.push(phi); + } Node* in1 = use->in(1); for (uint i = 0; i < in1->outcnt(); i++) { if (in1->raw_out(i)->Opcode() == Op_CastII) { @@ -1714,6 +1733,15 @@ void PhaseCCP::analyze() { } } } + // If n is used in a counted loop exit condition then the type + // of the counted loop's Phi depends on the type of n. See + // PhiNode::Value(). + if (m_op == Op_CmpI) { + PhiNode* phi = countedloop_phi_from_cmp((CmpINode*)m, n); + if (phi != NULL) { + worklist.push(phi); + } + } } } } diff --git a/hotspot/src/share/vm/opto/phaseX.hpp b/hotspot/src/share/vm/opto/phaseX.hpp index 837118d177a..6ef389e8649 100644 --- a/hotspot/src/share/vm/opto/phaseX.hpp +++ b/hotspot/src/share/vm/opto/phaseX.hpp @@ -431,7 +431,7 @@ public: // Phase for iteratively performing local, pessimistic GVN-style optimizations. // and ideal transformations on the graph. class PhaseIterGVN : public PhaseGVN { - private: +private: bool _delay_transform; // When true simply register the node when calling transform // instead of actually optimizing it From 8dd35ed3dd37a2f0a931290d0a9bf4ab8486ffb1 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Wed, 17 Feb 2016 14:06:45 +0000 Subject: [PATCH 013/129] 8150045: arraycopy causes segfaults in SATB during garbage collection Reviewed-by: roland --- .../cpu/aarch64/vm/stubGenerator_aarch64.cpp | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp index 554495da44e..64833c5ccc4 100644 --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp @@ -666,7 +666,7 @@ class StubGenerator: public StubCodeGenerator { // count - element count // tmp - scratch register // - // Destroy no registers! + // Destroy no registers except rscratch1 and rscratch2 // void gen_write_ref_array_pre_barrier(Register addr, Register count, bool dest_uninitialized) { BarrierSet* bs = Universe::heap()->barrier_set(); @@ -674,12 +674,13 @@ class StubGenerator: public StubCodeGenerator { case BarrierSet::G1SATBCTLogging: // With G1, don't generate the call if we statically know that the target in uninitialized if (!dest_uninitialized) { - __ push(RegSet::range(r0, r29), sp); // integer registers except lr & sp + __ push_call_clobbered_registers(); if (count == c_rarg0) { if (addr == c_rarg1) { // exactly backwards!! - __ stp(c_rarg0, c_rarg1, __ pre(sp, -2 * wordSize)); - __ ldp(c_rarg1, c_rarg0, __ post(sp, -2 * wordSize)); + __ mov(rscratch1, c_rarg0); + __ mov(c_rarg0, c_rarg1); + __ mov(c_rarg1, rscratch1); } else { __ mov(c_rarg1, count); __ mov(c_rarg0, addr); @@ -689,7 +690,7 @@ class StubGenerator: public StubCodeGenerator { __ mov(c_rarg1, count); } __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre), 2); - __ pop(RegSet::range(r0, r29), sp); // integer registers except lr & sp } + __ pop_call_clobbered_registers(); break; case BarrierSet::CardTableForRS: case BarrierSet::CardTableExtension: @@ -719,7 +720,7 @@ class StubGenerator: public StubCodeGenerator { case BarrierSet::G1SATBCTLogging: { - __ push(RegSet::range(r0, r29), sp); // integer registers except lr & sp + __ push_call_clobbered_registers(); // must compute element count unless barrier set interface is changed (other platforms supply count) assert_different_registers(start, end, scratch); __ lea(scratch, Address(end, BytesPerHeapOop)); @@ -728,7 +729,7 @@ class StubGenerator: public StubCodeGenerator { __ mov(c_rarg0, start); __ mov(c_rarg1, scratch); __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), 2); - __ pop(RegSet::range(r0, r29), sp); // integer registers except lr & sp } + __ pop_call_clobbered_registers(); } break; case BarrierSet::CardTableForRS: @@ -1394,10 +1395,10 @@ class StubGenerator: public StubCodeGenerator { // no-overlap entry point used by generate_conjoint_long_oop_copy(). // address generate_disjoint_oop_copy(bool aligned, address *entry, - const char *name, bool dest_uninitialized = false) { + const char *name, bool dest_uninitialized) { const bool is_oop = true; const size_t size = UseCompressedOops ? sizeof (jint) : sizeof (jlong); - return generate_disjoint_copy(size, aligned, is_oop, entry, name); + return generate_disjoint_copy(size, aligned, is_oop, entry, name, dest_uninitialized); } // Arguments: @@ -1412,10 +1413,11 @@ class StubGenerator: public StubCodeGenerator { // address generate_conjoint_oop_copy(bool aligned, address nooverlap_target, address *entry, - const char *name, bool dest_uninitialized = false) { + const char *name, bool dest_uninitialized) { const bool is_oop = true; const size_t size = UseCompressedOops ? sizeof (jint) : sizeof (jlong); - return generate_conjoint_copy(size, aligned, is_oop, nooverlap_target, entry, name); + return generate_conjoint_copy(size, aligned, is_oop, nooverlap_target, entry, + name, dest_uninitialized); } @@ -1522,6 +1524,8 @@ class StubGenerator: public StubCodeGenerator { } #endif //ASSERT + gen_write_ref_array_pre_barrier(to, count, dest_uninitialized); + // save the original count __ mov(count_save, count); @@ -1988,9 +1992,11 @@ class StubGenerator: public StubCodeGenerator { bool aligned = !UseCompressedOops; StubRoutines::_arrayof_oop_disjoint_arraycopy - = generate_disjoint_oop_copy(aligned, &entry, "arrayof_oop_disjoint_arraycopy"); + = generate_disjoint_oop_copy(aligned, &entry, "arrayof_oop_disjoint_arraycopy", + /*dest_uninitialized*/false); StubRoutines::_arrayof_oop_arraycopy - = generate_conjoint_oop_copy(aligned, entry, &entry_oop_arraycopy, "arrayof_oop_arraycopy"); + = generate_conjoint_oop_copy(aligned, entry, &entry_oop_arraycopy, "arrayof_oop_arraycopy", + /*dest_uninitialized*/false); // Aligned versions without pre-barriers StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit = generate_disjoint_oop_copy(aligned, &entry, "arrayof_oop_disjoint_arraycopy_uninit", From 1e654fe813b220aa97d80ae2b6320a2002dd3aa2 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 19 Feb 2016 11:16:38 +0300 Subject: [PATCH 014/129] 8150102: C1 should fold arraylength for constant/trusted arrays Reviewed-by: vlivanov, kvn --- hotspot/src/share/vm/c1/c1_Canonicalizer.cpp | 38 ++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp index e06aa581833..48b814531e4 100644 --- a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp +++ b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp @@ -222,29 +222,31 @@ void Canonicalizer::do_StoreField (StoreField* x) { } void Canonicalizer::do_ArrayLength (ArrayLength* x) { - NewArray* array = x->array()->as_NewArray(); - if (array != NULL && array->length() != NULL) { - Constant* length = array->length()->as_Constant(); - if (length != NULL) { - // do not use the Constant itself, but create a new Constant - // with same value Otherwise a Constant is live over multiple - // blocks without being registered in a state array. + NewArray* na; + Constant* ct; + + if ((na = x->array()->as_NewArray()) != NULL) { + // New arrays might have the known length. + // Do not use the Constant itself, but create a new Constant + // with same value Otherwise a Constant is live over multiple + // blocks without being registered in a state array. + Constant* length; + if (na->length() != NULL && + (length = na->length()->as_Constant()) != NULL) { assert(length->type()->as_IntConstant() != NULL, "array length must be integer"); set_constant(length->type()->as_IntConstant()->value()); } + + } else if ((ct = x->array()->as_Constant()) != NULL) { + // Constant arrays have constant lengths. + set_constant(ct->type()->as_ArrayConstant()->value()->length()); + +#ifdef ASSERT } else { LoadField* lf = x->array()->as_LoadField(); - if (lf != NULL) { - ciField* field = lf->field(); - if (field->is_constant() && field->is_static()) { - // final static field - ciObject* c = field->constant_value().as_object(); - if (c->is_array()) { - ciArray* array = (ciArray*) c; - set_constant(array->length()); - } - } - } + bool is_static_constant = (lf != NULL) && lf->field()->is_constant() && lf->field()->is_static(); + assert(!is_static_constant, "Constant field loads are folded during parsing"); +#endif // ASSERT } } From 36e011b2f09ce3e16cd4009156421b024e16fe89 Mon Sep 17 00:00:00 2001 From: Jamsheed Mohammed C M Date: Mon, 22 Feb 2016 23:37:29 -0800 Subject: [PATCH 015/129] 8145333: -XX:+EnableJVMCI -XX:+UseJVMCICompiler -XX:-EnableJVMCI makes JVM crash JVMCI Flags are checked for consistency after parse. Reviewed-by: twisti --- .../jvmci/commandLineFlagConstraintsJVMCI.cpp | 51 ----- .../jvmci/commandLineFlagConstraintsJVMCI.hpp | 40 ---- hotspot/src/share/vm/jvmci/jvmci_globals.cpp | 184 ++++++++++++++++++ hotspot/src/share/vm/jvmci/jvmci_globals.hpp | 21 +- hotspot/src/share/vm/runtime/arguments.cpp | 14 ++ hotspot/src/share/vm/runtime/arguments.hpp | 5 +- .../runtime/commandLineFlagConstraintList.cpp | 14 -- 7 files changed, 210 insertions(+), 119 deletions(-) delete mode 100644 hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp delete mode 100644 hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp diff --git a/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp b/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp deleted file mode 100644 index 6481aaddca2..00000000000 --- a/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "jvmci/commandLineFlagConstraintsJVMCI.hpp" -#include "runtime/arguments.hpp" -#include "runtime/globals.hpp" -#include "utilities/defaultStream.hpp" - -Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(bool value, bool verbose) { - if (!EnableJVMCI) { - if (verbose == true) { - jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); - } - return Flag::VIOLATES_CONSTRAINT; - } else { - return Flag::SUCCESS; - } -} - -Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(intx value, bool verbose) { - if (!EnableJVMCI) { - if (verbose == true) { - jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); - } - return Flag::VIOLATES_CONSTRAINT; - } else { - return Flag::SUCCESS; - } -} diff --git a/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp b/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp deleted file mode 100644 index 35f47f9967d..00000000000 --- a/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP -#define SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP - -#include "runtime/globals.hpp" -#include "utilities/globalDefinitions.hpp" - -/* - * Here we have JVMCI arguments constraints functions, which are called automatically - * whenever flag's value changes. If the constraint fails the function should return - * an appropriate error value. - */ - -Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(bool value, bool verbose); -Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(intx value, bool verbose); - -#endif /* SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP */ diff --git a/hotspot/src/share/vm/jvmci/jvmci_globals.cpp b/hotspot/src/share/vm/jvmci/jvmci_globals.cpp index f555863ed0d..992746975f4 100644 --- a/hotspot/src/share/vm/jvmci/jvmci_globals.cpp +++ b/hotspot/src/share/vm/jvmci/jvmci_globals.cpp @@ -24,6 +24,8 @@ #include "precompiled.hpp" #include "jvmci/jvmci_globals.hpp" +#include "utilities/defaultStream.hpp" +#include "runtime/globals_extension.hpp" JVMCI_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ MATERIALIZE_PD_DEVELOPER_FLAG, \ @@ -34,3 +36,185 @@ JVMCI_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ MATERIALIZE_NOTPRODUCT_FLAG, IGNORE_RANGE, \ IGNORE_CONSTRAINT) + +#define JVMCI_IGNORE_FLAG_FOUR_PARAM(type, name, value, doc) +#define JVMCI_IGNORE_FLAG_THREE_PARAM(type, name, doc) + +// Return true if jvmci flags are consistent. +bool JVMCIGlobals::check_jvmci_flags_are_consistent() { + if (EnableJVMCI) { + return true; + } + + // "FLAG_IS_DEFAULT" fail count. + int fail_count = 0; + // Number of "FLAG_IS_DEFAULT" fails that should be skipped before code + // detect real consistency failure. + int skip_fail_count; + + // EnableJVMCI flag is false here. + // If any other flag is changed, consistency check should fail. + // JVMCI_FLAGS macros added below can handle all JVMCI flags automatically. + // But it contains check for EnableJVMCI flag too, which is required to be + // skipped. This can't be handled easily! + // So the code looks for at-least two flag changes to detect consistency + // failure when EnableJVMCI flag is changed. + // Otherwise one flag change is sufficient to detect consistency failure. + // Set skip_fail_count to 0 if EnableJVMCI flag is default. + // Set skip_fail_count to 1 if EnableJVMCI flag is changed. + // This value will be used to skip fails in macro expanded code later. + if (!FLAG_IS_DEFAULT(EnableJVMCI)) { + skip_fail_count = 1; + } else { + skip_fail_count = 0; + } + +#define EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(FLAG) \ + if (!FLAG_IS_DEFAULT(FLAG)) { \ + fail_count++; \ + if (fail_count > skip_fail_count) { \ + return false; \ + } \ + } + +#define JVMCI_DIAGNOSTIC_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#define JVMCI_EXPERIMENTAL_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) + + // Check consistency of diagnostic flags if UnlockDiagnosticVMOptions is true + // or not default. UnlockDiagnosticVMOptions is default true in debug builds. + if (UnlockDiagnosticVMOptions || !FLAG_IS_DEFAULT(UnlockDiagnosticVMOptions)) { + JVMCI_FLAGS(JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_DIAGNOSTIC_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + } + + // Check consistency of experimental flags if UnlockExperimentalVMOptions is + // true or not default. + if (UnlockExperimentalVMOptions || !FLAG_IS_DEFAULT(UnlockExperimentalVMOptions)) { + JVMCI_FLAGS(JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_EXPERIMENTAL_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + } + +#ifndef PRODUCT +#define JVMCI_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#define JVMCI_PD_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#define JVMCI_NOTPRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#else +#define JVMCI_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) +#define JVMCI_PD_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, doc) +#define JVMCI_NOTPRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) +#endif + +#define JVMCI_PD_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#define JVMCI_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) + + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_PD_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_PD_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_NOTPRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + +#undef EMIT_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_PD_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_NOTPRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_DIAGNOSTIC_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_PD_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_EXPERIMENTAL_FLAG_VALUE_CHANGED_CHECK_CODE + + return true; +} + +// Print jvmci arguments inconsistency error message. +void JVMCIGlobals::print_jvmci_args_inconsistency_error_message() { + const char* error_msg = "Improperly specified VM option '%s'\n"; + jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); + +#define EMIT_CHECK_PRINT_ERR_MSG_CODE(FLAG) \ + if (!FLAG_IS_DEFAULT(FLAG)) { \ + if (strcmp(#FLAG, "EnableJVMCI")) { \ + jio_fprintf(defaultStream::error_stream(), error_msg, #FLAG); \ + } \ + } + +#define JVMCI_DIAGNOSTIC_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#define JVMCI_EXPERIMENTAL_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) + + if (UnlockDiagnosticVMOptions || !FLAG_IS_DEFAULT(UnlockDiagnosticVMOptions)) { + JVMCI_FLAGS(JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_DIAGNOSTIC_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + } + + if (UnlockExperimentalVMOptions || !FLAG_IS_DEFAULT(UnlockExperimentalVMOptions)) { + JVMCI_FLAGS(JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_EXPERIMENTAL_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + } + +#ifndef PRODUCT +#define JVMCI_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#define JVMCI_PD_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#define JVMCI_NOTPRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#else +#define JVMCI_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) +#define JVMCI_PD_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, doc) +#define JVMCI_NOTPRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) +#endif + +#define JVMCI_PD_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#define JVMCI_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) + + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_PD_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_PD_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_NOTPRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + +#undef EMIT_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_PD_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_NOTPRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_PD_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_DIAGNOSTIC_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_EXPERIMENTAL_FLAG_CHECK_PRINT_ERR_MSG_CODE + +} + +#undef JVMCI_IGNORE_FLAG_FOUR_PARAM +#undef JVMCI_IGNORE_FLAG_THREE_PARAM diff --git a/hotspot/src/share/vm/jvmci/jvmci_globals.hpp b/hotspot/src/share/vm/jvmci/jvmci_globals.hpp index ac1bfd119e6..03285e3bdfc 100644 --- a/hotspot/src/share/vm/jvmci/jvmci_globals.hpp +++ b/hotspot/src/share/vm/jvmci/jvmci_globals.hpp @@ -39,29 +39,23 @@ \ experimental(bool, UseJVMCICompiler, false, \ "Use JVMCI as the default compiler") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(bool, BootstrapJVMCI, false, \ "Bootstrap JVMCI before running Java main method") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(bool, PrintBootstrap, true, \ "Print JVMCI bootstrap progress and summary") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(intx, JVMCIThreads, 1, \ "Force number of JVMCI compiler threads to use") \ range(1, max_jint) \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(intx, JVMCIHostThreads, 1, \ "Force number of compiler threads for JVMCI host compiler") \ range(1, max_jint) \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(bool, CodeInstallSafepointChecks, true, \ "Perform explicit safepoint checks while installing code") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ NOT_COMPILER2(product(intx, MaxVectorSize, 64, \ "Max vector size in bytes, " \ @@ -74,28 +68,22 @@ "Trace level for JVMCI: " \ "1 means emit a message for each CompilerToVM call," \ "levels greater than 1 provide progressively greater detail") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(intx, JVMCICounterSize, 0, \ "Reserved size for benchmark counters") \ range(0, max_jint) \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(bool, JVMCICountersExcludeCompiler, true, \ "Exclude JVMCI compiler threads from benchmark counters") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ develop(bool, JVMCIUseFastLocking, true, \ "Use fast inlined locking code") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(intx, JVMCINMethodSizeLimit, (80*K)*wordSize, \ "Maximum size of a compiled method.") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ develop(bool, TraceUncollectedSpeculations, false, \ - "Print message when a failed speculation was not collected") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + "Print message when a failed speculation was not collected") // Read default values for JVMCI globals @@ -110,4 +98,11 @@ JVMCI_FLAGS(DECLARE_DEVELOPER_FLAG, \ IGNORE_RANGE, \ IGNORE_CONSTRAINT) +class JVMCIGlobals { + public: + // Return true if jvmci flags are consistent. + static bool check_jvmci_flags_are_consistent(); + // Print jvmci arguments inconsistency error message. + static void print_jvmci_args_inconsistency_error_message(); +}; #endif // SHARE_VM_JVMCI_JVMCIGLOBALS_HPP diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index fc891394d4a..3b335e39a36 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -2314,6 +2314,17 @@ bool Arguments::sun_java_launcher_is_altjvm() { //=========================================================================================================== // Parsing of main arguments +#if INCLUDE_JVMCI +// Check consistency of jvmci vm argument settings. +bool Arguments::check_jvmci_args_consistency() { + if (!EnableJVMCI && !JVMCIGlobals::check_jvmci_flags_are_consistent()) { + JVMCIGlobals::print_jvmci_args_inconsistency_error_message(); + return false; + } + return true; +} +#endif //INCLUDE_JVMCI + // Check consistency of GC selection bool Arguments::check_gc_consistency() { // Ensure that the user has not selected conflicting sets @@ -2410,6 +2421,9 @@ bool Arguments::check_vm_args_consistency() { #endif } #if INCLUDE_JVMCI + + status = status && check_jvmci_args_consistency(); + if (EnableJVMCI) { if (!ScavengeRootsInCode) { warning("forcing ScavengeRootsInCode non-zero because JVMCI is enabled"); diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index e7ce4f30cab..8fb95492c61 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -505,7 +505,10 @@ class Arguments : AllStatic { static void set_gc_specific_flags(); static inline bool gc_selected(); // whether a gc has been selected static void select_gc_ergonomically(); - +#if INCLUDE_JVMCI + // Check consistency of jvmci vm argument settings. + static bool check_jvmci_args_consistency(); +#endif // Check for consistency in the selection of the garbage collector. static bool check_gc_consistency(); // Check user-selected gc // Check consistency or otherwise of VM argument settings diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp index 60cf0daecc1..2f96660c260 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp @@ -33,9 +33,6 @@ #include "runtime/commandLineFlagConstraintsRuntime.hpp" #include "runtime/os.hpp" #include "utilities/macros.hpp" -#if INCLUDE_JVMCI -#include "jvmci/commandLineFlagConstraintsJVMCI.hpp" -#endif class CommandLineFlagConstraint_bool : public CommandLineFlagConstraint { CommandLineFlagConstraintFunc_bool _constraint; @@ -254,17 +251,6 @@ void CommandLineFlagConstraintList::init(void) { IGNORE_RANGE, EMIT_CONSTRAINT_CHECK)); -#if INCLUDE_JVMCI - emit_constraint_no(NULL JVMCI_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, - EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, - EMIT_CONSTRAINT_PRODUCT_FLAG, - EMIT_CONSTRAINT_PD_PRODUCT_FLAG, - EMIT_CONSTRAINT_DIAGNOSTIC_FLAG, - EMIT_CONSTRAINT_EXPERIMENTAL_FLAG, - EMIT_CONSTRAINT_NOTPRODUCT_FLAG, - IGNORE_RANGE, - EMIT_CONSTRAINT_CHECK)); -#endif // INCLUDE_JVMCI #ifdef COMPILER1 emit_constraint_no(NULL C1_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, From 0e31a18fd122d2fd9f97d8c34aef43f66c3cabee Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 23 Feb 2016 17:55:20 +0300 Subject: [PATCH 016/129] 8150180: String.value contents should be trusted Reviewed-by: vlivanov, redestad, jrose, twisti --- hotspot/src/share/vm/opto/library_call.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 753612c206f..f604d59a1ac 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -1584,6 +1584,13 @@ bool LibraryCallKit::inline_string_char_access(bool is_store) { assert (type2aelembytes(T_CHAR) == type2aelembytes(T_BYTE)*2, "sanity: byte[] and char[] scales agree"); + // Bail when getChar over constants is requested: constant folding would + // reject folding mismatched char access over byte[]. A normal inlining for getChar + // Java method would constant fold nicely instead. + if (!is_store && value->is_Con() && index->is_Con()) { + return false; + } + Node* adr = array_element_address(value, index, T_CHAR); if (is_store) { (void) store_to_memory(control(), adr, ch, T_CHAR, TypeAryPtr::BYTES, MemNode::unordered, From 744d73a67ff99438835465042ab18985f728335c Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 23 Feb 2016 17:18:31 +0100 Subject: [PATCH 017/129] 8148353: [linux-sparc] Crash in libawt.so on Linux SPARC Gcc expects clean 32 bit int in 64 bit register on function entry Reviewed-by: kvn, dlong --- hotspot/make/test/JtregNative.gmk | 1 + .../src/cpu/sparc/vm/sharedRuntime_sparc.cpp | 7 ++- .../test/compiler/native/TestDirtyInt.java | 46 +++++++++++++++++++ .../test/compiler/native/libTestDirtyInt.c | 33 +++++++++++++ 4 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 hotspot/test/compiler/native/TestDirtyInt.java create mode 100644 hotspot/test/compiler/native/libTestDirtyInt.c diff --git a/hotspot/make/test/JtregNative.gmk b/hotspot/make/test/JtregNative.gmk index 109c04d37fb..bced741d6a7 100644 --- a/hotspot/make/test/JtregNative.gmk +++ b/hotspot/make/test/JtregNative.gmk @@ -48,6 +48,7 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \ $(HOTSPOT_TOPDIR)/test/runtime/SameObject \ $(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \ $(HOTSPOT_TOPDIR)/test/compiler/calls \ + $(HOTSPOT_TOPDIR)/test/compiler/native \ # # Add conditional directories here when needed. diff --git a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index da9869fdb4d..65cbf6e8315 100644 --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp @@ -1349,9 +1349,12 @@ static void move32_64(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { } } else if (dst.first()->is_stack()) { // reg to stack - __ st_ptr(src.first()->as_Register(), SP, reg2offset(dst.first()) + STACK_BIAS); + // Some compilers (gcc) expect a clean 32 bit value on function entry + __ signx(src.first()->as_Register(), L5); + __ st_ptr(L5, SP, reg2offset(dst.first()) + STACK_BIAS); } else { - __ mov(src.first()->as_Register(), dst.first()->as_Register()); + // Some compilers (gcc) expect a clean 32 bit value on function entry + __ signx(src.first()->as_Register(), dst.first()->as_Register()); } } diff --git a/hotspot/test/compiler/native/TestDirtyInt.java b/hotspot/test/compiler/native/TestDirtyInt.java new file mode 100644 index 00000000000..607fd2d491c --- /dev/null +++ b/hotspot/test/compiler/native/TestDirtyInt.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @run main/native TestDirtyInt + */ +public class TestDirtyInt { + static { + System.loadLibrary("TestDirtyInt"); + } + + native static int test(int v); + + static int compiled(int v) { + return test(v<<2); + } + + static public void main(String[] args) { + for (int i = 0; i < 20000; i++) { + int res = compiled(Integer.MAX_VALUE); + if (res != 0x42) { + throw new RuntimeException("Test failed"); + } + } + } +} diff --git a/hotspot/test/compiler/native/libTestDirtyInt.c b/hotspot/test/compiler/native/libTestDirtyInt.c new file mode 100644 index 00000000000..b688a369398 --- /dev/null +++ b/hotspot/test/compiler/native/libTestDirtyInt.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jni.h" +#include + +static int array = 0x42; + +JNIEXPORT jint JNICALL Java_TestDirtyInt_test(JNIEnv* env, jclass jclazz, jint v) +{ + int* ptr = &array + v + 4; + return *ptr; +} From 449c65bf50107d92f18c7ebbefd2aec4979febc3 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 23 Feb 2016 17:59:27 +0100 Subject: [PATCH 018/129] 8007986: GrowableArray should implement binary search Binary search method for GrowableArray Reviewed-by: vlivanov, jrose --- .../src/share/vm/ci/ciConstantPoolCache.cpp | 49 ++++-------- .../src/share/vm/ci/ciConstantPoolCache.hpp | 2 +- hotspot/src/share/vm/ci/ciObjectFactory.cpp | 73 ++++-------------- hotspot/src/share/vm/ci/ciObjectFactory.hpp | 4 +- hotspot/src/share/vm/opto/compile.cpp | 75 ++++++++----------- hotspot/src/share/vm/opto/compile.hpp | 2 +- .../src/share/vm/utilities/growableArray.hpp | 2 +- 7 files changed, 62 insertions(+), 145 deletions(-) diff --git a/hotspot/src/share/vm/ci/ciConstantPoolCache.cpp b/hotspot/src/share/vm/ci/ciConstantPoolCache.cpp index 6ceacdc5a5a..b67450bf026 100644 --- a/hotspot/src/share/vm/ci/ciConstantPoolCache.cpp +++ b/hotspot/src/share/vm/ci/ciConstantPoolCache.cpp @@ -41,58 +41,37 @@ ciConstantPoolCache::ciConstantPoolCache(Arena* arena, _keys = new (arena) GrowableArray(arena, expected_size, 0, 0); } +int ciConstantPoolCache::key_compare(const int& key, const int& elt) { + if (key < elt) return -1; + else if (key > elt) return 1; + else return 0; +} + // ------------------------------------------------------------------ // ciConstantPoolCache::get // // Get the entry at some index void* ciConstantPoolCache::get(int index) { ASSERT_IN_VM; - int pos = find(index); - if (pos >= _keys->length() || - _keys->at(pos) != index) { + bool found = false; + int pos = _keys->find_sorted(index, found); + if (!found) { // This element is not present in the cache. return NULL; } return _elements->at(pos); } -// ------------------------------------------------------------------ -// ciConstantPoolCache::find -// -// Use binary search to find the position of this index in the cache. -// If there is no entry in the cache corresponding to this oop, return -// the position at which the index would be inserted. -int ciConstantPoolCache::find(int key) { - int min = 0; - int max = _keys->length()-1; - - while (max >= min) { - int mid = (max + min) / 2; - int value = _keys->at(mid); - if (value < key) { - min = mid + 1; - } else if (value > key) { - max = mid - 1; - } else { - return mid; - } - } - return min; -} - // ------------------------------------------------------------------ // ciConstantPoolCache::insert // // Insert a ciObject into the table at some index. void ciConstantPoolCache::insert(int index, void* elem) { - int i; - int pos = find(index); - for (i = _keys->length()-1; i >= pos; i--) { - _keys->at_put_grow(i+1, _keys->at(i)); - _elements->at_put_grow(i+1, _elements->at(i)); - } - _keys->at_put_grow(pos, index); - _elements->at_put_grow(pos, elem); + bool found = false; + int pos = _keys->find_sorted(index, found); + assert(!found, "duplicate"); + _keys->insert_before(pos, index); + _elements->insert_before(pos, elem); } // ------------------------------------------------------------------ diff --git a/hotspot/src/share/vm/ci/ciConstantPoolCache.hpp b/hotspot/src/share/vm/ci/ciConstantPoolCache.hpp index 17cf77681e0..8c726a0154f 100644 --- a/hotspot/src/share/vm/ci/ciConstantPoolCache.hpp +++ b/hotspot/src/share/vm/ci/ciConstantPoolCache.hpp @@ -38,7 +38,7 @@ private: GrowableArray* _keys; GrowableArray* _elements; - int find(int index); + static int key_compare(const int& key, const int& elt); public: ciConstantPoolCache(Arena* arena, int expected_size); diff --git a/hotspot/src/share/vm/ci/ciObjectFactory.cpp b/hotspot/src/share/vm/ci/ciObjectFactory.cpp index 240ed839bf0..bcb7540a3e9 100644 --- a/hotspot/src/share/vm/ci/ciObjectFactory.cpp +++ b/hotspot/src/share/vm/ci/ciObjectFactory.cpp @@ -260,6 +260,13 @@ ciObject* ciObjectFactory::get(oop key) { return new_object; } +int ciObjectFactory::metadata_compare(Metadata* const& key, ciMetadata* const& elt) { + Metadata* value = elt->constant_encoding(); + if (key < value) return -1; + else if (key > value) return 1; + else return 0; +} + // ------------------------------------------------------------------ // ciObjectFactory::get_metadata // @@ -280,7 +287,8 @@ ciMetadata* ciObjectFactory::get_metadata(Metadata* key) { } #endif // ASSERT int len = _ci_metadata->length(); - int index = find(key, _ci_metadata); + bool found = false; + int index = _ci_metadata->find_sorted(key, found); #ifdef ASSERT if (CIObjectFactoryVerify) { for (int i=0; i<_ci_metadata->length(); i++) { @@ -290,7 +298,8 @@ ciMetadata* ciObjectFactory::get_metadata(Metadata* key) { } } #endif - if (!is_found_at(index, key, _ci_metadata)) { + + if (!found) { // The ciMetadata does not yet exist. Create it and insert it // into the cache. ciMetadata* new_object = create_new_metadata(key); @@ -300,10 +309,10 @@ ciMetadata* ciObjectFactory::get_metadata(Metadata* key) { if (len != _ci_metadata->length()) { // creating the new object has recursively entered new objects // into the table. We need to recompute our index. - index = find(key, _ci_metadata); + index = _ci_metadata->find_sorted(key, found); } - assert(!is_found_at(index, key, _ci_metadata), "no double insert"); - insert(index, new_object, _ci_metadata); + assert(!found, "no double insert"); + _ci_metadata->insert_before(index, new_object); return new_object; } return _ci_metadata->at(index)->as_metadata(); @@ -655,60 +664,6 @@ void ciObjectFactory::init_ident_of(ciBaseObject* obj) { obj->set_ident(_next_ident++); } -// ------------------------------------------------------------------ -// ciObjectFactory::find -// -// Use binary search to find the position of this oop in the cache. -// If there is no entry in the cache corresponding to this oop, return -// the position at which the oop should be inserted. -int ciObjectFactory::find(Metadata* key, GrowableArray* objects) { - int min = 0; - int max = objects->length()-1; - - // print_contents(); - - while (max >= min) { - int mid = (max + min) / 2; - Metadata* value = objects->at(mid)->constant_encoding(); - if (value < key) { - min = mid + 1; - } else if (value > key) { - max = mid - 1; - } else { - return mid; - } - } - return min; -} - -// ------------------------------------------------------------------ -// ciObjectFactory::is_found_at -// -// Verify that the binary seach found the given key. -bool ciObjectFactory::is_found_at(int index, Metadata* key, GrowableArray* objects) { - return (index < objects->length() && - objects->at(index)->constant_encoding() == key); -} - - -// ------------------------------------------------------------------ -// ciObjectFactory::insert -// -// Insert a ciObject into the table at some index. -void ciObjectFactory::insert(int index, ciMetadata* obj, GrowableArray* objects) { - int len = objects->length(); - if (len == index) { - objects->append(obj); - } else { - objects->append(objects->at(len-1)); - int pos; - for (pos = len-2; pos >= index; pos--) { - objects->at_put(pos+1,objects->at(pos)); - } - objects->at_put(index, obj); - } -} - static ciObjectFactory::NonPermObject* emptyBucket = NULL; // ------------------------------------------------------------------ diff --git a/hotspot/src/share/vm/ci/ciObjectFactory.hpp b/hotspot/src/share/vm/ci/ciObjectFactory.hpp index 4cdcc69beac..4f0cbd7ac73 100644 --- a/hotspot/src/share/vm/ci/ciObjectFactory.hpp +++ b/hotspot/src/share/vm/ci/ciObjectFactory.hpp @@ -68,9 +68,7 @@ private: NonPermObject* _non_perm_bucket[NON_PERM_BUCKETS]; int _non_perm_count; - int find(Metadata* key, GrowableArray* objects); - bool is_found_at(int index, Metadata* key, GrowableArray* objects); - void insert(int index, ciMetadata* obj, GrowableArray* objects); + static int metadata_compare(Metadata* const& key, ciMetadata* const& elt); ciObject* create_new_object(oop o); ciMetadata* create_new_metadata(Metadata* o); diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index bf5597753b6..6e3e46d790f 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -88,7 +88,27 @@ MachConstantBaseNode* Compile::mach_constant_base_node() { // Return the index at which m must be inserted (or already exists). // The sort order is by the address of the ciMethod, with is_virtual as minor key. -int Compile::intrinsic_insertion_index(ciMethod* m, bool is_virtual) { +class IntrinsicDescPair { + private: + ciMethod* _m; + bool _is_virtual; + public: + IntrinsicDescPair(ciMethod* m, bool is_virtual) : _m(m), _is_virtual(is_virtual) {} + static int compare(IntrinsicDescPair* const& key, CallGenerator* const& elt) { + ciMethod* m= elt->method(); + ciMethod* key_m = key->_m; + if (key_m < m) return -1; + else if (key_m > m) return 1; + else { + bool is_virtual = elt->is_virtual(); + bool key_virtual = key->_is_virtual; + if (key_virtual < is_virtual) return -1; + else if (key_virtual > is_virtual) return 1; + else return 0; + } + } +}; +int Compile::intrinsic_insertion_index(ciMethod* m, bool is_virtual, bool& found) { #ifdef ASSERT for (int i = 1; i < _intrinsics->length(); i++) { CallGenerator* cg1 = _intrinsics->at(i-1); @@ -99,63 +119,28 @@ int Compile::intrinsic_insertion_index(ciMethod* m, bool is_virtual) { "compiler intrinsics list must stay sorted"); } #endif - // Binary search sorted list, in decreasing intervals [lo, hi]. - int lo = 0, hi = _intrinsics->length()-1; - while (lo <= hi) { - int mid = (uint)(hi + lo) / 2; - ciMethod* mid_m = _intrinsics->at(mid)->method(); - if (m < mid_m) { - hi = mid-1; - } else if (m > mid_m) { - lo = mid+1; - } else { - // look at minor sort key - bool mid_virt = _intrinsics->at(mid)->is_virtual(); - if (is_virtual < mid_virt) { - hi = mid-1; - } else if (is_virtual > mid_virt) { - lo = mid+1; - } else { - return mid; // exact match - } - } - } - return lo; // inexact match + IntrinsicDescPair pair(m, is_virtual); + return _intrinsics->find_sorted(&pair, found); } void Compile::register_intrinsic(CallGenerator* cg) { if (_intrinsics == NULL) { _intrinsics = new (comp_arena())GrowableArray(comp_arena(), 60, 0, NULL); } - // This code is stolen from ciObjectFactory::insert. - // Really, GrowableArray should have methods for - // insert_at, remove_at, and binary_search. int len = _intrinsics->length(); - int index = intrinsic_insertion_index(cg->method(), cg->is_virtual()); - if (index == len) { - _intrinsics->append(cg); - } else { -#ifdef ASSERT - CallGenerator* oldcg = _intrinsics->at(index); - assert(oldcg->method() != cg->method() || oldcg->is_virtual() != cg->is_virtual(), "don't register twice"); -#endif - _intrinsics->append(_intrinsics->at(len-1)); - int pos; - for (pos = len-2; pos >= index; pos--) { - _intrinsics->at_put(pos+1,_intrinsics->at(pos)); - } - _intrinsics->at_put(index, cg); - } + bool found = false; + int index = intrinsic_insertion_index(cg->method(), cg->is_virtual(), found); + assert(!found, "registering twice"); + _intrinsics->insert_before(index, cg); assert(find_intrinsic(cg->method(), cg->is_virtual()) == cg, "registration worked"); } CallGenerator* Compile::find_intrinsic(ciMethod* m, bool is_virtual) { assert(m->is_loaded(), "don't try this on unloaded methods"); if (_intrinsics != NULL) { - int index = intrinsic_insertion_index(m, is_virtual); - if (index < _intrinsics->length() - && _intrinsics->at(index)->method() == m - && _intrinsics->at(index)->is_virtual() == is_virtual) { + bool found = false; + int index = intrinsic_insertion_index(m, is_virtual, found); + if (found) { return _intrinsics->at(index); } } diff --git a/hotspot/src/share/vm/opto/compile.hpp b/hotspot/src/share/vm/opto/compile.hpp index 871abe245a7..40724fbd6b7 100644 --- a/hotspot/src/share/vm/opto/compile.hpp +++ b/hotspot/src/share/vm/opto/compile.hpp @@ -1250,7 +1250,7 @@ class Compile : public Phase { // Intrinsic setup. void register_library_intrinsics(); // initializer CallGenerator* make_vm_intrinsic(ciMethod* m, bool is_virtual); // constructor - int intrinsic_insertion_index(ciMethod* m, bool is_virtual); // helper + int intrinsic_insertion_index(ciMethod* m, bool is_virtual, bool& found); // helper CallGenerator* find_intrinsic(ciMethod* m, bool is_virtual); // query fn void register_intrinsic(CallGenerator* cg); // update fn diff --git a/hotspot/src/share/vm/utilities/growableArray.hpp b/hotspot/src/share/vm/utilities/growableArray.hpp index 933cf339661..a2780fecca5 100644 --- a/hotspot/src/share/vm/utilities/growableArray.hpp +++ b/hotspot/src/share/vm/utilities/growableArray.hpp @@ -396,7 +396,7 @@ template class GrowableArray : public GenericGrowableArray { int max = length() - 1; while (max >= min) { - int mid = (max + min) / 2; + int mid = (int)(((uint)max + min) / 2); E value = at(mid); int diff = compare(key, value); if (diff > 0) { From 0c43809cfe25a4d07d9765a9f2ccb4b00c7d089f Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 23 Feb 2016 22:09:41 +0300 Subject: [PATCH 019/129] 8148146: Integrate new internal Unsafe entry points, and basic intrinsic support for VarHandles Reviewed-by: psandoz, kvn, jrose, adinn, simonis, coleenp --- hotspot/src/cpu/x86/vm/x86_32.ad | 28 + hotspot/src/cpu/x86/vm/x86_64.ad | 81 ++ hotspot/src/share/vm/adlc/formssel.cpp | 2 + hotspot/src/share/vm/classfile/vmSymbols.cpp | 56 +- hotspot/src/share/vm/classfile/vmSymbols.hpp | 138 +++- hotspot/src/share/vm/opto/c2compiler.cpp | 95 ++- hotspot/src/share/vm/opto/classes.hpp | 8 + hotspot/src/share/vm/opto/compile.cpp | 8 + hotspot/src/share/vm/opto/escape.cpp | 8 + hotspot/src/share/vm/opto/library_call.cpp | 765 ++++++++++++------ hotspot/src/share/vm/opto/loopTransform.cpp | 8 + hotspot/src/share/vm/opto/matcher.cpp | 16 + hotspot/src/share/vm/opto/memnode.hpp | 107 ++- hotspot/src/share/vm/opto/node.hpp | 5 + hotspot/src/share/vm/prims/unsafe.cpp | 42 + hotspot/src/share/vm/runtime/vmStructs.cpp | 18 +- ...dkInternalMiscUnsafeAccessTestBoolean.java | 14 + .../JdkInternalMiscUnsafeAccessTestByte.java | 14 + .../JdkInternalMiscUnsafeAccessTestChar.java | 14 + ...JdkInternalMiscUnsafeAccessTestDouble.java | 14 + .../JdkInternalMiscUnsafeAccessTestFloat.java | 14 + .../JdkInternalMiscUnsafeAccessTestInt.java | 78 ++ .../JdkInternalMiscUnsafeAccessTestLong.java | 78 ++ ...JdkInternalMiscUnsafeAccessTestObject.java | 78 ++ .../JdkInternalMiscUnsafeAccessTestShort.java | 14 + .../unsafe/X-UnsafeAccessTest.java.template | 85 +- .../compiler/unsafe/generate-unsafe-tests.sh | 97 +++ 27 files changed, 1590 insertions(+), 295 deletions(-) create mode 100644 hotspot/test/compiler/unsafe/generate-unsafe-tests.sh diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index f684cd5b5cd..b09ca8e36ab 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -7236,6 +7236,7 @@ instruct storeLConditional( memory mem, eADXRegL oldval, eBCXRegL newval, eFlags instruct compareAndSwapL( rRegI res, eSIRegP mem_ptr, eADXRegL oldval, eBCXRegL newval, eFlagsReg cr ) %{ predicate(VM_Version::supports_cx8()); match(Set res (CompareAndSwapL mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapL mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "CMPXCHG8 [$mem_ptr],$newval\t# If EDX:EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" "MOV $res,0\n\t" @@ -7249,6 +7250,7 @@ instruct compareAndSwapL( rRegI res, eSIRegP mem_ptr, eADXRegL oldval, eBCXRegL instruct compareAndSwapP( rRegI res, pRegP mem_ptr, eAXRegP oldval, eCXRegP newval, eFlagsReg cr) %{ match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "CMPXCHG [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" "MOV $res,0\n\t" @@ -7261,6 +7263,7 @@ instruct compareAndSwapP( rRegI res, pRegP mem_ptr, eAXRegP oldval, eCXRegP new instruct compareAndSwapI( rRegI res, pRegP mem_ptr, eAXRegI oldval, eCXRegI newval, eFlagsReg cr) %{ match(Set res (CompareAndSwapI mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapI mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "CMPXCHG [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" "MOV $res,0\n\t" @@ -7271,6 +7274,31 @@ instruct compareAndSwapI( rRegI res, pRegP mem_ptr, eAXRegI oldval, eCXRegI newv ins_pipe( pipe_cmpxchg ); %} +instruct compareAndExchangeL( eSIRegP mem_ptr, eADXRegL oldval, eBCXRegL newval, eFlagsReg cr ) %{ + predicate(VM_Version::supports_cx8()); + match(Set oldval (CompareAndExchangeL mem_ptr (Binary oldval newval))); + effect(KILL cr); + format %{ "CMPXCHG8 [$mem_ptr],$newval\t# If EDX:EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" %} + ins_encode( enc_cmpxchg8(mem_ptr) ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeP( pRegP mem_ptr, eAXRegP oldval, eCXRegP newval, eFlagsReg cr) %{ + match(Set oldval (CompareAndExchangeP mem_ptr (Binary oldval newval))); + effect(KILL cr); + format %{ "CMPXCHG [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" %} + ins_encode( enc_cmpxchg(mem_ptr) ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeI( pRegP mem_ptr, eAXRegI oldval, eCXRegI newval, eFlagsReg cr) %{ + match(Set oldval (CompareAndExchangeI mem_ptr (Binary oldval newval))); + effect(KILL cr); + format %{ "CMPXCHG [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" %} + ins_encode( enc_cmpxchg(mem_ptr) ); + ins_pipe( pipe_cmpxchg ); +%} + instruct xaddI_no_res( memory mem, Universe dummy, immI add, eFlagsReg cr) %{ predicate(n->as_LoadStore()->result_not_used()); match(Set dummy (GetAndAddI mem add)); diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index 455354834ea..6f32ace2f18 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -7281,6 +7281,7 @@ instruct compareAndSwapP(rRegI res, %{ predicate(VM_Version::supports_cx8()); match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "cmpxchgq $mem_ptr,$newval\t# " @@ -7305,6 +7306,7 @@ instruct compareAndSwapL(rRegI res, %{ predicate(VM_Version::supports_cx8()); match(Set res (CompareAndSwapL mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapL mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "cmpxchgq $mem_ptr,$newval\t# " @@ -7328,6 +7330,7 @@ instruct compareAndSwapI(rRegI res, rFlagsReg cr) %{ match(Set res (CompareAndSwapI mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapI mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "cmpxchgl $mem_ptr,$newval\t# " @@ -7351,6 +7354,7 @@ instruct compareAndSwapN(rRegI res, rax_RegN oldval, rRegN newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "cmpxchgl $mem_ptr,$newval\t# " @@ -7368,6 +7372,83 @@ instruct compareAndSwapN(rRegI res, ins_pipe( pipe_cmpxchg ); %} +instruct compareAndExchangeI( + memory mem_ptr, + rax_RegI oldval, rRegI newval, + rFlagsReg cr) +%{ + match(Set oldval (CompareAndExchangeI mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgl $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + opcode(0x0F, 0xB1); + ins_encode(lock_prefix, + REX_reg_mem(newval, mem_ptr), + OpcP, OpcS, + reg_mem(newval, mem_ptr) // lock cmpxchg + ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeL( + memory mem_ptr, + rax_RegL oldval, rRegL newval, + rFlagsReg cr) +%{ + predicate(VM_Version::supports_cx8()); + match(Set oldval (CompareAndExchangeL mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgq $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + opcode(0x0F, 0xB1); + ins_encode(lock_prefix, + REX_reg_mem_wide(newval, mem_ptr), + OpcP, OpcS, + reg_mem(newval, mem_ptr) // lock cmpxchg + ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeN( + memory mem_ptr, + rax_RegN oldval, rRegN newval, + rFlagsReg cr) %{ + match(Set oldval (CompareAndExchangeN mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgl $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + opcode(0x0F, 0xB1); + ins_encode(lock_prefix, + REX_reg_mem(newval, mem_ptr), + OpcP, OpcS, + reg_mem(newval, mem_ptr) // lock cmpxchg + ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeP( + memory mem_ptr, + rax_RegP oldval, rRegP newval, + rFlagsReg cr) +%{ + predicate(VM_Version::supports_cx8()); + match(Set oldval (CompareAndExchangeP mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgq $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + opcode(0x0F, 0xB1); + ins_encode(lock_prefix, + REX_reg_mem_wide(newval, mem_ptr), + OpcP, OpcS, + reg_mem(newval, mem_ptr) // lock cmpxchg + ); + ins_pipe( pipe_cmpxchg ); +%} + instruct xaddI_no_res( memory mem, Universe dummy, immI add, rFlagsReg cr) %{ predicate(n->as_LoadStore()->result_not_used()); match(Set dummy (GetAndAddI mem add)); diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp index d408c904c6c..a3faa48e426 100644 --- a/hotspot/src/share/vm/adlc/formssel.cpp +++ b/hotspot/src/share/vm/adlc/formssel.cpp @@ -3491,6 +3491,8 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const { "LoadPLocked", "StorePConditional", "StoreIConditional", "StoreLConditional", "CompareAndSwapI", "CompareAndSwapL", "CompareAndSwapP", "CompareAndSwapN", + "WeakCompareAndSwapI", "WeakCompareAndSwapL", "WeakCompareAndSwapP", "WeakCompareAndSwapN", + "CompareAndExchangeI", "CompareAndExchangeL", "CompareAndExchangeP", "CompareAndExchangeN", "StoreCM", "ClearArray", "GetAndAddI", "GetAndSetI", "GetAndSetP", diff --git a/hotspot/src/share/vm/classfile/vmSymbols.cpp b/hotspot/src/share/vm/classfile/vmSymbols.cpp index 81dda6e4fd0..1a5fe2a05fd 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.cpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp @@ -544,6 +544,42 @@ bool vmIntrinsics::is_disabled_by_flags(const methodHandle& method) { case vmIntrinsics::_putLongVolatile: case vmIntrinsics::_putFloatVolatile: case vmIntrinsics::_putDoubleVolatile: + case vmIntrinsics::_getObjectAcquire: + case vmIntrinsics::_getBooleanAcquire: + case vmIntrinsics::_getByteAcquire: + case vmIntrinsics::_getShortAcquire: + case vmIntrinsics::_getCharAcquire: + case vmIntrinsics::_getIntAcquire: + case vmIntrinsics::_getLongAcquire: + case vmIntrinsics::_getFloatAcquire: + case vmIntrinsics::_getDoubleAcquire: + case vmIntrinsics::_putObjectRelease: + case vmIntrinsics::_putBooleanRelease: + case vmIntrinsics::_putByteRelease: + case vmIntrinsics::_putShortRelease: + case vmIntrinsics::_putCharRelease: + case vmIntrinsics::_putIntRelease: + case vmIntrinsics::_putLongRelease: + case vmIntrinsics::_putFloatRelease: + case vmIntrinsics::_putDoubleRelease: + case vmIntrinsics::_getObjectOpaque: + case vmIntrinsics::_getBooleanOpaque: + case vmIntrinsics::_getByteOpaque: + case vmIntrinsics::_getShortOpaque: + case vmIntrinsics::_getCharOpaque: + case vmIntrinsics::_getIntOpaque: + case vmIntrinsics::_getLongOpaque: + case vmIntrinsics::_getFloatOpaque: + case vmIntrinsics::_getDoubleOpaque: + case vmIntrinsics::_putObjectOpaque: + case vmIntrinsics::_putBooleanOpaque: + case vmIntrinsics::_putByteOpaque: + case vmIntrinsics::_putShortOpaque: + case vmIntrinsics::_putCharOpaque: + case vmIntrinsics::_putIntOpaque: + case vmIntrinsics::_putLongOpaque: + case vmIntrinsics::_putFloatOpaque: + case vmIntrinsics::_putDoubleOpaque: case vmIntrinsics::_getByte_raw: case vmIntrinsics::_getShort_raw: case vmIntrinsics::_getChar_raw: @@ -569,9 +605,27 @@ bool vmIntrinsics::is_disabled_by_flags(const methodHandle& method) { case vmIntrinsics::_loadFence: case vmIntrinsics::_storeFence: case vmIntrinsics::_fullFence: - case vmIntrinsics::_compareAndSwapObject: case vmIntrinsics::_compareAndSwapLong: + case vmIntrinsics::_weakCompareAndSwapLong: + case vmIntrinsics::_weakCompareAndSwapLongAcquire: + case vmIntrinsics::_weakCompareAndSwapLongRelease: case vmIntrinsics::_compareAndSwapInt: + case vmIntrinsics::_weakCompareAndSwapInt: + case vmIntrinsics::_weakCompareAndSwapIntAcquire: + case vmIntrinsics::_weakCompareAndSwapIntRelease: + case vmIntrinsics::_compareAndSwapObject: + case vmIntrinsics::_weakCompareAndSwapObject: + case vmIntrinsics::_weakCompareAndSwapObjectAcquire: + case vmIntrinsics::_weakCompareAndSwapObjectRelease: + case vmIntrinsics::_compareAndExchangeIntVolatile: + case vmIntrinsics::_compareAndExchangeIntAcquire: + case vmIntrinsics::_compareAndExchangeIntRelease: + case vmIntrinsics::_compareAndExchangeLongVolatile: + case vmIntrinsics::_compareAndExchangeLongAcquire: + case vmIntrinsics::_compareAndExchangeLongRelease: + case vmIntrinsics::_compareAndExchangeObjectVolatile: + case vmIntrinsics::_compareAndExchangeObjectAcquire: + case vmIntrinsics::_compareAndExchangeObjectRelease: if (!InlineUnsafeOps) return true; break; case vmIntrinsics::_getShortUnaligned: diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 626009f4c2f..4cce6873268 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -1146,6 +1146,64 @@ do_intrinsic(_putFloatVolatile, jdk_internal_misc_Unsafe, putFloatVolatile_name, putFloat_signature, F_RN) \ do_intrinsic(_putDoubleVolatile, jdk_internal_misc_Unsafe, putDoubleVolatile_name, putDouble_signature, F_RN) \ \ + do_name(getObjectOpaque_name,"getObjectOpaque") do_name(putObjectOpaque_name,"putObjectOpaque") \ + do_name(getBooleanOpaque_name,"getBooleanOpaque") do_name(putBooleanOpaque_name,"putBooleanOpaque") \ + do_name(getByteOpaque_name,"getByteOpaque") do_name(putByteOpaque_name,"putByteOpaque") \ + do_name(getShortOpaque_name,"getShortOpaque") do_name(putShortOpaque_name,"putShortOpaque") \ + do_name(getCharOpaque_name,"getCharOpaque") do_name(putCharOpaque_name,"putCharOpaque") \ + do_name(getIntOpaque_name,"getIntOpaque") do_name(putIntOpaque_name,"putIntOpaque") \ + do_name(getLongOpaque_name,"getLongOpaque") do_name(putLongOpaque_name,"putLongOpaque") \ + do_name(getFloatOpaque_name,"getFloatOpaque") do_name(putFloatOpaque_name,"putFloatOpaque") \ + do_name(getDoubleOpaque_name,"getDoubleOpaque") do_name(putDoubleOpaque_name,"putDoubleOpaque") \ + \ + do_intrinsic(_getObjectOpaque, jdk_internal_misc_Unsafe, getObjectOpaque_name, getObject_signature, F_R) \ + do_intrinsic(_getBooleanOpaque, jdk_internal_misc_Unsafe, getBooleanOpaque_name, getBoolean_signature, F_R) \ + do_intrinsic(_getByteOpaque, jdk_internal_misc_Unsafe, getByteOpaque_name, getByte_signature, F_R) \ + do_intrinsic(_getShortOpaque, jdk_internal_misc_Unsafe, getShortOpaque_name, getShort_signature, F_R) \ + do_intrinsic(_getCharOpaque, jdk_internal_misc_Unsafe, getCharOpaque_name, getChar_signature, F_R) \ + do_intrinsic(_getIntOpaque, jdk_internal_misc_Unsafe, getIntOpaque_name, getInt_signature, F_R) \ + do_intrinsic(_getLongOpaque, jdk_internal_misc_Unsafe, getLongOpaque_name, getLong_signature, F_R) \ + do_intrinsic(_getFloatOpaque, jdk_internal_misc_Unsafe, getFloatOpaque_name, getFloat_signature, F_R) \ + do_intrinsic(_getDoubleOpaque, jdk_internal_misc_Unsafe, getDoubleOpaque_name, getDouble_signature, F_R) \ + do_intrinsic(_putObjectOpaque, jdk_internal_misc_Unsafe, putObjectOpaque_name, putObject_signature, F_R) \ + do_intrinsic(_putBooleanOpaque, jdk_internal_misc_Unsafe, putBooleanOpaque_name, putBoolean_signature, F_R) \ + do_intrinsic(_putByteOpaque, jdk_internal_misc_Unsafe, putByteOpaque_name, putByte_signature, F_R) \ + do_intrinsic(_putShortOpaque, jdk_internal_misc_Unsafe, putShortOpaque_name, putShort_signature, F_R) \ + do_intrinsic(_putCharOpaque, jdk_internal_misc_Unsafe, putCharOpaque_name, putChar_signature, F_R) \ + do_intrinsic(_putIntOpaque, jdk_internal_misc_Unsafe, putIntOpaque_name, putInt_signature, F_R) \ + do_intrinsic(_putLongOpaque, jdk_internal_misc_Unsafe, putLongOpaque_name, putLong_signature, F_R) \ + do_intrinsic(_putFloatOpaque, jdk_internal_misc_Unsafe, putFloatOpaque_name, putFloat_signature, F_R) \ + do_intrinsic(_putDoubleOpaque, jdk_internal_misc_Unsafe, putDoubleOpaque_name, putDouble_signature, F_R) \ + \ + do_name(getObjectAcquire_name, "getObjectAcquire") do_name(putObjectRelease_name, "putObjectRelease") \ + do_name(getBooleanAcquire_name, "getBooleanAcquire") do_name(putBooleanRelease_name, "putBooleanRelease") \ + do_name(getByteAcquire_name, "getByteAcquire") do_name(putByteRelease_name, "putByteRelease") \ + do_name(getShortAcquire_name, "getShortAcquire") do_name(putShortRelease_name, "putShortRelease") \ + do_name(getCharAcquire_name, "getCharAcquire") do_name(putCharRelease_name, "putCharRelease") \ + do_name(getIntAcquire_name, "getIntAcquire") do_name(putIntRelease_name, "putIntRelease") \ + do_name(getLongAcquire_name, "getLongAcquire") do_name(putLongRelease_name, "putLongRelease") \ + do_name(getFloatAcquire_name, "getFloatAcquire") do_name(putFloatRelease_name, "putFloatRelease") \ + do_name(getDoubleAcquire_name, "getDoubleAcquire") do_name(putDoubleRelease_name, "putDoubleRelease") \ + \ + do_intrinsic(_getObjectAcquire, jdk_internal_misc_Unsafe, getObjectAcquire_name, getObject_signature, F_R) \ + do_intrinsic(_getBooleanAcquire, jdk_internal_misc_Unsafe, getBooleanAcquire_name, getBoolean_signature, F_R) \ + do_intrinsic(_getByteAcquire, jdk_internal_misc_Unsafe, getByteAcquire_name, getByte_signature, F_R) \ + do_intrinsic(_getShortAcquire, jdk_internal_misc_Unsafe, getShortAcquire_name, getShort_signature, F_R) \ + do_intrinsic(_getCharAcquire, jdk_internal_misc_Unsafe, getCharAcquire_name, getChar_signature, F_R) \ + do_intrinsic(_getIntAcquire, jdk_internal_misc_Unsafe, getIntAcquire_name, getInt_signature, F_R) \ + do_intrinsic(_getLongAcquire, jdk_internal_misc_Unsafe, getLongAcquire_name, getLong_signature, F_R) \ + do_intrinsic(_getFloatAcquire, jdk_internal_misc_Unsafe, getFloatAcquire_name, getFloat_signature, F_R) \ + do_intrinsic(_getDoubleAcquire, jdk_internal_misc_Unsafe, getDoubleAcquire_name, getDouble_signature, F_R) \ + do_intrinsic(_putObjectRelease, jdk_internal_misc_Unsafe, putObjectRelease_name, putObject_signature, F_R) \ + do_intrinsic(_putBooleanRelease, jdk_internal_misc_Unsafe, putBooleanRelease_name, putBoolean_signature, F_R) \ + do_intrinsic(_putByteRelease, jdk_internal_misc_Unsafe, putByteRelease_name, putByte_signature, F_R) \ + do_intrinsic(_putShortRelease, jdk_internal_misc_Unsafe, putShortRelease_name, putShort_signature, F_R) \ + do_intrinsic(_putCharRelease, jdk_internal_misc_Unsafe, putCharRelease_name, putChar_signature, F_R) \ + do_intrinsic(_putIntRelease, jdk_internal_misc_Unsafe, putIntRelease_name, putInt_signature, F_R) \ + do_intrinsic(_putLongRelease, jdk_internal_misc_Unsafe, putLongRelease_name, putLong_signature, F_R) \ + do_intrinsic(_putFloatRelease, jdk_internal_misc_Unsafe, putFloatRelease_name, putFloat_signature, F_R) \ + do_intrinsic(_putDoubleRelease, jdk_internal_misc_Unsafe, putDoubleRelease_name, putDouble_signature, F_R) \ + \ do_name(getShortUnaligned_name,"getShortUnaligned") do_name(putShortUnaligned_name,"putShortUnaligned") \ do_name(getCharUnaligned_name,"getCharUnaligned") do_name(putCharUnaligned_name,"putCharUnaligned") \ do_name(getIntUnaligned_name,"getIntUnaligned") do_name(putIntUnaligned_name,"putIntUnaligned") \ @@ -1197,24 +1255,68 @@ do_intrinsic(_putDouble_raw, jdk_internal_misc_Unsafe, putDouble_name, putDouble_raw_signature, F_R) \ do_intrinsic(_putAddress_raw, jdk_internal_misc_Unsafe, putAddress_name, putAddress_raw_signature, F_R) \ \ - do_intrinsic(_compareAndSwapObject, jdk_internal_misc_Unsafe, compareAndSwapObject_name, compareAndSwapObject_signature, F_R) \ - do_name( compareAndSwapObject_name, "compareAndSwapObject") \ - do_signature(compareAndSwapObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z") \ - do_intrinsic(_compareAndSwapLong, jdk_internal_misc_Unsafe, compareAndSwapLong_name, compareAndSwapLong_signature, F_R) \ - do_name( compareAndSwapLong_name, "compareAndSwapLong") \ - do_signature(compareAndSwapLong_signature, "(Ljava/lang/Object;JJJ)Z") \ - do_intrinsic(_compareAndSwapInt, jdk_internal_misc_Unsafe, compareAndSwapInt_name, compareAndSwapInt_signature, F_R) \ - do_name( compareAndSwapInt_name, "compareAndSwapInt") \ - do_signature(compareAndSwapInt_signature, "(Ljava/lang/Object;JII)Z") \ - do_intrinsic(_putOrderedObject, jdk_internal_misc_Unsafe, putOrderedObject_name, putOrderedObject_signature, F_R) \ - do_name( putOrderedObject_name, "putOrderedObject") \ - do_alias( putOrderedObject_signature, /*(LObject;JLObject;)V*/ putObject_signature) \ - do_intrinsic(_putOrderedLong, jdk_internal_misc_Unsafe, putOrderedLong_name, putOrderedLong_signature, F_R) \ - do_name( putOrderedLong_name, "putOrderedLong") \ - do_alias( putOrderedLong_signature, /*(Ljava/lang/Object;JJ)V*/ putLong_signature) \ - do_intrinsic(_putOrderedInt, jdk_internal_misc_Unsafe, putOrderedInt_name, putOrderedInt_signature, F_R) \ - do_name( putOrderedInt_name, "putOrderedInt") \ - do_alias( putOrderedInt_signature, /*(Ljava/lang/Object;JI)V*/ putInt_signature) \ + do_signature(compareAndSwapObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z") \ + do_signature(compareAndExchangeObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") \ + do_signature(compareAndSwapLong_signature, "(Ljava/lang/Object;JJJ)Z") \ + do_signature(compareAndExchangeLong_signature, "(Ljava/lang/Object;JJJ)J") \ + do_signature(compareAndSwapInt_signature, "(Ljava/lang/Object;JII)Z") \ + do_signature(compareAndExchangeInt_signature, "(Ljava/lang/Object;JII)I") \ + \ + do_name(compareAndSwapObject_name, "compareAndSwapObject") \ + do_name(compareAndExchangeObjectVolatile_name, "compareAndExchangeObjectVolatile") \ + do_name(compareAndExchangeObjectAcquire_name, "compareAndExchangeObjectAcquire") \ + do_name(compareAndExchangeObjectRelease_name, "compareAndExchangeObjectRelease") \ + do_name(compareAndSwapLong_name, "compareAndSwapLong") \ + do_name(compareAndExchangeLongVolatile_name, "compareAndExchangeLongVolatile") \ + do_name(compareAndExchangeLongAcquire_name, "compareAndExchangeLongAcquire") \ + do_name(compareAndExchangeLongRelease_name, "compareAndExchangeLongRelease") \ + do_name(compareAndSwapInt_name, "compareAndSwapInt") \ + do_name(compareAndExchangeIntVolatile_name, "compareAndExchangeIntVolatile") \ + do_name(compareAndExchangeIntAcquire_name, "compareAndExchangeIntAcquire") \ + do_name(compareAndExchangeIntRelease_name, "compareAndExchangeIntRelease") \ + \ + do_name(weakCompareAndSwapObject_name, "weakCompareAndSwapObject") \ + do_name(weakCompareAndSwapObjectAcquire_name, "weakCompareAndSwapObjectAcquire") \ + do_name(weakCompareAndSwapObjectRelease_name, "weakCompareAndSwapObjectRelease") \ + do_name(weakCompareAndSwapLong_name, "weakCompareAndSwapLong") \ + do_name(weakCompareAndSwapLongAcquire_name, "weakCompareAndSwapLongAcquire") \ + do_name(weakCompareAndSwapLongRelease_name, "weakCompareAndSwapLongRelease") \ + do_name(weakCompareAndSwapInt_name, "weakCompareAndSwapInt") \ + do_name(weakCompareAndSwapIntAcquire_name, "weakCompareAndSwapIntAcquire") \ + do_name(weakCompareAndSwapIntRelease_name, "weakCompareAndSwapIntRelease") \ + \ + do_intrinsic(_compareAndSwapObject, jdk_internal_misc_Unsafe, compareAndSwapObject_name, compareAndSwapObject_signature, F_RN) \ + do_intrinsic(_compareAndExchangeObjectVolatile, jdk_internal_misc_Unsafe, compareAndExchangeObjectVolatile_name, compareAndExchangeObject_signature, F_RN) \ + do_intrinsic(_compareAndExchangeObjectAcquire, jdk_internal_misc_Unsafe, compareAndExchangeObjectAcquire_name, compareAndExchangeObject_signature, F_R) \ + do_intrinsic(_compareAndExchangeObjectRelease, jdk_internal_misc_Unsafe, compareAndExchangeObjectRelease_name, compareAndExchangeObject_signature, F_R) \ + do_intrinsic(_compareAndSwapLong, jdk_internal_misc_Unsafe, compareAndSwapLong_name, compareAndSwapLong_signature, F_RN) \ + do_intrinsic(_compareAndExchangeLongVolatile, jdk_internal_misc_Unsafe, compareAndExchangeLongVolatile_name, compareAndExchangeLong_signature, F_RN) \ + do_intrinsic(_compareAndExchangeLongAcquire, jdk_internal_misc_Unsafe, compareAndExchangeLongAcquire_name, compareAndExchangeLong_signature, F_R) \ + do_intrinsic(_compareAndExchangeLongRelease, jdk_internal_misc_Unsafe, compareAndExchangeLongRelease_name, compareAndExchangeLong_signature, F_R) \ + do_intrinsic(_compareAndSwapInt, jdk_internal_misc_Unsafe, compareAndSwapInt_name, compareAndSwapInt_signature, F_RN) \ + do_intrinsic(_compareAndExchangeIntVolatile, jdk_internal_misc_Unsafe, compareAndExchangeIntVolatile_name, compareAndExchangeInt_signature, F_RN) \ + do_intrinsic(_compareAndExchangeIntAcquire, jdk_internal_misc_Unsafe, compareAndExchangeIntAcquire_name, compareAndExchangeInt_signature, F_R) \ + do_intrinsic(_compareAndExchangeIntRelease, jdk_internal_misc_Unsafe, compareAndExchangeIntRelease_name, compareAndExchangeInt_signature, F_R) \ + \ + do_intrinsic(_weakCompareAndSwapObject, jdk_internal_misc_Unsafe, weakCompareAndSwapObject_name, compareAndSwapObject_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapObjectAcquire, jdk_internal_misc_Unsafe, weakCompareAndSwapObjectAcquire_name, compareAndSwapObject_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapObjectRelease, jdk_internal_misc_Unsafe, weakCompareAndSwapObjectRelease_name, compareAndSwapObject_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapLong, jdk_internal_misc_Unsafe, weakCompareAndSwapLong_name, compareAndSwapLong_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapLongAcquire, jdk_internal_misc_Unsafe, weakCompareAndSwapLongAcquire_name, compareAndSwapLong_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapLongRelease, jdk_internal_misc_Unsafe, weakCompareAndSwapLongRelease_name, compareAndSwapLong_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapInt, jdk_internal_misc_Unsafe, weakCompareAndSwapInt_name, compareAndSwapInt_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapIntAcquire, jdk_internal_misc_Unsafe, weakCompareAndSwapIntAcquire_name, compareAndSwapInt_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapIntRelease, jdk_internal_misc_Unsafe, weakCompareAndSwapIntRelease_name, compareAndSwapInt_signature, F_R) \ + \ + do_intrinsic(_putOrderedObject, jdk_internal_misc_Unsafe, putOrderedObject_name, putOrderedObject_signature, F_RN) \ + do_name( putOrderedObject_name, "putOrderedObject") \ + do_alias( putOrderedObject_signature, /*(LObject;JLObject;)V*/ putObject_signature) \ + do_intrinsic(_putOrderedLong, jdk_internal_misc_Unsafe, putOrderedLong_name, putOrderedLong_signature, F_RN) \ + do_name( putOrderedLong_name, "putOrderedLong") \ + do_alias( putOrderedLong_signature, /*(Ljava/lang/Object;JJ)V*/ putLong_signature) \ + do_intrinsic(_putOrderedInt, jdk_internal_misc_Unsafe, putOrderedInt_name, putOrderedInt_signature, F_RN) \ + do_name( putOrderedInt_name, "putOrderedInt") \ + do_alias( putOrderedInt_signature, /*(Ljava/lang/Object;JI)V*/ putInt_signature) \ \ do_intrinsic(_getAndAddInt, jdk_internal_misc_Unsafe, getAndAddInt_name, getAndAddInt_signature, F_R) \ do_name( getAndAddInt_name, "getAndAddInt") \ diff --git a/hotspot/src/share/vm/opto/c2compiler.cpp b/hotspot/src/share/vm/opto/c2compiler.cpp index 7068b5cfb1a..aeea26748fe 100644 --- a/hotspot/src/share/vm/opto/c2compiler.cpp +++ b/hotspot/src/share/vm/opto/c2compiler.cpp @@ -243,14 +243,72 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_reverseBytes_l: if (!Matcher::match_rule_supported(Op_ReverseBytesL)) return false; break; + + /* CompareAndSwap, Object: */ case vmIntrinsics::_compareAndSwapObject: #ifdef _LP64 + if ( UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndSwapN)) return false; if (!UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndSwapP)) return false; +#else + if (!Matcher::match_rule_supported(Op_CompareAndSwapP)) return false; #endif break; + case vmIntrinsics::_weakCompareAndSwapObject: + case vmIntrinsics::_weakCompareAndSwapObjectAcquire: + case vmIntrinsics::_weakCompareAndSwapObjectRelease: +#ifdef _LP64 + if ( UseCompressedOops && !Matcher::match_rule_supported(Op_WeakCompareAndSwapN)) return false; + if (!UseCompressedOops && !Matcher::match_rule_supported(Op_WeakCompareAndSwapP)) return false; +#else + if (!Matcher::match_rule_supported(Op_WeakCompareAndSwapP)) return false; +#endif + break; + /* CompareAndSwap, Long: */ case vmIntrinsics::_compareAndSwapLong: if (!Matcher::match_rule_supported(Op_CompareAndSwapL)) return false; break; + case vmIntrinsics::_weakCompareAndSwapLong: + case vmIntrinsics::_weakCompareAndSwapLongAcquire: + case vmIntrinsics::_weakCompareAndSwapLongRelease: + if (!Matcher::match_rule_supported(Op_WeakCompareAndSwapL)) return false; + break; + + /* CompareAndSwap, Int: */ + case vmIntrinsics::_compareAndSwapInt: + if (!Matcher::match_rule_supported(Op_CompareAndSwapI)) return false; + break; + case vmIntrinsics::_weakCompareAndSwapInt: + case vmIntrinsics::_weakCompareAndSwapIntAcquire: + case vmIntrinsics::_weakCompareAndSwapIntRelease: + if (!Matcher::match_rule_supported(Op_WeakCompareAndSwapL)) return false; + break; + + /* CompareAndExchange, Object: */ + case vmIntrinsics::_compareAndExchangeObjectVolatile: + case vmIntrinsics::_compareAndExchangeObjectAcquire: + case vmIntrinsics::_compareAndExchangeObjectRelease: +#ifdef _LP64 + if ( UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndExchangeN)) return false; + if (!UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndExchangeP)) return false; +#else + if (!Matcher::match_rule_supported(Op_CompareAndExchangeP)) return false; +#endif + break; + + /* CompareAndExchange, Long: */ + case vmIntrinsics::_compareAndExchangeLongVolatile: + case vmIntrinsics::_compareAndExchangeLongAcquire: + case vmIntrinsics::_compareAndExchangeLongRelease: + if (!Matcher::match_rule_supported(Op_CompareAndExchangeL)) return false; + break; + + /* CompareAndExchange, Int: */ + case vmIntrinsics::_compareAndExchangeIntVolatile: + case vmIntrinsics::_compareAndExchangeIntAcquire: + case vmIntrinsics::_compareAndExchangeIntRelease: + if (!Matcher::match_rule_supported(Op_CompareAndExchangeI)) return false; + break; + case vmIntrinsics::_getAndAddInt: if (!Matcher::match_rule_supported(Op_GetAndAddI)) return false; break; @@ -382,6 +440,42 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_putLongVolatile: case vmIntrinsics::_putFloatVolatile: case vmIntrinsics::_putDoubleVolatile: + case vmIntrinsics::_getObjectAcquire: + case vmIntrinsics::_getBooleanAcquire: + case vmIntrinsics::_getByteAcquire: + case vmIntrinsics::_getShortAcquire: + case vmIntrinsics::_getCharAcquire: + case vmIntrinsics::_getIntAcquire: + case vmIntrinsics::_getLongAcquire: + case vmIntrinsics::_getFloatAcquire: + case vmIntrinsics::_getDoubleAcquire: + case vmIntrinsics::_putObjectRelease: + case vmIntrinsics::_putBooleanRelease: + case vmIntrinsics::_putByteRelease: + case vmIntrinsics::_putShortRelease: + case vmIntrinsics::_putCharRelease: + case vmIntrinsics::_putIntRelease: + case vmIntrinsics::_putLongRelease: + case vmIntrinsics::_putFloatRelease: + case vmIntrinsics::_putDoubleRelease: + case vmIntrinsics::_getObjectOpaque: + case vmIntrinsics::_getBooleanOpaque: + case vmIntrinsics::_getByteOpaque: + case vmIntrinsics::_getShortOpaque: + case vmIntrinsics::_getCharOpaque: + case vmIntrinsics::_getIntOpaque: + case vmIntrinsics::_getLongOpaque: + case vmIntrinsics::_getFloatOpaque: + case vmIntrinsics::_getDoubleOpaque: + case vmIntrinsics::_putObjectOpaque: + case vmIntrinsics::_putBooleanOpaque: + case vmIntrinsics::_putByteOpaque: + case vmIntrinsics::_putShortOpaque: + case vmIntrinsics::_putCharOpaque: + case vmIntrinsics::_putIntOpaque: + case vmIntrinsics::_putLongOpaque: + case vmIntrinsics::_putFloatOpaque: + case vmIntrinsics::_putDoubleOpaque: case vmIntrinsics::_getShortUnaligned: case vmIntrinsics::_getCharUnaligned: case vmIntrinsics::_getIntUnaligned: @@ -390,7 +484,6 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_putCharUnaligned: case vmIntrinsics::_putIntUnaligned: case vmIntrinsics::_putLongUnaligned: - case vmIntrinsics::_compareAndSwapInt: case vmIntrinsics::_putOrderedObject: case vmIntrinsics::_putOrderedInt: case vmIntrinsics::_putOrderedLong: diff --git a/hotspot/src/share/vm/opto/classes.hpp b/hotspot/src/share/vm/opto/classes.hpp index e101a9768a2..ee36282de38 100644 --- a/hotspot/src/share/vm/opto/classes.hpp +++ b/hotspot/src/share/vm/opto/classes.hpp @@ -85,6 +85,14 @@ macro(CompareAndSwapI) macro(CompareAndSwapL) macro(CompareAndSwapP) macro(CompareAndSwapN) +macro(WeakCompareAndSwapI) +macro(WeakCompareAndSwapL) +macro(WeakCompareAndSwapP) +macro(WeakCompareAndSwapN) +macro(CompareAndExchangeI) +macro(CompareAndExchangeL) +macro(CompareAndExchangeP) +macro(CompareAndExchangeN) macro(GetAndAddI) macro(GetAndAddL) macro(GetAndSetI) diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 6e3e46d790f..ec737694e53 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -2786,6 +2786,14 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { case Op_CompareAndSwapL: case Op_CompareAndSwapP: case Op_CompareAndSwapN: + case Op_WeakCompareAndSwapI: + case Op_WeakCompareAndSwapL: + case Op_WeakCompareAndSwapP: + case Op_WeakCompareAndSwapN: + case Op_CompareAndExchangeI: + case Op_CompareAndExchangeL: + case Op_CompareAndExchangeP: + case Op_CompareAndExchangeN: case Op_GetAndAddI: case Op_GetAndAddL: case Op_GetAndSetI: diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index 310ac7fa70e..d2641d2acca 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -490,6 +490,8 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de } break; } + case Op_CompareAndExchangeP: + case Op_CompareAndExchangeN: case Op_GetAndSetP: case Op_GetAndSetN: { add_objload_to_connection_graph(n, delayed_worklist); @@ -499,6 +501,8 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de case Op_StoreN: case Op_StoreNKlass: case Op_StorePConditional: + case Op_WeakCompareAndSwapP: + case Op_WeakCompareAndSwapN: case Op_CompareAndSwapP: case Op_CompareAndSwapN: { Node* adr = n->in(MemNode::Address); @@ -698,8 +702,12 @@ void ConnectionGraph::add_final_edges(Node *n) { case Op_StoreN: case Op_StoreNKlass: case Op_StorePConditional: + case Op_CompareAndExchangeP: + case Op_CompareAndExchangeN: case Op_CompareAndSwapP: case Op_CompareAndSwapN: + case Op_WeakCompareAndSwapP: + case Op_WeakCompareAndSwapN: case Op_GetAndSetP: case Op_GetAndSetN: { Node* adr = n->in(MemNode::Address); diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index f604d59a1ac..de751bc1a97 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -241,7 +241,9 @@ class LibraryCallKit : public GraphKit { // Generates the guards that check whether the result of // Unsafe.getObject should be recorded in an SATB log buffer. void insert_pre_barrier(Node* base_oop, Node* offset, Node* pre_val, bool need_mem_bar); - bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool is_unaligned); + + typedef enum { Relaxed, Opaque, Volatile, Acquire, Release } AccessKind; + bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, AccessKind kind, bool is_unaligned); static bool klass_needs_init_guard(Node* kls); bool inline_unsafe_allocate(); bool inline_unsafe_copyMemory(); @@ -274,9 +276,10 @@ class LibraryCallKit : public GraphKit { JVMState* arraycopy_restore_alloc_state(AllocateArrayNode* alloc, int& saved_reexecute_sp); void arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms, int saved_reexecute_sp); - typedef enum { LS_xadd, LS_xchg, LS_cmpxchg } LoadStoreKind; - bool inline_unsafe_load_store(BasicType type, LoadStoreKind kind); - bool inline_unsafe_ordered_store(BasicType type); + typedef enum { LS_get_add, LS_get_set, LS_cmp_swap, LS_cmp_swap_weak, LS_cmp_exchange } LoadStoreKind; + MemNode::MemOrd access_kind_to_memord_LS(AccessKind access_kind, bool is_store); + MemNode::MemOrd access_kind_to_memord(AccessKind access_kind); + bool inline_unsafe_load_store(BasicType type, LoadStoreKind kind, AccessKind access_kind); bool inline_unsafe_fence(vmIntrinsics::ID id); bool inline_fp_conversions(vmIntrinsics::ID id); bool inline_number_methods(vmIntrinsics::ID id); @@ -553,86 +556,147 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_inflateStringC: case vmIntrinsics::_inflateStringB: return inline_string_copy(!is_compress); - case vmIntrinsics::_getObject: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, !is_volatile, false); - case vmIntrinsics::_getBoolean: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, !is_volatile, false); - case vmIntrinsics::_getByte: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, !is_volatile, false); - case vmIntrinsics::_getShort: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, !is_volatile, false); - case vmIntrinsics::_getChar: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, !is_volatile, false); - case vmIntrinsics::_getInt: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, !is_volatile, false); - case vmIntrinsics::_getLong: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile, false); - case vmIntrinsics::_getFloat: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, !is_volatile, false); - case vmIntrinsics::_getDouble: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, !is_volatile, false); - case vmIntrinsics::_putObject: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, !is_volatile, false); - case vmIntrinsics::_putBoolean: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, !is_volatile, false); - case vmIntrinsics::_putByte: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, !is_volatile, false); - case vmIntrinsics::_putShort: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, !is_volatile, false); - case vmIntrinsics::_putChar: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, !is_volatile, false); - case vmIntrinsics::_putInt: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, !is_volatile, false); - case vmIntrinsics::_putLong: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, !is_volatile, false); - case vmIntrinsics::_putFloat: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, !is_volatile, false); - case vmIntrinsics::_putDouble: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, !is_volatile, false); + case vmIntrinsics::_getObject: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, Relaxed, false); + case vmIntrinsics::_getBoolean: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, Relaxed, false); + case vmIntrinsics::_getByte: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, Relaxed, false); + case vmIntrinsics::_getShort: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Relaxed, false); + case vmIntrinsics::_getChar: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Relaxed, false); + case vmIntrinsics::_getInt: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Relaxed, false); + case vmIntrinsics::_getLong: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Relaxed, false); + case vmIntrinsics::_getFloat: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, Relaxed, false); + case vmIntrinsics::_getDouble: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, Relaxed, false); - case vmIntrinsics::_getByte_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_BYTE, !is_volatile, false); - case vmIntrinsics::_getShort_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_SHORT, !is_volatile, false); - case vmIntrinsics::_getChar_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_CHAR, !is_volatile, false); - case vmIntrinsics::_getInt_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_INT, !is_volatile, false); - case vmIntrinsics::_getLong_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_LONG, !is_volatile, false); - case vmIntrinsics::_getFloat_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_FLOAT, !is_volatile, false); - case vmIntrinsics::_getDouble_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_DOUBLE, !is_volatile, false); - case vmIntrinsics::_getAddress_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_ADDRESS, !is_volatile, false); + case vmIntrinsics::_putObject: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Relaxed, false); + case vmIntrinsics::_putBoolean: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, Relaxed, false); + case vmIntrinsics::_putByte: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, Relaxed, false); + case vmIntrinsics::_putShort: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Relaxed, false); + case vmIntrinsics::_putChar: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Relaxed, false); + case vmIntrinsics::_putInt: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Relaxed, false); + case vmIntrinsics::_putLong: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Relaxed, false); + case vmIntrinsics::_putFloat: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, Relaxed, false); + case vmIntrinsics::_putDouble: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, Relaxed, false); - case vmIntrinsics::_putByte_raw: return inline_unsafe_access( is_native_ptr, is_store, T_BYTE, !is_volatile, false); - case vmIntrinsics::_putShort_raw: return inline_unsafe_access( is_native_ptr, is_store, T_SHORT, !is_volatile, false); - case vmIntrinsics::_putChar_raw: return inline_unsafe_access( is_native_ptr, is_store, T_CHAR, !is_volatile, false); - case vmIntrinsics::_putInt_raw: return inline_unsafe_access( is_native_ptr, is_store, T_INT, !is_volatile, false); - case vmIntrinsics::_putLong_raw: return inline_unsafe_access( is_native_ptr, is_store, T_LONG, !is_volatile, false); - case vmIntrinsics::_putFloat_raw: return inline_unsafe_access( is_native_ptr, is_store, T_FLOAT, !is_volatile, false); - case vmIntrinsics::_putDouble_raw: return inline_unsafe_access( is_native_ptr, is_store, T_DOUBLE, !is_volatile, false); - case vmIntrinsics::_putAddress_raw: return inline_unsafe_access( is_native_ptr, is_store, T_ADDRESS, !is_volatile, false); + case vmIntrinsics::_getByte_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_BYTE, Relaxed, false); + case vmIntrinsics::_getShort_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_SHORT, Relaxed, false); + case vmIntrinsics::_getChar_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_CHAR, Relaxed, false); + case vmIntrinsics::_getInt_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_INT, Relaxed, false); + case vmIntrinsics::_getLong_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_LONG, Relaxed, false); + case vmIntrinsics::_getFloat_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_FLOAT, Relaxed, false); + case vmIntrinsics::_getDouble_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_DOUBLE, Relaxed, false); + case vmIntrinsics::_getAddress_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_ADDRESS, Relaxed, false); - case vmIntrinsics::_getObjectVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, is_volatile, false); - case vmIntrinsics::_getBooleanVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, is_volatile, false); - case vmIntrinsics::_getByteVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, is_volatile, false); - case vmIntrinsics::_getShortVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, is_volatile, false); - case vmIntrinsics::_getCharVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, is_volatile, false); - case vmIntrinsics::_getIntVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, is_volatile, false); - case vmIntrinsics::_getLongVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, is_volatile, false); - case vmIntrinsics::_getFloatVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, is_volatile, false); - case vmIntrinsics::_getDoubleVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, is_volatile, false); + case vmIntrinsics::_putByte_raw: return inline_unsafe_access( is_native_ptr, is_store, T_BYTE, Relaxed, false); + case vmIntrinsics::_putShort_raw: return inline_unsafe_access( is_native_ptr, is_store, T_SHORT, Relaxed, false); + case vmIntrinsics::_putChar_raw: return inline_unsafe_access( is_native_ptr, is_store, T_CHAR, Relaxed, false); + case vmIntrinsics::_putInt_raw: return inline_unsafe_access( is_native_ptr, is_store, T_INT, Relaxed, false); + case vmIntrinsics::_putLong_raw: return inline_unsafe_access( is_native_ptr, is_store, T_LONG, Relaxed, false); + case vmIntrinsics::_putFloat_raw: return inline_unsafe_access( is_native_ptr, is_store, T_FLOAT, Relaxed, false); + case vmIntrinsics::_putDouble_raw: return inline_unsafe_access( is_native_ptr, is_store, T_DOUBLE, Relaxed, false); + case vmIntrinsics::_putAddress_raw: return inline_unsafe_access( is_native_ptr, is_store, T_ADDRESS, Relaxed, false); - case vmIntrinsics::_putObjectVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, is_volatile, false); - case vmIntrinsics::_putBooleanVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, is_volatile, false); - case vmIntrinsics::_putByteVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, is_volatile, false); - case vmIntrinsics::_putShortVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, is_volatile, false); - case vmIntrinsics::_putCharVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, is_volatile, false); - case vmIntrinsics::_putIntVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, is_volatile, false); - case vmIntrinsics::_putLongVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, is_volatile, false); - case vmIntrinsics::_putFloatVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, is_volatile, false); - case vmIntrinsics::_putDoubleVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, is_volatile, false); + case vmIntrinsics::_getObjectVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, Volatile, false); + case vmIntrinsics::_getBooleanVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, Volatile, false); + case vmIntrinsics::_getByteVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, Volatile, false); + case vmIntrinsics::_getShortVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Volatile, false); + case vmIntrinsics::_getCharVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Volatile, false); + case vmIntrinsics::_getIntVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Volatile, false); + case vmIntrinsics::_getLongVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Volatile, false); + case vmIntrinsics::_getFloatVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, Volatile, false); + case vmIntrinsics::_getDoubleVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, Volatile, false); - case vmIntrinsics::_getShortUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, !is_volatile, true); - case vmIntrinsics::_getCharUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, !is_volatile, true); - case vmIntrinsics::_getIntUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, !is_volatile, true); - case vmIntrinsics::_getLongUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile, true); + case vmIntrinsics::_putObjectVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Volatile, false); + case vmIntrinsics::_putBooleanVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, Volatile, false); + case vmIntrinsics::_putByteVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, Volatile, false); + case vmIntrinsics::_putShortVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Volatile, false); + case vmIntrinsics::_putCharVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Volatile, false); + case vmIntrinsics::_putIntVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Volatile, false); + case vmIntrinsics::_putLongVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Volatile, false); + case vmIntrinsics::_putFloatVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, Volatile, false); + case vmIntrinsics::_putDoubleVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, Volatile, false); - case vmIntrinsics::_putShortUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, !is_volatile, true); - case vmIntrinsics::_putCharUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, !is_volatile, true); - case vmIntrinsics::_putIntUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, !is_volatile, true); - case vmIntrinsics::_putLongUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, !is_volatile, true); + case vmIntrinsics::_getShortUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Relaxed, true); + case vmIntrinsics::_getCharUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Relaxed, true); + case vmIntrinsics::_getIntUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Relaxed, true); + case vmIntrinsics::_getLongUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Relaxed, true); - case vmIntrinsics::_compareAndSwapObject: return inline_unsafe_load_store(T_OBJECT, LS_cmpxchg); - case vmIntrinsics::_compareAndSwapInt: return inline_unsafe_load_store(T_INT, LS_cmpxchg); - case vmIntrinsics::_compareAndSwapLong: return inline_unsafe_load_store(T_LONG, LS_cmpxchg); + case vmIntrinsics::_putShortUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Relaxed, true); + case vmIntrinsics::_putCharUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Relaxed, true); + case vmIntrinsics::_putIntUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Relaxed, true); + case vmIntrinsics::_putLongUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Relaxed, true); - case vmIntrinsics::_putOrderedObject: return inline_unsafe_ordered_store(T_OBJECT); - case vmIntrinsics::_putOrderedInt: return inline_unsafe_ordered_store(T_INT); - case vmIntrinsics::_putOrderedLong: return inline_unsafe_ordered_store(T_LONG); + case vmIntrinsics::_putOrderedObject: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Release, false); + case vmIntrinsics::_putOrderedInt: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Release, false); + case vmIntrinsics::_putOrderedLong: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Release, false); - case vmIntrinsics::_getAndAddInt: return inline_unsafe_load_store(T_INT, LS_xadd); - case vmIntrinsics::_getAndAddLong: return inline_unsafe_load_store(T_LONG, LS_xadd); - case vmIntrinsics::_getAndSetInt: return inline_unsafe_load_store(T_INT, LS_xchg); - case vmIntrinsics::_getAndSetLong: return inline_unsafe_load_store(T_LONG, LS_xchg); - case vmIntrinsics::_getAndSetObject: return inline_unsafe_load_store(T_OBJECT, LS_xchg); + case vmIntrinsics::_getObjectAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, Acquire, false); + case vmIntrinsics::_getBooleanAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, Acquire, false); + case vmIntrinsics::_getByteAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, Acquire, false); + case vmIntrinsics::_getShortAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Acquire, false); + case vmIntrinsics::_getCharAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Acquire, false); + case vmIntrinsics::_getIntAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Acquire, false); + case vmIntrinsics::_getLongAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Acquire, false); + case vmIntrinsics::_getFloatAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, Acquire, false); + case vmIntrinsics::_getDoubleAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, Acquire, false); + + case vmIntrinsics::_putObjectRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Release, false); + case vmIntrinsics::_putBooleanRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, Release, false); + case vmIntrinsics::_putByteRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, Release, false); + case vmIntrinsics::_putShortRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Release, false); + case vmIntrinsics::_putCharRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Release, false); + case vmIntrinsics::_putIntRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Release, false); + case vmIntrinsics::_putLongRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Release, false); + case vmIntrinsics::_putFloatRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, Release, false); + case vmIntrinsics::_putDoubleRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, Release, false); + + case vmIntrinsics::_getObjectOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, Opaque, false); + case vmIntrinsics::_getBooleanOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, Opaque, false); + case vmIntrinsics::_getByteOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, Opaque, false); + case vmIntrinsics::_getShortOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Opaque, false); + case vmIntrinsics::_getCharOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Opaque, false); + case vmIntrinsics::_getIntOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Opaque, false); + case vmIntrinsics::_getLongOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Opaque, false); + case vmIntrinsics::_getFloatOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, Opaque, false); + case vmIntrinsics::_getDoubleOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, Opaque, false); + + case vmIntrinsics::_putObjectOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Opaque, false); + case vmIntrinsics::_putBooleanOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, Opaque, false); + case vmIntrinsics::_putByteOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, Opaque, false); + case vmIntrinsics::_putShortOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Opaque, false); + case vmIntrinsics::_putCharOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Opaque, false); + case vmIntrinsics::_putIntOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Opaque, false); + case vmIntrinsics::_putLongOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Opaque, false); + case vmIntrinsics::_putFloatOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, Opaque, false); + case vmIntrinsics::_putDoubleOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, Opaque, false); + + case vmIntrinsics::_compareAndSwapObject: return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap, Volatile); + case vmIntrinsics::_compareAndSwapInt: return inline_unsafe_load_store(T_INT, LS_cmp_swap, Volatile); + case vmIntrinsics::_compareAndSwapLong: return inline_unsafe_load_store(T_LONG, LS_cmp_swap, Volatile); + + case vmIntrinsics::_weakCompareAndSwapObject: return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap_weak, Relaxed); + case vmIntrinsics::_weakCompareAndSwapObjectAcquire: return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap_weak, Acquire); + case vmIntrinsics::_weakCompareAndSwapObjectRelease: return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap_weak, Release); + case vmIntrinsics::_weakCompareAndSwapInt: return inline_unsafe_load_store(T_INT, LS_cmp_swap_weak, Relaxed); + case vmIntrinsics::_weakCompareAndSwapIntAcquire: return inline_unsafe_load_store(T_INT, LS_cmp_swap_weak, Acquire); + case vmIntrinsics::_weakCompareAndSwapIntRelease: return inline_unsafe_load_store(T_INT, LS_cmp_swap_weak, Release); + case vmIntrinsics::_weakCompareAndSwapLong: return inline_unsafe_load_store(T_LONG, LS_cmp_swap_weak, Relaxed); + case vmIntrinsics::_weakCompareAndSwapLongAcquire: return inline_unsafe_load_store(T_LONG, LS_cmp_swap_weak, Acquire); + case vmIntrinsics::_weakCompareAndSwapLongRelease: return inline_unsafe_load_store(T_LONG, LS_cmp_swap_weak, Release); + + case vmIntrinsics::_compareAndExchangeObjectVolatile: return inline_unsafe_load_store(T_OBJECT, LS_cmp_exchange, Volatile); + case vmIntrinsics::_compareAndExchangeObjectAcquire: return inline_unsafe_load_store(T_OBJECT, LS_cmp_exchange, Acquire); + case vmIntrinsics::_compareAndExchangeObjectRelease: return inline_unsafe_load_store(T_OBJECT, LS_cmp_exchange, Release); + case vmIntrinsics::_compareAndExchangeIntVolatile: return inline_unsafe_load_store(T_INT, LS_cmp_exchange, Volatile); + case vmIntrinsics::_compareAndExchangeIntAcquire: return inline_unsafe_load_store(T_INT, LS_cmp_exchange, Acquire); + case vmIntrinsics::_compareAndExchangeIntRelease: return inline_unsafe_load_store(T_INT, LS_cmp_exchange, Release); + case vmIntrinsics::_compareAndExchangeLongVolatile: return inline_unsafe_load_store(T_LONG, LS_cmp_exchange, Volatile); + case vmIntrinsics::_compareAndExchangeLongAcquire: return inline_unsafe_load_store(T_LONG, LS_cmp_exchange, Acquire); + case vmIntrinsics::_compareAndExchangeLongRelease: return inline_unsafe_load_store(T_LONG, LS_cmp_exchange, Release); + + case vmIntrinsics::_getAndAddInt: return inline_unsafe_load_store(T_INT, LS_get_add, Volatile); + case vmIntrinsics::_getAndAddLong: return inline_unsafe_load_store(T_LONG, LS_get_add, Volatile); + case vmIntrinsics::_getAndSetInt: return inline_unsafe_load_store(T_INT, LS_get_set, Volatile); + case vmIntrinsics::_getAndSetLong: return inline_unsafe_load_store(T_LONG, LS_get_set, Volatile); + case vmIntrinsics::_getAndSetObject: return inline_unsafe_load_store(T_OBJECT, LS_get_set, Volatile); case vmIntrinsics::_loadFence: case vmIntrinsics::_storeFence: @@ -2284,8 +2348,10 @@ const TypeOopPtr* LibraryCallKit::sharpen_unsafe_type(Compile::AliasType* alias_ return NULL; } -bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool unaligned) { +bool LibraryCallKit::inline_unsafe_access(const bool is_native_ptr, bool is_store, const BasicType type, const AccessKind kind, const bool unaligned) { if (callee()->is_static()) return false; // caller must have the capability! + guarantee(!is_store || kind != Acquire, "Acquire accesses can be produced only for loads"); + guarantee( is_store || kind != Release, "Release accesses can be produced only for stores"); #ifndef PRODUCT { @@ -2374,7 +2440,42 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas // the barriers get omitted and the unsafe reference begins to "pollute" // the alias analysis of the rest of the graph, either Compile::can_alias // or Compile::must_alias will throw a diagnostic assert.) - bool need_mem_bar = (alias_type->adr_type() == TypeOopPtr::BOTTOM); + bool need_mem_bar; + switch (kind) { + case Relaxed: + need_mem_bar = (alias_type->adr_type() == TypeOopPtr::BOTTOM); + break; + case Opaque: + // Opaque uses CPUOrder membars for protection against code movement. + case Acquire: + case Release: + case Volatile: + need_mem_bar = true; + break; + default: + ShouldNotReachHere(); + } + + // Some accesses require access atomicity for all types, notably longs and doubles. + // When AlwaysAtomicAccesses is enabled, all accesses are atomic. + bool requires_atomic_access = false; + switch (kind) { + case Relaxed: + case Opaque: + requires_atomic_access = AlwaysAtomicAccesses; + break; + case Acquire: + case Release: + case Volatile: + requires_atomic_access = true; + break; + default: + ShouldNotReachHere(); + } + + // Figure out the memory ordering. + // Acquire/Release/Volatile accesses require marking the loads/stores with MemOrd + MemNode::MemOrd mo = access_kind_to_memord_LS(kind, is_store); // If we are reading the value of the referent field of a Reference // object (either by using Unsafe directly or through reflection) @@ -2401,22 +2502,30 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas // and it is not possible to fully distinguish unintended nulls // from intended ones in this API. - if (is_volatile) { - // We need to emit leading and trailing CPU membars (see below) in - // addition to memory membars when is_volatile. This is a little - // too strong, but avoids the need to insert per-alias-type - // volatile membars (for stores; compare Parse::do_put_xxx), which - // we cannot do effectively here because we probably only have a - // rough approximation of type. - need_mem_bar = true; - // For Stores, place a memory ordering barrier now. - if (is_store) { - insert_mem_bar(Op_MemBarRelease); - } else { - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - insert_mem_bar(Op_MemBarVolatile); + // We need to emit leading and trailing CPU membars (see below) in + // addition to memory membars for special access modes. This is a little + // too strong, but avoids the need to insert per-alias-type + // volatile membars (for stores; compare Parse::do_put_xxx), which + // we cannot do effectively here because we probably only have a + // rough approximation of type. + + switch(kind) { + case Relaxed: + case Opaque: + case Acquire: + break; + case Release: + case Volatile: + if (is_store) { + insert_mem_bar(Op_MemBarRelease); + } else { + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + insert_mem_bar(Op_MemBarVolatile); + } } - } + break; + default: + ShouldNotReachHere(); } // Memory barrier to prevent normal and 'unsafe' accesses from @@ -2460,10 +2569,9 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas } } if (p == NULL) { - MemNode::MemOrd mo = is_volatile ? MemNode::acquire : MemNode::unordered; // To be valid, unsafe loads may depend on other conditions than // the one that guards them: pin the Load node - p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, is_volatile, unaligned, mismatched); + p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, requires_atomic_access, unaligned, mismatched); // load value switch (type) { case T_BOOLEAN: @@ -2477,7 +2585,9 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas break; case T_OBJECT: if (need_read_barrier) { - insert_pre_barrier(heap_base_oop, offset, p, !(is_volatile || need_mem_bar)); + // We do not require a mem bar inside pre_barrier if need_mem_bar + // is set: the barriers would be emitted by us. + insert_pre_barrier(heap_base_oop, offset, p, !need_mem_bar); } break; case T_ADDRESS: @@ -2508,9 +2618,8 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas break; } - MemNode::MemOrd mo = is_volatile ? MemNode::release : MemNode::unordered; - if (type != T_OBJECT ) { - (void) store_to_memory(control(), adr, val, type, adr_type, mo, is_volatile, unaligned, mismatched); + if (type != T_OBJECT) { + (void) store_to_memory(control(), adr, val, type, adr_type, mo, requires_atomic_access, unaligned, mismatched); } else { // Possibly an oop being stored to Java heap or native memory if (!TypePtr::NULL_PTR->higher_equal(_gvn.type(heap_base_oop))) { @@ -2531,7 +2640,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas // Update IdealKit memory. __ sync_kit(this); } __ else_(); { - __ store(__ ctrl(), adr, val, type, alias_type->index(), mo, is_volatile, mismatched); + __ store(__ ctrl(), adr, val, type, alias_type->index(), mo, requires_atomic_access, mismatched); } __ end_if(); // Final sync IdealKit and GraphKit. final_sync(ideal); @@ -2540,14 +2649,23 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas } } - if (is_volatile) { - if (!is_store) { - insert_mem_bar(Op_MemBarAcquire); - } else { - if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { - insert_mem_bar(Op_MemBarVolatile); + switch(kind) { + case Relaxed: + case Opaque: + case Release: + break; + case Acquire: + case Volatile: + if (!is_store) { + insert_mem_bar(Op_MemBarAcquire); + } else { + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + insert_mem_bar(Op_MemBarVolatile); + } } - } + break; + default: + ShouldNotReachHere(); } if (need_mem_bar) insert_mem_bar(Op_MemBarCPUOrder); @@ -2558,21 +2676,52 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas //----------------------------inline_unsafe_load_store---------------------------- // This method serves a couple of different customers (depending on LoadStoreKind): // -// LS_cmpxchg: -// public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x); -// public final native boolean compareAndSwapInt( Object o, long offset, int expected, int x); -// public final native boolean compareAndSwapLong( Object o, long offset, long expected, long x); +// LS_cmp_swap: // -// LS_xadd: -// public int getAndAddInt( Object o, long offset, int delta) -// public long getAndAddLong(Object o, long offset, long delta) +// boolean compareAndSwapObject(Object o, long offset, Object expected, Object x); +// boolean compareAndSwapInt( Object o, long offset, int expected, int x); +// boolean compareAndSwapLong( Object o, long offset, long expected, long x); +// +// LS_cmp_swap_weak: +// +// boolean weakCompareAndSwapObject( Object o, long offset, Object expected, Object x); +// boolean weakCompareAndSwapObjectAcquire(Object o, long offset, Object expected, Object x); +// boolean weakCompareAndSwapObjectRelease(Object o, long offset, Object expected, Object x); +// +// boolean weakCompareAndSwapInt( Object o, long offset, int expected, int x); +// boolean weakCompareAndSwapIntAcquire( Object o, long offset, int expected, int x); +// boolean weakCompareAndSwapIntRelease( Object o, long offset, int expected, int x); +// +// boolean weakCompareAndSwapLong( Object o, long offset, long expected, long x); +// boolean weakCompareAndSwapLongAcquire( Object o, long offset, long expected, long x); +// boolean weakCompareAndSwapLongRelease( Object o, long offset, long expected, long x); +// +// LS_cmp_exchange: +// +// Object compareAndExchangeObjectVolatile(Object o, long offset, Object expected, Object x); +// Object compareAndExchangeObjectAcquire( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeObjectRelease( Object o, long offset, Object expected, Object x); +// +// Object compareAndExchangeIntVolatile( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeIntAcquire( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeIntRelease( Object o, long offset, Object expected, Object x); +// +// Object compareAndExchangeLongVolatile( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeLongAcquire( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeLongRelease( Object o, long offset, Object expected, Object x); +// +// LS_get_add: +// +// int getAndAddInt( Object o, long offset, int delta) +// long getAndAddLong(Object o, long offset, long delta) +// +// LS_get_set: // -// LS_xchg: // int getAndSet(Object o, long offset, int newValue) // long getAndSet(Object o, long offset, long newValue) // Object getAndSet(Object o, long offset, Object newValue) // -bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind) { +bool LibraryCallKit::inline_unsafe_load_store(const BasicType type, const LoadStoreKind kind, const AccessKind access_kind) { // This basic scheme here is the same as inline_unsafe_access, but // differs in enough details that combining them would make the code // overly confusing. (This is a true fact! I originally combined @@ -2589,7 +2738,9 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind // Check the signatures. ciSignature* sig = callee()->signature(); rtype = sig->return_type()->basic_type(); - if (kind == LS_xadd || kind == LS_xchg) { + switch(kind) { + case LS_get_add: + case LS_get_set: { // Check the signatures. #ifdef ASSERT assert(rtype == type, "get and set must return the expected type"); @@ -2598,7 +2749,10 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind assert(sig->type_at(1)->basic_type() == T_LONG, "get and set offset is long"); assert(sig->type_at(2)->basic_type() == type, "get and set must take expected type as new value/delta"); #endif // ASSERT - } else if (kind == LS_cmpxchg) { + break; + } + case LS_cmp_swap: + case LS_cmp_swap_weak: { // Check the signatures. #ifdef ASSERT assert(rtype == T_BOOLEAN, "CAS must return boolean"); @@ -2606,8 +2760,20 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind assert(sig->type_at(0)->basic_type() == T_OBJECT, "CAS base is object"); assert(sig->type_at(1)->basic_type() == T_LONG, "CAS offset is long"); #endif // ASSERT - } else { - ShouldNotReachHere(); + break; + } + case LS_cmp_exchange: { + // Check the signatures. +#ifdef ASSERT + assert(rtype == type, "CAS must return the expected type"); + assert(sig->count() == 4, "CAS has 4 arguments"); + assert(sig->type_at(0)->basic_type() == T_OBJECT, "CAS base is object"); + assert(sig->type_at(1)->basic_type() == T_LONG, "CAS offset is long"); +#endif // ASSERT + break; + } + default: + ShouldNotReachHere(); } } #endif //PRODUCT @@ -2620,19 +2786,29 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind Node* offset = NULL; Node* oldval = NULL; Node* newval = NULL; - if (kind == LS_cmpxchg) { - const bool two_slot_type = type2size[type] == 2; - receiver = argument(0); // type: oop - base = argument(1); // type: oop - offset = argument(2); // type: long - oldval = argument(4); // type: oop, int, or long - newval = argument(two_slot_type ? 6 : 5); // type: oop, int, or long - } else if (kind == LS_xadd || kind == LS_xchg){ - receiver = argument(0); // type: oop - base = argument(1); // type: oop - offset = argument(2); // type: long - oldval = NULL; - newval = argument(4); // type: oop, int, or long + switch(kind) { + case LS_cmp_swap: + case LS_cmp_swap_weak: + case LS_cmp_exchange: { + const bool two_slot_type = type2size[type] == 2; + receiver = argument(0); // type: oop + base = argument(1); // type: oop + offset = argument(2); // type: long + oldval = argument(4); // type: oop, int, or long + newval = argument(two_slot_type ? 6 : 5); // type: oop, int, or long + break; + } + case LS_get_add: + case LS_get_set: { + receiver = argument(0); // type: oop + base = argument(1); // type: oop + offset = argument(2); // type: long + oldval = NULL; + newval = argument(4); // type: oop, int, or long + break; + } + default: + ShouldNotReachHere(); } // Null check receiver. @@ -2657,11 +2833,23 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind Compile::AliasType* alias_type = C->alias_type(adr_type); assert(alias_type->index() != Compile::AliasIdxBot, "no bare pointers here"); - if (kind == LS_xchg && type == T_OBJECT) { - const TypeOopPtr* tjp = sharpen_unsafe_type(alias_type, adr_type); - if (tjp != NULL) { - value_type = tjp; + switch (kind) { + case LS_get_set: + case LS_cmp_exchange: { + if (type == T_OBJECT) { + const TypeOopPtr* tjp = sharpen_unsafe_type(alias_type, adr_type); + if (tjp != NULL) { + value_type = tjp; + } + } + break; } + case LS_cmp_swap: + case LS_cmp_swap_weak: + case LS_get_add: + break; + default: + ShouldNotReachHere(); } int alias_idx = C->get_alias_index(adr_type); @@ -2671,9 +2859,22 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind // into actual barriers on most machines, but we still need rest of // compiler to respect ordering. - insert_mem_bar(Op_MemBarRelease); + switch (access_kind) { + case Relaxed: + case Acquire: + break; + case Release: + case Volatile: + insert_mem_bar(Op_MemBarRelease); + break; + default: + ShouldNotReachHere(); + } insert_mem_bar(Op_MemBarCPUOrder); + // Figure out the memory ordering. + MemNode::MemOrd mo = access_kind_to_memord(access_kind); + // 4984716: MemBars must be inserted before this // memory node in order to avoid a false // dependency which will confuse the scheduler. @@ -2684,25 +2885,45 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind Node* load_store = NULL; switch(type) { case T_INT: - if (kind == LS_xadd) { - load_store = _gvn.transform(new GetAndAddINode(control(), mem, adr, newval, adr_type)); - } else if (kind == LS_xchg) { - load_store = _gvn.transform(new GetAndSetINode(control(), mem, adr, newval, adr_type)); - } else if (kind == LS_cmpxchg) { - load_store = _gvn.transform(new CompareAndSwapINode(control(), mem, adr, newval, oldval)); - } else { - ShouldNotReachHere(); + switch(kind) { + case LS_get_add: + load_store = _gvn.transform(new GetAndAddINode(control(), mem, adr, newval, adr_type)); + break; + case LS_get_set: + load_store = _gvn.transform(new GetAndSetINode(control(), mem, adr, newval, adr_type)); + break; + case LS_cmp_swap_weak: + load_store = _gvn.transform(new WeakCompareAndSwapINode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_swap: + load_store = _gvn.transform(new CompareAndSwapINode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_exchange: + load_store = _gvn.transform(new CompareAndExchangeINode(control(), mem, adr, newval, oldval, adr_type, mo)); + break; + default: + ShouldNotReachHere(); } break; case T_LONG: - if (kind == LS_xadd) { - load_store = _gvn.transform(new GetAndAddLNode(control(), mem, adr, newval, adr_type)); - } else if (kind == LS_xchg) { - load_store = _gvn.transform(new GetAndSetLNode(control(), mem, adr, newval, adr_type)); - } else if (kind == LS_cmpxchg) { - load_store = _gvn.transform(new CompareAndSwapLNode(control(), mem, adr, newval, oldval)); - } else { - ShouldNotReachHere(); + switch(kind) { + case LS_get_add: + load_store = _gvn.transform(new GetAndAddLNode(control(), mem, adr, newval, adr_type)); + break; + case LS_get_set: + load_store = _gvn.transform(new GetAndSetLNode(control(), mem, adr, newval, adr_type)); + break; + case LS_cmp_swap_weak: + load_store = _gvn.transform(new WeakCompareAndSwapLNode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_swap: + load_store = _gvn.transform(new CompareAndSwapLNode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_exchange: + load_store = _gvn.transform(new CompareAndExchangeLNode(control(), mem, adr, newval, oldval, adr_type, mo)); + break; + default: + ShouldNotReachHere(); } break; case T_OBJECT: @@ -2713,65 +2934,109 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind newval = _gvn.makecon(TypePtr::NULL_PTR); // Reference stores need a store barrier. - if (kind == LS_xchg) { - // If pre-barrier must execute before the oop store, old value will require do_load here. - if (!can_move_pre_barrier()) { - pre_barrier(true /* do_load*/, - control(), base, adr, alias_idx, newval, value_type->make_oopptr(), - NULL /* pre_val*/, - T_OBJECT); - } // Else move pre_barrier to use load_store value, see below. - } else if (kind == LS_cmpxchg) { - // Same as for newval above: - if (_gvn.type(oldval) == TypePtr::NULL_PTR) { - oldval = _gvn.makecon(TypePtr::NULL_PTR); + switch(kind) { + case LS_get_set: { + // If pre-barrier must execute before the oop store, old value will require do_load here. + if (!can_move_pre_barrier()) { + pre_barrier(true /* do_load*/, + control(), base, adr, alias_idx, newval, value_type->make_oopptr(), + NULL /* pre_val*/, + T_OBJECT); + } // Else move pre_barrier to use load_store value, see below. + break; } - // The only known value which might get overwritten is oldval. - pre_barrier(false /* do_load */, - control(), NULL, NULL, max_juint, NULL, NULL, - oldval /* pre_val */, - T_OBJECT); - } else { - ShouldNotReachHere(); + case LS_cmp_swap_weak: + case LS_cmp_swap: + case LS_cmp_exchange: { + // Same as for newval above: + if (_gvn.type(oldval) == TypePtr::NULL_PTR) { + oldval = _gvn.makecon(TypePtr::NULL_PTR); + } + // The only known value which might get overwritten is oldval. + pre_barrier(false /* do_load */, + control(), NULL, NULL, max_juint, NULL, NULL, + oldval /* pre_val */, + T_OBJECT); + break; + } + default: + ShouldNotReachHere(); } #ifdef _LP64 if (adr->bottom_type()->is_ptr_to_narrowoop()) { Node *newval_enc = _gvn.transform(new EncodePNode(newval, newval->bottom_type()->make_narrowoop())); - if (kind == LS_xchg) { - load_store = _gvn.transform(new GetAndSetNNode(control(), mem, adr, - newval_enc, adr_type, value_type->make_narrowoop())); - } else { - assert(kind == LS_cmpxchg, "wrong LoadStore operation"); - Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop())); - load_store = _gvn.transform(new CompareAndSwapNNode(control(), mem, adr, - newval_enc, oldval_enc)); + + switch(kind) { + case LS_get_set: + load_store = _gvn.transform(new GetAndSetNNode(control(), mem, adr, newval_enc, adr_type, value_type->make_narrowoop())); + break; + case LS_cmp_swap_weak: { + Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop())); + load_store = _gvn.transform(new WeakCompareAndSwapNNode(control(), mem, adr, newval_enc, oldval_enc, mo)); + break; + } + case LS_cmp_swap: { + Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop())); + load_store = _gvn.transform(new CompareAndSwapNNode(control(), mem, adr, newval_enc, oldval_enc, mo)); + break; + } + case LS_cmp_exchange: { + Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop())); + load_store = _gvn.transform(new CompareAndExchangeNNode(control(), mem, adr, newval_enc, oldval_enc, adr_type, value_type->make_narrowoop(), mo)); + break; + } + default: + ShouldNotReachHere(); } } else #endif - { - if (kind == LS_xchg) { + switch (kind) { + case LS_get_set: load_store = _gvn.transform(new GetAndSetPNode(control(), mem, adr, newval, adr_type, value_type->is_oopptr())); - } else { - assert(kind == LS_cmpxchg, "wrong LoadStore operation"); - load_store = _gvn.transform(new CompareAndSwapPNode(control(), mem, adr, newval, oldval)); - } + break; + case LS_cmp_swap_weak: + load_store = _gvn.transform(new WeakCompareAndSwapPNode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_swap: + load_store = _gvn.transform(new CompareAndSwapPNode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_exchange: + load_store = _gvn.transform(new CompareAndExchangePNode(control(), mem, adr, newval, oldval, adr_type, value_type->is_oopptr(), mo)); + break; + default: + ShouldNotReachHere(); } - if (kind == LS_cmpxchg) { - // Emit the post barrier only when the actual store happened. - // This makes sense to check only for compareAndSet that can fail to set the value. - // CAS success path is marked more likely since we anticipate this is a performance - // critical path, while CAS failure path can use the penalty for going through unlikely - // path as backoff. Which is still better than doing a store barrier there. - IdealKit ideal(this); - ideal.if_then(load_store, BoolTest::ne, ideal.ConI(0), PROB_STATIC_FREQUENT); { - sync_kit(ideal); - post_barrier(ideal.ctrl(), load_store, base, adr, alias_idx, newval, T_OBJECT, true); - ideal.sync_kit(this); - } ideal.end_if(); - final_sync(ideal); - } else { - post_barrier(control(), load_store, base, adr, alias_idx, newval, T_OBJECT, true); + + // Emit the post barrier only when the actual store happened. This makes sense + // to check only for LS_cmp_* that can fail to set the value. + // LS_cmp_exchange does not produce any branches by default, so there is no + // boolean result to piggyback on. TODO: When we merge CompareAndSwap with + // CompareAndExchange and move branches here, it would make sense to conditionalize + // post_barriers for LS_cmp_exchange as well. + // + // CAS success path is marked more likely since we anticipate this is a performance + // critical path, while CAS failure path can use the penalty for going through unlikely + // path as backoff. Which is still better than doing a store barrier there. + switch (kind) { + case LS_get_set: + case LS_cmp_exchange: { + post_barrier(control(), load_store, base, adr, alias_idx, newval, T_OBJECT, true); + break; + } + case LS_cmp_swap_weak: + case LS_cmp_swap: { + IdealKit ideal(this); + ideal.if_then(load_store, BoolTest::ne, ideal.ConI(0), PROB_STATIC_FREQUENT); { + sync_kit(ideal); + post_barrier(ideal.ctrl(), load_store, base, adr, alias_idx, newval, T_OBJECT, true); + ideal.sync_kit(this); + } ideal.end_if(); + final_sync(ideal); + break; + } + default: + ShouldNotReachHere(); } break; default: @@ -2785,7 +3050,7 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind Node* proj = _gvn.transform(new SCMemProjNode(load_store)); set_memory(proj, alias_idx); - if (type == T_OBJECT && kind == LS_xchg) { + if (type == T_OBJECT && (kind == LS_get_set || kind == LS_cmp_exchange)) { #ifdef _LP64 if (adr->bottom_type()->is_ptr_to_narrowoop()) { load_store = _gvn.transform(new DecodeNNode(load_store, load_store->get_ptr_type())); @@ -2804,74 +3069,52 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind // Add the trailing membar surrounding the access insert_mem_bar(Op_MemBarCPUOrder); - insert_mem_bar(Op_MemBarAcquire); + + switch (access_kind) { + case Relaxed: + case Release: + break; // do nothing + case Acquire: + case Volatile: + insert_mem_bar(Op_MemBarAcquire); + break; + default: + ShouldNotReachHere(); + } assert(type2size[load_store->bottom_type()->basic_type()] == type2size[rtype], "result type should match"); set_result(load_store); return true; } -//----------------------------inline_unsafe_ordered_store---------------------- -// public native void Unsafe.putOrderedObject(Object o, long offset, Object x); -// public native void Unsafe.putOrderedInt(Object o, long offset, int x); -// public native void Unsafe.putOrderedLong(Object o, long offset, long x); -bool LibraryCallKit::inline_unsafe_ordered_store(BasicType type) { - // This is another variant of inline_unsafe_access, differing in - // that it always issues store-store ("release") barrier and ensures - // store-atomicity (which only matters for "long"). - - if (callee()->is_static()) return false; // caller must have the capability! - -#ifndef PRODUCT - { - ResourceMark rm; - // Check the signatures. - ciSignature* sig = callee()->signature(); -#ifdef ASSERT - BasicType rtype = sig->return_type()->basic_type(); - assert(rtype == T_VOID, "must return void"); - assert(sig->count() == 3, "has 3 arguments"); - assert(sig->type_at(0)->basic_type() == T_OBJECT, "base is object"); - assert(sig->type_at(1)->basic_type() == T_LONG, "offset is long"); -#endif // ASSERT +MemNode::MemOrd LibraryCallKit::access_kind_to_memord_LS(AccessKind kind, bool is_store) { + MemNode::MemOrd mo = MemNode::unset; + switch(kind) { + case Opaque: + case Relaxed: mo = MemNode::unordered; break; + case Acquire: mo = MemNode::acquire; break; + case Release: mo = MemNode::release; break; + case Volatile: mo = is_store ? MemNode::release : MemNode::acquire; break; + default: + ShouldNotReachHere(); } -#endif //PRODUCT + guarantee(mo != MemNode::unset, "Should select memory ordering"); + return mo; +} - C->set_has_unsafe_access(true); // Mark eventual nmethod as "unsafe". - - // Get arguments: - Node* receiver = argument(0); // type: oop - Node* base = argument(1); // type: oop - Node* offset = argument(2); // type: long - Node* val = argument(4); // type: oop, int, or long - - // Null check receiver. - receiver = null_check(receiver); - if (stopped()) { - return true; +MemNode::MemOrd LibraryCallKit::access_kind_to_memord(AccessKind kind) { + MemNode::MemOrd mo = MemNode::unset; + switch(kind) { + case Opaque: + case Relaxed: mo = MemNode::unordered; break; + case Acquire: mo = MemNode::acquire; break; + case Release: mo = MemNode::release; break; + case Volatile: mo = MemNode::seqcst; break; + default: + ShouldNotReachHere(); } - - // Build field offset expression. - assert(Unsafe_field_offset_to_byte_offset(11) == 11, "fieldOffset must be byte-scaled"); - // 32-bit machines ignore the high half of long offsets - offset = ConvL2X(offset); - Node* adr = make_unsafe_address(base, offset); - const TypePtr *adr_type = _gvn.type(adr)->isa_ptr(); - const Type *value_type = Type::get_const_basic_type(type); - Compile::AliasType* alias_type = C->alias_type(adr_type); - - insert_mem_bar(Op_MemBarRelease); - insert_mem_bar(Op_MemBarCPUOrder); - // Ensure that the store is atomic for longs: - const bool require_atomic_access = true; - Node* store; - if (type == T_OBJECT) // reference stores need a store barrier. - store = store_oop_to_unknown(control(), base, adr, adr_type, val, type, MemNode::release); - else { - store = store_to_memory(control(), adr, val, type, adr_type, MemNode::release, require_atomic_access); - } - insert_mem_bar(Op_MemBarCPUOrder); - return true; + guarantee(mo != MemNode::unset, "Should select memory ordering"); + return mo; } bool LibraryCallKit::inline_unsafe_fence(vmIntrinsics::ID id) { diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index 57568819107..8c077f11d5f 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -2417,6 +2417,14 @@ void IdealLoopTree::adjust_loop_exit_prob( PhaseIdealLoop *phase ) { ((bol->in(1)->Opcode() == Op_StorePConditional ) || (bol->in(1)->Opcode() == Op_StoreIConditional ) || (bol->in(1)->Opcode() == Op_StoreLConditional ) || + (bol->in(1)->Opcode() == Op_CompareAndExchangeI ) || + (bol->in(1)->Opcode() == Op_CompareAndExchangeL ) || + (bol->in(1)->Opcode() == Op_CompareAndExchangeP ) || + (bol->in(1)->Opcode() == Op_CompareAndExchangeN ) || + (bol->in(1)->Opcode() == Op_WeakCompareAndSwapI ) || + (bol->in(1)->Opcode() == Op_WeakCompareAndSwapL ) || + (bol->in(1)->Opcode() == Op_WeakCompareAndSwapP ) || + (bol->in(1)->Opcode() == Op_WeakCompareAndSwapN ) || (bol->in(1)->Opcode() == Op_CompareAndSwapI ) || (bol->in(1)->Opcode() == Op_CompareAndSwapL ) || (bol->in(1)->Opcode() == Op_CompareAndSwapP ) || diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index bb18a3da6d8..edb69afb43d 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -2307,6 +2307,14 @@ void Matcher::find_shared( Node *n ) { case Op_StorePConditional: case Op_StoreIConditional: case Op_StoreLConditional: + case Op_CompareAndExchangeI: + case Op_CompareAndExchangeL: + case Op_CompareAndExchangeP: + case Op_CompareAndExchangeN: + case Op_WeakCompareAndSwapI: + case Op_WeakCompareAndSwapL: + case Op_WeakCompareAndSwapP: + case Op_WeakCompareAndSwapN: case Op_CompareAndSwapI: case Op_CompareAndSwapL: case Op_CompareAndSwapP: @@ -2522,6 +2530,14 @@ bool Matcher::post_store_load_barrier(const Node* vmb) { // that a monitor exit operation contains a serializing instruction. if (xop == Op_MemBarVolatile || + xop == Op_CompareAndExchangeI || + xop == Op_CompareAndExchangeL || + xop == Op_CompareAndExchangeP || + xop == Op_CompareAndExchangeN || + xop == Op_WeakCompareAndSwapL || + xop == Op_WeakCompareAndSwapP || + xop == Op_WeakCompareAndSwapN || + xop == Op_WeakCompareAndSwapI || xop == Op_CompareAndSwapL || xop == Op_CompareAndSwapP || xop == Op_CompareAndSwapN || diff --git a/hotspot/src/share/vm/opto/memnode.hpp b/hotspot/src/share/vm/opto/memnode.hpp index 994b782dfbb..8d9cd71bc0a 100644 --- a/hotspot/src/share/vm/opto/memnode.hpp +++ b/hotspot/src/share/vm/opto/memnode.hpp @@ -56,7 +56,9 @@ public: }; typedef enum { unordered = 0, acquire, // Load has to acquire or be succeeded by MemBarAcquire. - release // Store has to release or be preceded by MemBarRelease. + release, // Store has to release or be preceded by MemBarRelease. + seqcst, // LoadStore has to have both acquire and release semantics. + unset // The memory ordering is not set (used for testing) } MemOrd; protected: MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at ) @@ -848,34 +850,121 @@ public: virtual uint ideal_reg() const { return Op_RegFlags; } }; +class CompareAndSwapNode : public LoadStoreConditionalNode { +private: + const MemNode::MemOrd _mem_ord; +public: + CompareAndSwapNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : LoadStoreConditionalNode(c, mem, adr, val, ex), _mem_ord(mem_ord) {} + MemNode::MemOrd order() const { + return _mem_ord; + } +}; + +class CompareAndExchangeNode : public LoadStoreNode { +private: + const MemNode::MemOrd _mem_ord; +public: + enum { + ExpectedIn = MemNode::ValueIn+1 // One more input than MemNode + }; + CompareAndExchangeNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord, const TypePtr* at, const Type* t) : + LoadStoreNode(c, mem, adr, val, at, t, 5), _mem_ord(mem_ord) { + init_req(ExpectedIn, ex ); + } + + MemNode::MemOrd order() const { + return _mem_ord; + } +}; //------------------------------CompareAndSwapLNode--------------------------- -class CompareAndSwapLNode : public LoadStoreConditionalNode { +class CompareAndSwapLNode : public CompareAndSwapNode { public: - CompareAndSwapLNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex) : LoadStoreConditionalNode(c, mem, adr, val, ex) { } + CompareAndSwapLNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } virtual int Opcode() const; }; //------------------------------CompareAndSwapINode--------------------------- -class CompareAndSwapINode : public LoadStoreConditionalNode { +class CompareAndSwapINode : public CompareAndSwapNode { public: - CompareAndSwapINode( Node *c, Node *mem, Node *adr, Node *val, Node *ex) : LoadStoreConditionalNode(c, mem, adr, val, ex) { } + CompareAndSwapINode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } virtual int Opcode() const; }; //------------------------------CompareAndSwapPNode--------------------------- -class CompareAndSwapPNode : public LoadStoreConditionalNode { +class CompareAndSwapPNode : public CompareAndSwapNode { public: - CompareAndSwapPNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex) : LoadStoreConditionalNode(c, mem, adr, val, ex) { } + CompareAndSwapPNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } virtual int Opcode() const; }; //------------------------------CompareAndSwapNNode--------------------------- -class CompareAndSwapNNode : public LoadStoreConditionalNode { +class CompareAndSwapNNode : public CompareAndSwapNode { public: - CompareAndSwapNNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex) : LoadStoreConditionalNode(c, mem, adr, val, ex) { } + CompareAndSwapNNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + + +//------------------------------WeakCompareAndSwapLNode--------------------------- +class WeakCompareAndSwapLNode : public CompareAndSwapNode { +public: + WeakCompareAndSwapLNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + + +//------------------------------WeakCompareAndSwapINode--------------------------- +class WeakCompareAndSwapINode : public CompareAndSwapNode { +public: + WeakCompareAndSwapINode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + + +//------------------------------WeakCompareAndSwapPNode--------------------------- +class WeakCompareAndSwapPNode : public CompareAndSwapNode { +public: + WeakCompareAndSwapPNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + +//------------------------------WeakCompareAndSwapNNode--------------------------- +class WeakCompareAndSwapNNode : public CompareAndSwapNode { +public: + WeakCompareAndSwapNNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + +//------------------------------CompareAndExchangeLNode--------------------------- +class CompareAndExchangeLNode : public CompareAndExchangeNode { +public: + CompareAndExchangeLNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, const TypePtr* at, MemNode::MemOrd mem_ord) : CompareAndExchangeNode(c, mem, adr, val, ex, mem_ord, at, TypeLong::LONG) { } + virtual int Opcode() const; +}; + + +//------------------------------CompareAndExchangeINode--------------------------- +class CompareAndExchangeINode : public CompareAndExchangeNode { +public: + CompareAndExchangeINode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, const TypePtr* at, MemNode::MemOrd mem_ord) : CompareAndExchangeNode(c, mem, adr, val, ex, mem_ord, at, TypeInt::INT) { } + virtual int Opcode() const; +}; + + +//------------------------------CompareAndExchangePNode--------------------------- +class CompareAndExchangePNode : public CompareAndExchangeNode { +public: + CompareAndExchangePNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, const TypePtr* at, const Type* t, MemNode::MemOrd mem_ord) : CompareAndExchangeNode(c, mem, adr, val, ex, mem_ord, at, t) { } + virtual int Opcode() const; +}; + +//------------------------------CompareAndExchangeNNode--------------------------- +class CompareAndExchangeNNode : public CompareAndExchangeNode { +public: + CompareAndExchangeNNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, const TypePtr* at, const Type* t, MemNode::MemOrd mem_ord) : CompareAndExchangeNode(c, mem, adr, val, ex, mem_ord, at, t) { } virtual int Opcode() const; }; diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp index b7900ad276d..b14505d3c4c 100644 --- a/hotspot/src/share/vm/opto/node.hpp +++ b/hotspot/src/share/vm/opto/node.hpp @@ -60,6 +60,8 @@ class CmpNode; class CodeBuffer; class ConstraintCastNode; class ConNode; +class CompareAndSwapNode; +class CompareAndExchangeNode; class CountedLoopNode; class CountedLoopEndNode; class DecodeNarrowPtrNode; @@ -679,6 +681,9 @@ public: DEFINE_CLASS_ID(Store, Mem, 1) DEFINE_CLASS_ID(StoreVector, Store, 0) DEFINE_CLASS_ID(LoadStore, Mem, 2) + DEFINE_CLASS_ID(LoadStoreConditional, LoadStore, 0) + DEFINE_CLASS_ID(CompareAndSwap, LoadStoreConditional, 0) + DEFINE_CLASS_ID(CompareAndExchangeNode, LoadStore, 1) DEFINE_CLASS_ID(Region, Node, 5) DEFINE_CLASS_ID(Loop, Region, 0) diff --git a/hotspot/src/share/vm/prims/unsafe.cpp b/hotspot/src/share/vm/prims/unsafe.cpp index 84d24626a15..cdd4334e229 100644 --- a/hotspot/src/share/vm/prims/unsafe.cpp +++ b/hotspot/src/share/vm/prims/unsafe.cpp @@ -1117,6 +1117,44 @@ UNSAFE_END // JSR166 ------------------------------------------------------------------ +UNSAFE_ENTRY(jobject, Unsafe_CompareAndExchangeObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h)) + UnsafeWrapper("Unsafe_CompareAndExchangeObject"); + oop x = JNIHandles::resolve(x_h); + oop e = JNIHandles::resolve(e_h); + oop p = JNIHandles::resolve(obj); + HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset); + oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e, true); + if (res == e) + update_barrier_set((void*)addr, x); + return JNIHandles::make_local(env, res); +UNSAFE_END + +UNSAFE_ENTRY(jint, Unsafe_CompareAndExchangeInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) + UnsafeWrapper("Unsafe_CompareAndExchangeInt"); + oop p = JNIHandles::resolve(obj); + jint* addr = (jint *) index_oop_from_field_offset_long(p, offset); + return (jint)(Atomic::cmpxchg(x, addr, e)); +UNSAFE_END + +UNSAFE_ENTRY(jlong, Unsafe_CompareAndExchangeLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x)) + UnsafeWrapper("Unsafe_CompareAndExchangeLong"); + Handle p (THREAD, JNIHandles::resolve(obj)); + jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset)); +#ifdef SUPPORTS_NATIVE_CX8 + return (jlong)(Atomic::cmpxchg(x, addr, e)); +#else + if (VM_Version::supports_cx8()) + return (jlong)(Atomic::cmpxchg(x, addr, e)); + else { + MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag); + jlong val = Atomic::load(addr); + if (val == e) + Atomic::store(x, addr); + return val; + } +#endif +UNSAFE_END + UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h)) UnsafeWrapper("Unsafe_CompareAndSwapObject"); oop x = JNIHandles::resolve(x_h); @@ -1384,6 +1422,10 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = { {CC "compareAndSwapObject", CC "(" OBJ "J" OBJ "" OBJ ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, {CC "compareAndSwapInt", CC "(" OBJ "J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)}, {CC "compareAndSwapLong", CC "(" OBJ "J""J""J"")Z", FN_PTR(Unsafe_CompareAndSwapLong)}, + {CC "compareAndExchangeObjectVolatile", CC "(" OBJ "J" OBJ "" OBJ ")" OBJ, FN_PTR(Unsafe_CompareAndExchangeObject)}, + {CC "compareAndExchangeIntVolatile", CC "(" OBJ "J""I""I"")I", FN_PTR(Unsafe_CompareAndExchangeInt)}, + {CC "compareAndExchangeLongVolatile", CC "(" OBJ "J""J""J"")J", FN_PTR(Unsafe_CompareAndExchangeLong)}, + {CC "putOrderedObject", CC "(" OBJ "J" OBJ ")V", FN_PTR(Unsafe_SetOrderedObject)}, {CC "putOrderedInt", CC "(" OBJ "JI)V", FN_PTR(Unsafe_SetOrderedInt)}, {CC "putOrderedLong", CC "(" OBJ "JJ)V", FN_PTR(Unsafe_SetOrderedLong)}, diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 0778abc2f7a..84d2c6ebd3b 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -2005,10 +2005,20 @@ typedef CompactHashtable SymbolCompactHashTable; declare_c2_type(LoadStoreNode, Node) \ declare_c2_type(StorePConditionalNode, LoadStoreNode) \ declare_c2_type(StoreLConditionalNode, LoadStoreNode) \ - declare_c2_type(CompareAndSwapLNode, LoadStoreNode) \ - declare_c2_type(CompareAndSwapINode, LoadStoreNode) \ - declare_c2_type(CompareAndSwapPNode, LoadStoreNode) \ - declare_c2_type(CompareAndSwapNNode, LoadStoreNode) \ + declare_c2_type(CompareAndSwapNode, LoadStoreConditionalNode) \ + declare_c2_type(CompareAndSwapLNode, CompareAndSwapNode) \ + declare_c2_type(CompareAndSwapINode, CompareAndSwapNode) \ + declare_c2_type(CompareAndSwapPNode, CompareAndSwapNode) \ + declare_c2_type(CompareAndSwapNNode, CompareAndSwapNode) \ + declare_c2_type(WeakCompareAndSwapLNode, CompareAndSwapNode) \ + declare_c2_type(WeakCompareAndSwapINode, CompareAndSwapNode) \ + declare_c2_type(WeakCompareAndSwapPNode, CompareAndSwapNode) \ + declare_c2_type(WeakCompareAndSwapNNode, CompareAndSwapNode) \ + declare_c2_type(CompareAndExchangeNode, LoadStoreNode) \ + declare_c2_type(CompareAndExchangeLNode, CompareAndExchangeNode) \ + declare_c2_type(CompareAndExchangeINode, CompareAndExchangeNode) \ + declare_c2_type(CompareAndExchangePNode, CompareAndExchangeNode) \ + declare_c2_type(CompareAndExchangeNNode, CompareAndExchangeNode) \ declare_c2_type(MulNode, Node) \ declare_c2_type(MulINode, MulNode) \ declare_c2_type(MulLNode, MulNode) \ diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java index 1f19d4c14da..f8b82d21549 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java @@ -128,6 +128,20 @@ public class JdkInternalMiscUnsafeAccessTestBoolean { } + // Lazy + { + UNSAFE.putBooleanRelease(base, offset, true); + boolean x = UNSAFE.getBooleanAcquire(base, offset); + assertEquals(x, true, "putRelease boolean value"); + } + + // Opaque + { + UNSAFE.putBooleanOpaque(base, offset, false); + boolean x = UNSAFE.getBooleanOpaque(base, offset); + assertEquals(x, false, "putOpaque boolean value"); + } + } diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java index a3ffa6fb8ab..edc6f9ad859 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestByte { } + // Lazy + { + UNSAFE.putByteRelease(base, offset, (byte)1); + byte x = UNSAFE.getByteAcquire(base, offset); + assertEquals(x, (byte)1, "putRelease byte value"); + } + + // Opaque + { + UNSAFE.putByteOpaque(base, offset, (byte)2); + byte x = UNSAFE.getByteOpaque(base, offset); + assertEquals(x, (byte)2, "putOpaque byte value"); + } + } diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java index b148aee5c8a..b63b1716ffa 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestChar { } + // Lazy + { + UNSAFE.putCharRelease(base, offset, 'a'); + char x = UNSAFE.getCharAcquire(base, offset); + assertEquals(x, 'a', "putRelease char value"); + } + + // Opaque + { + UNSAFE.putCharOpaque(base, offset, 'b'); + char x = UNSAFE.getCharOpaque(base, offset); + assertEquals(x, 'b', "putOpaque char value"); + } + // Unaligned { UNSAFE.putCharUnaligned(base, offset, 'b'); diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java index 3ea637178ac..2309269f473 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestDouble { } + // Lazy + { + UNSAFE.putDoubleRelease(base, offset, 1.0d); + double x = UNSAFE.getDoubleAcquire(base, offset); + assertEquals(x, 1.0d, "putRelease double value"); + } + + // Opaque + { + UNSAFE.putDoubleOpaque(base, offset, 2.0d); + double x = UNSAFE.getDoubleOpaque(base, offset); + assertEquals(x, 2.0d, "putOpaque double value"); + } + } diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java index a2e313620fb..07f537f4c5e 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestFloat { } + // Lazy + { + UNSAFE.putFloatRelease(base, offset, 1.0f); + float x = UNSAFE.getFloatAcquire(base, offset); + assertEquals(x, 1.0f, "putRelease float value"); + } + + // Opaque + { + UNSAFE.putFloatOpaque(base, offset, 2.0f); + float x = UNSAFE.getFloatOpaque(base, offset); + assertEquals(x, 2.0f, "putOpaque float value"); + } + } diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java index 1ea024f1320..0d8bc7e4291 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java @@ -163,6 +163,20 @@ public class JdkInternalMiscUnsafeAccessTestInt { assertEquals(x, 1, "putRelease int value"); } + // Lazy + { + UNSAFE.putIntRelease(base, offset, 1); + int x = UNSAFE.getIntAcquire(base, offset); + assertEquals(x, 1, "putRelease int value"); + } + + // Opaque + { + UNSAFE.putIntOpaque(base, offset, 2); + int x = UNSAFE.getIntOpaque(base, offset); + assertEquals(x, 2, "putOpaque int value"); + } + // Unaligned { UNSAFE.putIntUnaligned(base, offset, 2); @@ -199,6 +213,70 @@ public class JdkInternalMiscUnsafeAccessTestInt { assertEquals(x, 2, "failing compareAndSwap int value"); } + // Advanced compare + { + int r = UNSAFE.compareAndExchangeIntVolatile(base, offset, 2, 1); + assertEquals(r, 2, "success compareAndExchangeVolatile int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "success compareAndExchangeVolatile int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntVolatile(base, offset, 2, 3); + assertEquals(r, 1, "failing compareAndExchangeVolatile int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "failing compareAndExchangeVolatile int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntAcquire(base, offset, 1, 2); + assertEquals(r, 1, "success compareAndExchangeAcquire int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "success compareAndExchangeAcquire int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntAcquire(base, offset, 1, 3); + assertEquals(r, 2, "failing compareAndExchangeAcquire int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "failing compareAndExchangeAcquire int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntRelease(base, offset, 2, 1); + assertEquals(r, 2, "success compareAndExchangeRelease int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "success compareAndExchangeRelease int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntRelease(base, offset, 2, 3); + assertEquals(r, 1, "failing compareAndExchangeRelease int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "failing compareAndExchangeRelease int value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapInt(base, offset, 1, 2); + assertEquals(r, true, "weakCompareAndSwap int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "weakCompareAndSwap int value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapIntAcquire(base, offset, 2, 1); + assertEquals(r, true, "weakCompareAndSwapAcquire int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "weakCompareAndSwapAcquire int"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapIntRelease(base, offset, 1, 2); + assertEquals(r, true, "weakCompareAndSwapRelease int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "weakCompareAndSwapRelease int"); + } + // Compare set and get { int o = UNSAFE.getAndSetInt(base, offset, 1); diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java index 0c5262019b1..4460b4452e4 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java @@ -163,6 +163,20 @@ public class JdkInternalMiscUnsafeAccessTestLong { assertEquals(x, 1L, "putRelease long value"); } + // Lazy + { + UNSAFE.putLongRelease(base, offset, 1L); + long x = UNSAFE.getLongAcquire(base, offset); + assertEquals(x, 1L, "putRelease long value"); + } + + // Opaque + { + UNSAFE.putLongOpaque(base, offset, 2L); + long x = UNSAFE.getLongOpaque(base, offset); + assertEquals(x, 2L, "putOpaque long value"); + } + // Unaligned { UNSAFE.putLongUnaligned(base, offset, 2L); @@ -199,6 +213,70 @@ public class JdkInternalMiscUnsafeAccessTestLong { assertEquals(x, 2L, "failing compareAndSwap long value"); } + // Advanced compare + { + long r = UNSAFE.compareAndExchangeLongVolatile(base, offset, 2L, 1L); + assertEquals(r, 2L, "success compareAndExchangeVolatile long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "success compareAndExchangeVolatile long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongVolatile(base, offset, 2L, 3L); + assertEquals(r, 1L, "failing compareAndExchangeVolatile long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "failing compareAndExchangeVolatile long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongAcquire(base, offset, 1L, 2L); + assertEquals(r, 1L, "success compareAndExchangeAcquire long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "success compareAndExchangeAcquire long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongAcquire(base, offset, 1L, 3L); + assertEquals(r, 2L, "failing compareAndExchangeAcquire long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "failing compareAndExchangeAcquire long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongRelease(base, offset, 2L, 1L); + assertEquals(r, 2L, "success compareAndExchangeRelease long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "success compareAndExchangeRelease long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongRelease(base, offset, 2L, 3L); + assertEquals(r, 1L, "failing compareAndExchangeRelease long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "failing compareAndExchangeRelease long value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapLong(base, offset, 1L, 2L); + assertEquals(r, true, "weakCompareAndSwap long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "weakCompareAndSwap long value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapLongAcquire(base, offset, 2L, 1L); + assertEquals(r, true, "weakCompareAndSwapAcquire long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "weakCompareAndSwapAcquire long"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapLongRelease(base, offset, 1L, 2L); + assertEquals(r, true, "weakCompareAndSwapRelease long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "weakCompareAndSwapRelease long"); + } + // Compare set and get { long o = UNSAFE.getAndSetLong(base, offset, 1L); diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java index c23cffd02ad..98afe49f6fa 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java @@ -134,6 +134,20 @@ public class JdkInternalMiscUnsafeAccessTestObject { assertEquals(x, "foo", "putRelease Object value"); } + // Lazy + { + UNSAFE.putObjectRelease(base, offset, "foo"); + Object x = UNSAFE.getObjectAcquire(base, offset); + assertEquals(x, "foo", "putRelease Object value"); + } + + // Opaque + { + UNSAFE.putObjectOpaque(base, offset, "bar"); + Object x = UNSAFE.getObjectOpaque(base, offset); + assertEquals(x, "bar", "putOpaque Object value"); + } + UNSAFE.putObject(base, offset, "foo"); @@ -152,6 +166,70 @@ public class JdkInternalMiscUnsafeAccessTestObject { assertEquals(x, "bar", "failing compareAndSwap Object value"); } + // Advanced compare + { + Object r = UNSAFE.compareAndExchangeObjectVolatile(base, offset, "bar", "foo"); + assertEquals(r, "bar", "success compareAndExchangeVolatile Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "success compareAndExchangeVolatile Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectVolatile(base, offset, "bar", "baz"); + assertEquals(r, "foo", "failing compareAndExchangeVolatile Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "failing compareAndExchangeVolatile Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectAcquire(base, offset, "foo", "bar"); + assertEquals(r, "foo", "success compareAndExchangeAcquire Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "success compareAndExchangeAcquire Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectAcquire(base, offset, "foo", "baz"); + assertEquals(r, "bar", "failing compareAndExchangeAcquire Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "failing compareAndExchangeAcquire Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectRelease(base, offset, "bar", "foo"); + assertEquals(r, "bar", "success compareAndExchangeRelease Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "success compareAndExchangeRelease Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectRelease(base, offset, "bar", "baz"); + assertEquals(r, "foo", "failing compareAndExchangeRelease Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "failing compareAndExchangeRelease Object value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapObject(base, offset, "foo", "bar"); + assertEquals(r, true, "weakCompareAndSwap Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "weakCompareAndSwap Object value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapObjectAcquire(base, offset, "bar", "foo"); + assertEquals(r, true, "weakCompareAndSwapAcquire Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "weakCompareAndSwapAcquire Object"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapObjectRelease(base, offset, "foo", "bar"); + assertEquals(r, true, "weakCompareAndSwapRelease Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "weakCompareAndSwapRelease Object"); + } + // Compare set and get { Object o = UNSAFE.getAndSetObject(base, offset, "foo"); diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java index 40a20789769..600425dc913 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestShort { } + // Lazy + { + UNSAFE.putShortRelease(base, offset, (short)1); + short x = UNSAFE.getShortAcquire(base, offset); + assertEquals(x, (short)1, "putRelease short value"); + } + + // Opaque + { + UNSAFE.putShortOpaque(base, offset, (short)2); + short x = UNSAFE.getShortOpaque(base, offset); + assertEquals(x, (short)2, "putOpaque short value"); + } + // Unaligned { UNSAFE.putShortUnaligned(base, offset, (short)2); diff --git a/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template b/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template index fcc74e325b0..4553635a158 100644 --- a/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template +++ b/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template @@ -169,6 +169,22 @@ public class $Qualifier$UnsafeAccessTest$Type$ { } #end[Ordered] +#if[JdkInternalMisc] + // Lazy + { + UNSAFE.put$Type$Release(base, offset, $value1$); + $type$ x = UNSAFE.get$Type$Acquire(base, offset); + assertEquals(x, $value1$, "putRelease $type$ value"); + } + + // Opaque + { + UNSAFE.put$Type$Opaque(base, offset, $value2$); + $type$ x = UNSAFE.get$Type$Opaque(base, offset); + assertEquals(x, $value2$, "putOpaque $type$ value"); + } +#end[JdkInternalMisc] + #if[JdkInternalMisc] #if[Unaligned] // Unaligned @@ -210,6 +226,72 @@ public class $Qualifier$UnsafeAccessTest$Type$ { assertEquals(x, $value2$, "failing compareAndSwap $type$ value"); } +#if[JdkInternalMisc] + // Advanced compare + { + $type$ r = UNSAFE.compareAndExchange$Type$Volatile(base, offset, $value2$, $value1$); + assertEquals(r, $value2$, "success compareAndExchangeVolatile $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "success compareAndExchangeVolatile $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Volatile(base, offset, $value2$, $value3$); + assertEquals(r, $value1$, "failing compareAndExchangeVolatile $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "failing compareAndExchangeVolatile $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Acquire(base, offset, $value1$, $value2$); + assertEquals(r, $value1$, "success compareAndExchangeAcquire $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "success compareAndExchangeAcquire $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Acquire(base, offset, $value1$, $value3$); + assertEquals(r, $value2$, "failing compareAndExchangeAcquire $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "failing compareAndExchangeAcquire $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Release(base, offset, $value2$, $value1$); + assertEquals(r, $value2$, "success compareAndExchangeRelease $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "success compareAndExchangeRelease $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Release(base, offset, $value2$, $value3$); + assertEquals(r, $value1$, "failing compareAndExchangeRelease $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "failing compareAndExchangeRelease $type$ value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwap$Type$(base, offset, $value1$, $value2$); + assertEquals(r, true, "weakCompareAndSwap $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "weakCompareAndSwap $type$ value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwap$Type$Acquire(base, offset, $value2$, $value1$); + assertEquals(r, true, "weakCompareAndSwapAcquire $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "weakCompareAndSwapAcquire $type$"); + } + + { + boolean r = UNSAFE.weakCompareAndSwap$Type$Release(base, offset, $value1$, $value2$); + assertEquals(r, true, "weakCompareAndSwapRelease $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "weakCompareAndSwapRelease $type$"); + } +#end[JdkInternalMisc] + // Compare set and get { $type$ o = UNSAFE.getAndSet$Type$(base, offset, $value1$); @@ -244,4 +326,5 @@ public class $Qualifier$UnsafeAccessTest$Type$ { } #end[!boolean] #end[!Object] -} \ No newline at end of file +} + diff --git a/hotspot/test/compiler/unsafe/generate-unsafe-tests.sh b/hotspot/test/compiler/unsafe/generate-unsafe-tests.sh new file mode 100644 index 00000000000..a20c45afa86 --- /dev/null +++ b/hotspot/test/compiler/unsafe/generate-unsafe-tests.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +javac -d . ../../../../jdk/make/src/classes/build/tools/spp/Spp.java + +SPP=build.tools.spp.Spp + +# Generates unsafe access tests for objects and all primitive types +# $1 = package name to Unsafe, sun.misc | jdk.internal.misc +# $2 = test class qualifier name, SunMisc | JdkInternalMisc +function generate { + package=$1 + Qualifier=$2 + + for type in boolean byte short char int long float double Object + do + Type="$(tr '[:lower:]' '[:upper:]' <<< ${type:0:1})${type:1}" + args="-K$type -Dtype=$type -DType=$Type" + + case $type in + Object|int|long) + args="$args -KCAS -KOrdered" + ;; + esac + + case $type in + int|long) + args="$args -KAtomicAdd" + ;; + esac + + case $type in + short|char|int|long) + args="$args -KUnaligned" + ;; + esac + + case $type in + boolean) + value1=true + value2=false + value3=false + ;; + byte) + value1=(byte)1 + value2=(byte)2 + value3=(byte)3 + ;; + short) + value1=(short)1 + value2=(short)2 + value3=(short)3 + ;; + char) + value1=\'a\' + value2=\'b\' + value3=\'c\' + ;; + int) + value1=1 + value2=2 + value3=3 + ;; + long) + value1=1L + value2=2L + value3=3L + ;; + float) + value1=1.0f + value2=2.0f + value3=3.0f + ;; + double) + value1=1.0d + value2=2.0d + value3=3.0d + ;; + Object) + value1=\"foo\" + value2=\"bar\" + value3=\"baz\" + ;; + esac + + args="$args -Dvalue1=$value1 -Dvalue2=$value2 -Dvalue3=$value3" + + echo $args + + java $SPP -nel -K$Qualifier -Dpackage=$package -DQualifier=$Qualifier \ + $args < X-UnsafeAccessTest.java.template > ${Qualifier}UnsafeAccessTest${Type}.java + done +} + +generate sun.misc SunMisc +generate jdk.internal.misc JdkInternalMisc + +rm -fr build \ No newline at end of file From 6e26b67678d236ccbffaa4aabc9348738f3b9438 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 24 Feb 2016 18:43:51 +0300 Subject: [PATCH 020/129] 8150514: C1 crashes in Canonicalizer::do_ArrayLength() after fix for JDK-8150102 Reviewed-by: thartmann, vlivanov --- hotspot/src/share/vm/c1/c1_Canonicalizer.cpp | 5 +- .../compiler/c1/CanonicalizeArrayLength.java | 154 ++++++++++++++++++ 2 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 hotspot/test/compiler/c1/CanonicalizeArrayLength.java diff --git a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp index 48b814531e4..f6e5baa0c28 100644 --- a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp +++ b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp @@ -239,7 +239,10 @@ void Canonicalizer::do_ArrayLength (ArrayLength* x) { } else if ((ct = x->array()->as_Constant()) != NULL) { // Constant arrays have constant lengths. - set_constant(ct->type()->as_ArrayConstant()->value()->length()); + ArrayConstant* cnst = ct->type()->as_ArrayConstant(); + if (cnst != NULL) { + set_constant(cnst->value()->length()); + } #ifdef ASSERT } else { diff --git a/hotspot/test/compiler/c1/CanonicalizeArrayLength.java b/hotspot/test/compiler/c1/CanonicalizeArrayLength.java new file mode 100644 index 00000000000..f8de9e595c9 --- /dev/null +++ b/hotspot/test/compiler/c1/CanonicalizeArrayLength.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8150102 8150514 + * @summary C1 crashes in Canonicalizer::do_ArrayLength() after fix for JDK-8150102 + * @run main/othervm -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation CanonicalizeArrayLength + * + */ + +public class CanonicalizeArrayLength { + int[] arr = new int[42]; + int[] arrNull = null; + + final int[] finalArr = new int[42]; + final int[] finalArrNull = null; + + static int[] staticArr = new int[42]; + static int[] staticArrNull = null; + + static final int[] staticFinalArr = new int[42]; + static final int[] staticFinalArrNull = null; + + public static void main(String... args) { + CanonicalizeArrayLength t = new CanonicalizeArrayLength(); + for (int i = 0; i < 20000; i++) { + if (t.testLocal() != 42) + throw new IllegalStateException(); + if (t.testLocalNull() != 42) + throw new IllegalStateException(); + if (t.testField() != 42) + throw new IllegalStateException(); + if (t.testFieldNull() != 42) + throw new IllegalStateException(); + if (t.testFinalField() != 42) + throw new IllegalStateException(); + if (t.testFinalFieldNull() != 42) + throw new IllegalStateException(); + if (t.testStaticField() != 42) + throw new IllegalStateException(); + if (t.testStaticFieldNull() != 42) + throw new IllegalStateException(); + if (t.testStaticFinalField() != 42) + throw new IllegalStateException(); + if (t.testStaticFinalFieldNull() != 42) + throw new IllegalStateException(); + } + } + + int testField() { + try { + return arr.length; + } catch (Throwable t) { + return -1; + } + } + + int testFieldNull() { + try { + return arrNull.length; + } catch (Throwable t) { + return 42; + } + } + + int testFinalField() { + try { + return finalArr.length; + } catch (Throwable t) { + return -1; + } + } + + int testFinalFieldNull() { + try { + return finalArrNull.length; + } catch (Throwable t) { + return 42; + } + } + + int testStaticField() { + try { + return staticArr.length; + } catch (Throwable t) { + return -1; + } + } + + int testStaticFieldNull() { + try { + return staticArrNull.length; + } catch (Throwable t) { + return 42; + } + } + + int testStaticFinalField() { + try { + return staticFinalArr.length; + } catch (Throwable t) { + return -1; + } + } + + int testStaticFinalFieldNull() { + try { + return staticFinalArrNull.length; + } catch (Throwable t) { + return 42; + } + } + + int testLocal() { + int[] arr = new int[42]; + try { + return arr.length; + } catch (Throwable t) { + return -1; + } + } + + int testLocalNull() { + int[] arrNull = null; + try { + return arrNull.length; + } catch (Throwable t) { + return 42; + } + } + + +} From 52c7cb7221cac7faf2ba195ef24265ce3e4559eb Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Thu, 25 Feb 2016 08:47:57 +0100 Subject: [PATCH 021/129] 8150441: CompileTask::print_impl() is broken after JDK-8146905 Timestamps should be explicitly initialized. Reviewed-by: dholmes --- hotspot/src/share/vm/utilities/vmError.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index ee6ad0e5ddb..2d0942349be 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -1121,6 +1121,10 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt if (first_error_tid == -1 && Atomic::cmpxchg_ptr(mytid, &first_error_tid, -1) == -1) { + // Initialize time stamps to use the same base. + out.time_stamp().update_to(1); + log.time_stamp().update_to(1); + _id = id; _message = message; _thread = thread; From e09bb29c2d6e11a78c8f59d9bf4f594207aa93cb Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Thu, 25 Feb 2016 10:42:42 +0100 Subject: [PATCH 022/129] 8148159: [TESTBUG] TestCompilerDirectivesCompatibility tests fails on non-tiered server VMs Add whitebox for checking available compilers Reviewed-by: kvn --- hotspot/src/share/vm/prims/whitebox.cpp | 10 ++-- ...stCompilerDirectivesCompatibilityBase.java | 51 +++++++++++-------- ...ilerDirectivesCompatibilityCommandOff.java | 39 +++++++------- ...pilerDirectivesCompatibilityCommandOn.java | 39 +++++++------- ...stCompilerDirectivesCompatibilityFlag.java | 39 +++++++------- 5 files changed, 94 insertions(+), 84 deletions(-) diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index 407d7249125..776df026f7d 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -644,12 +644,12 @@ WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobjec return (mh->queued_for_compilation() || nm != NULL); WB_END -WB_ENTRY(jboolean, WB_ShouldPrintAssembly(JNIEnv* env, jobject o, jobject method)) +WB_ENTRY(jboolean, WB_ShouldPrintAssembly(JNIEnv* env, jobject o, jobject method, jint comp_level)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION_(env, JNI_FALSE); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - DirectiveSet* directive = DirectivesStack::getMatchingDirective(mh, CompileBroker::compiler(CompLevel_simple)); + DirectiveSet* directive = DirectivesStack::getMatchingDirective(mh, CompileBroker::compiler(comp_level)); bool result = directive->PrintAssemblyOption; DirectivesStack::release(directive); @@ -1556,8 +1556,8 @@ static JNINativeMethod methods[] = { #endif // INCLUDE_NMT {CC"deoptimizeFrames", CC"(Z)I", (void*)&WB_DeoptimizeFrames }, {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, - {CC"deoptimizeMethod0", CC"(Ljava/lang/reflect/Executable;Z)I", - (void*)&WB_DeoptimizeMethod }, + {CC"deoptimizeMethod0", CC"(Ljava/lang/reflect/Executable;Z)I", + (void*)&WB_DeoptimizeMethod }, {CC"isMethodCompiled0", CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_IsMethodCompiled }, {CC"isMethodCompilable0", CC"(Ljava/lang/reflect/Executable;IZ)Z", @@ -1592,7 +1592,7 @@ static JNINativeMethod methods[] = { CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)I", (void*)&WB_MatchesInline}, {CC"shouldPrintAssembly", - CC"(Ljava/lang/reflect/Executable;)Z", + CC"(Ljava/lang/reflect/Executable;I)Z", (void*)&WB_ShouldPrintAssembly}, {CC"isConstantVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsConstantVMFlag}, diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java index 283003afde6..ff5f70eceaa 100644 --- a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java @@ -24,25 +24,26 @@ /* * @test TestCompilerDirectivesCompatibilityBase * @bug 8137167 - * @library /testlibrary /test/lib + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @build sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityBase + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityBase * @summary Test compiler control compatibility with compile command */ +import compiler.testlibrary.CompilerUtils; +import compiler.whitebox.CompilerWhiteBoxTest; import jdk.test.lib.dcmd.CommandExecutor; import jdk.test.lib.dcmd.JMXExecutor; - import org.testng.annotations.Test; import org.testng.Assert; - import sun.hotspot.WhiteBox; import java.io.BufferedReader; @@ -64,32 +65,38 @@ public class TestCompilerDirectivesCompatibilityBase { method = getMethod(TestCompilerDirectivesCompatibilityBase.class, "helper"); nomatch = getMethod(TestCompilerDirectivesCompatibilityBase.class, "another"); - testCompatibility(executor); + int[] levels = CompilerUtils.getAvailableCompilationLevels(); + for (int complevel : levels) { + // Only test the major compilers, ignore profiling levels + if (complevel == CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE || complevel == CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION){ + testCompatibility(executor, complevel); + } + } } - public void testCompatibility(CommandExecutor executor) throws Exception { + public void testCompatibility(CommandExecutor executor, int comp_level) throws Exception { // Call all validation twice to catch error when overwriting a directive // Flag is default off expect(!WB.getBooleanVMFlag("PrintAssembly")); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); // load directives that turn it on executor.execute("Compiler.directives_add " + control_on); - expect(WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); // remove and see that it is true again executor.execute("Compiler.directives_remove"); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); } public void expect(boolean test) throws Exception { diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java index a2922c8a2d9..661b06036c0 100644 --- a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java @@ -24,16 +24,17 @@ /* * @test TestCompilerDirectivesCompatibilityCommandOff * @bug 8137167 - * @library /testlibrary /test/lib + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @build sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions * -XX:-PrintAssembly -XX:CompileCommand=option,*.helper,bool,PrintAssembly,false * -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityCommandOff * @summary Test compiler control compatibility with compile command @@ -55,27 +56,27 @@ import java.util.Objects; public class TestCompilerDirectivesCompatibilityCommandOff extends TestCompilerDirectivesCompatibilityBase { - public void testCompatibility(CommandExecutor executor) throws Exception { + public void testCompatibility(CommandExecutor executor, int comp_level) throws Exception { // Call all validation twice to catch error when overwriting a directive // Flag is default off - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); // load directives that turn it on executor.execute("Compiler.directives_add " + control_on); - expect(WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); // remove and see that it is false again executor.execute("Compiler.directives_remove"); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); } } diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java index 0123c282b11..8fd0eec6d53 100644 --- a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java @@ -24,16 +24,17 @@ /* * @test TestCompilerDirectivesCompatibilityCommandOn * @bug 8137167 - * @library /testlibrary /test/lib + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @build sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions * -XX:-PrintAssembly -XX:CompileCommand=print,*.* -XX:+WhiteBoxAPI * TestCompilerDirectivesCompatibilityCommandOn * @summary Test compiler control compatibility with compile command @@ -55,27 +56,27 @@ import java.util.Objects; public class TestCompilerDirectivesCompatibilityCommandOn extends TestCompilerDirectivesCompatibilityBase{ - public void testCompatibility(CommandExecutor executor) throws Exception { + public void testCompatibility(CommandExecutor executor, int comp_level) throws Exception { // Call all validation twice to catch error when overwriting a directive // Flag is default on - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); // load directives that turn it off executor.execute("Compiler.directives_add " + control_off); - expect(!WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); // remove and see that it is true again executor.execute("Compiler.directives_remove"); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); } } diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java index 37c8d2b0181..8ec1fc9ee4e 100644 --- a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java @@ -24,16 +24,17 @@ /* * @test TestCompilerDirectivesCompatibilityFlag * @bug 8137167 - * @library /testlibrary /test/lib + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @build sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions * -XX:+PrintAssembly -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityFlag * @summary Test compiler control compatibility with compile command */ @@ -54,28 +55,28 @@ import java.util.Objects; public class TestCompilerDirectivesCompatibilityFlag extends TestCompilerDirectivesCompatibilityBase { - public void testCompatibility(CommandExecutor executor) throws Exception { + public void testCompatibility(CommandExecutor executor, int comp_level) throws Exception { // Call all validation twice to catch error when overwriting a directive // Flag is default on expect(WB.getBooleanVMFlag("PrintAssembly")); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); // load directives that turn it off executor.execute("Compiler.directives_add " + control_off); - expect(!WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); // remove and see that it is true again executor.execute("Compiler.directives_remove"); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); } } From 607365df56d16257ed9df05ad3a8a72cfe4cba53 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Thu, 25 Feb 2016 10:44:19 +0100 Subject: [PATCH 023/129] 8149789: SIGSEGV in CompileTask::print Print tasks from active compile threads requires safepoint Reviewed-by: kvn --- hotspot/src/share/vm/compiler/compileBroker.cpp | 1 - hotspot/src/share/vm/runtime/vm_operations.cpp | 4 ++++ hotspot/src/share/vm/runtime/vm_operations.hpp | 12 ++++++++++++ hotspot/src/share/vm/services/diagnosticCommand.cpp | 3 ++- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 44903801d83..8689088455c 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -469,7 +469,6 @@ CompileQueue* CompileBroker::compile_queue(int comp_level) { void CompileBroker::print_compile_queues(outputStream* st) { st->print_cr("Current compiles: "); MutexLocker locker(MethodCompileQueue_lock); - MutexLocker locker2(Threads_lock); char buf[2000]; int buflen = sizeof(buf); diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp index 80def983a56..db7341d869f 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.cpp +++ b/hotspot/src/share/vm/runtime/vm_operations.cpp @@ -485,6 +485,10 @@ void VM_Exit::wait_if_vm_exited() { } } +void VM_PrintCompileQueue::doit() { + CompileBroker::print_compile_queues(_out); +} + #if INCLUDE_SERVICES void VM_PrintClassHierarchy::doit() { KlassHierarchy::print_class_hierarchy(_out, _print_interfaces, _print_subclasses, _classname); diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index 03392091aee..a5b0ddbf47b 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -105,6 +105,7 @@ template(DumpHashtable) \ template(DumpTouchedMethods) \ template(MarkActiveNMethods) \ + template(PrintCompileQueue) \ template(PrintClassHierarchy) \ class VM_Operation: public CHeapObj { @@ -421,6 +422,17 @@ class VM_Exit: public VM_Operation { void doit(); }; +class VM_PrintCompileQueue: public VM_Operation { + private: + outputStream* _out; + + public: + VM_PrintCompileQueue(outputStream* st) : _out(st) {} + VMOp_Type type() const { return VMOp_PrintCompileQueue; } + Mode evaluation_mode() const { return _safepoint; } + void doit(); +}; + #if INCLUDE_SERVICES class VM_PrintClassHierarchy: public VM_Operation { private: diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index d6dde5eef83..c634edfce73 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -832,7 +832,8 @@ void VMDynamicLibrariesDCmd::execute(DCmdSource source, TRAPS) { } void CompileQueueDCmd::execute(DCmdSource source, TRAPS) { - CompileBroker::print_compile_queues(output()); + VM_PrintCompileQueue printCompileQueueOp(output()); + VMThread::execute(&printCompileQueueOp); } void CodeListDCmd::execute(DCmdSource source, TRAPS) { From d596cf06af037f78f9099876d7558ba2f7bb0252 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Thu, 25 Feb 2016 10:44:51 +0100 Subject: [PATCH 024/129] 8069160: serviceability/dcmd/compiler/CompilerQueueTest.java fails due to class not found Use whitebox to test specific cases making test less fragile Reviewed-by: kvn --- .../dcmd/compiler/CompilerQueueTest.java | 155 ++++++++++++------ 1 file changed, 108 insertions(+), 47 deletions(-) diff --git a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java index fac5034f984..321be8257f5 100644 --- a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java +++ b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java @@ -24,25 +24,33 @@ /* * @test CompilerQueueTest * @bug 8054889 - * @library /testlibrary + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * jdk.jvmstat/sun.jvmstat.monitor - * @ignore 8069160 * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @run testng CompilerQueueTest - * @run testng/othervm -XX:-TieredCompilation CompilerQueueTest - * @run testng/othervm -Xint CompilerQueueTest + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -Xmixed -XX:+WhiteBoxAPI CompilerQueueTest + * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -Xmixed -XX:-TieredCompilation -XX:+WhiteBoxAPI CompilerQueueTest + * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -Xint -XX:+WhiteBoxAPI CompilerQueueTest * @summary Test of diagnostic command Compiler.queue */ +import compiler.testlibrary.CompilerUtils; import jdk.test.lib.OutputAnalyzer; import jdk.test.lib.dcmd.CommandExecutor; import jdk.test.lib.dcmd.JMXExecutor; import org.testng.annotations.Test; +import org.testng.Assert; +import sun.hotspot.WhiteBox; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; import java.util.Iterator; public class CompilerQueueTest { @@ -54,70 +62,123 @@ public class CompilerQueueTest { * * Output example: * - * Contents of C1 compile queue - * ---------------------------- - * 73 3 java.lang.AbstractStringBuilder::append (50 bytes) - * 74 1 java.util.TreeMap::size (5 bytes) - * 75 3 java.lang.StringBuilder::append (8 bytes) - * 83 3 java.util.TreeMap$ValueIterator::next (8 bytes) - * 84 1 javax.management.MBeanFeatureInfo::getName (5 bytes) - * ---------------------------- - * Contents of C2 compile queue - * ---------------------------- + * Current compiles: + * C1 CompilerThread14 267 3 java.net.URLStreamHandler::parseURL (1166 bytes) + * C1 CompilerThread13 760 3 javax.management.StandardMBean::getDescription (11 bytes) + * C1 CompilerThread12 757 s 3 com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory::getMapping (27 bytes) + * C1 CompilerThread11 756 s! 3 com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory::mappingForType (110 bytes) + * C1 CompilerThread10 761 3 java.lang.StringLatin1::indexOf (121 bytes) + * C2 CompilerThread7 769 4 CompilerQueueTest::testcaseMethod4 (1 bytes) + * + * C1 compile queue: + * 762 3 java.lang.invoke.MethodType::basicType (8 bytes) + * 763 3 java.util.ArrayList::rangeCheck (22 bytes) + * 764 3 java.util.ArrayList::elementData (7 bytes) + * 765 3 jdk.internal.org.objectweb.asm.MethodVisitor:: (35 bytes) + * 766 1 CompilerQueueTest::testcaseMethod1 (1 bytes) + * 767 2 CompilerQueueTest::testcaseMethod2 (1 bytes) + * 768 3 CompilerQueueTest::testcaseMethod3 (1 bytes) + * 770 3 java.util.Properties::getProperty (46 bytes) + * + * C2 compile queue: * Empty - * ---------------------------- * **/ + protected static final WhiteBox WB = WhiteBox.getWhiteBox(); + public void run(CommandExecutor executor) { + TestCase[] testcases = { + new TestCase(1, "testcaseMethod1"), + new TestCase(2, "testcaseMethod2"), + new TestCase(3, "testcaseMethod3"), + new TestCase(4, "testcaseMethod4"), + }; + + // Lock compilation makes all compiles stay in queue or compile thread before completion + WB.lockCompilation(); + + // Enqueue one test method for each available level + int[] complevels = CompilerUtils.getAvailableCompilationLevels(); + for (int level : complevels) { + TestCase testcase = testcases[level - 1]; + + boolean added = WB.enqueueMethodForCompilation(testcase.method, testcase.level); + // Set results to false for those methods we must to find + // We will also assert if we find any test method we don't expect + Assert.assertTrue(WB.isMethodQueuedForCompilation(testcase.method)); + testcase.check = false; + } + // Get output from dcmd (diagnostic command) OutputAnalyzer output = executor.execute("Compiler.queue"); Iterator lines = output.asLines().iterator(); + // Loop over output set result for all found methods while (lines.hasNext()) { String str = lines.next(); - if (str.startsWith("Contents of C")) { - match(lines.next(), "----------------------------"); - str = lines.next(); - if (!str.equals("Empty")) { - while (str.charAt(0) != '-') { - validateMethodLine(str); - str = lines.next(); + // Fast check for common part of method name + if (str.contains("testcaseMethod")) { + for (TestCase testcase : testcases) { + if (str.contains(testcase.methodName)) { + Assert.assertFalse(testcase.check, "Must not be found or already found."); + testcase.check = true; } - } else { - str = lines.next(); } - match(str,"----------------------------"); - } else { - Assert.fail("Failed parsing dcmd queue, line: " + str); } } - } - private static void validateMethodLine(String str) { - // Skip until package/class name begins. Trim to remove whitespace that - // may differ. - String name = str.substring(14).trim(); - int sep = name.indexOf("::"); - if (sep == -1) { - Assert.fail("Failed dcmd queue, didn't find separator :: in: " + name); + for (TestCase testcase : testcases) { + if (!testcase.check) { + // If this method wasn't found it must have been removed by policy, + // verify that it is now removed from the queue + Assert.assertFalse(WB.isMethodQueuedForCompilation(testcase.method), "Must be found or not in queue"); + } + // Otherwise all good. } - try { - Class.forName(name.substring(0, sep)); - } catch (ClassNotFoundException e) { - Assert.fail("Failed dcmd queue, Class for name: " + str); - } - } - public static void match(String line, String str) { - if (!line.equals(str)) { - Assert.fail("String equals: " + line + ", " + str); - } + // Enable compilations again + WB.unlockCompilation(); } @Test public void jmx() { run(new JMXExecutor()); } + + public void testcaseMethod1() { + } + + public void testcaseMethod2() { + } + + public void testcaseMethod3() { + } + + public void testcaseMethod4() { + } + + public static Method getMethod(Class klass, String name, Class... parameterTypes) { + try { + return klass.getDeclaredMethod(name, parameterTypes); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException("exception on getting method Helper." + name, e); + } + } + + class TestCase { + Method method; + int level; + String methodName; + Boolean check; + + public TestCase(int level, String methodName) { + this.method = getMethod(CompilerQueueTest.class, methodName); + this.level = level; + this.methodName = methodName; + this.check = true; + } + } + } From 4a8c4fc0740251d8f753ee97c6bc2aaae2965eef Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 25 Feb 2016 15:10:16 +0300 Subject: [PATCH 025/129] 8150534: C1 compilation fails with "Constant field loads are folded during parsing" Reviewed-by: vlivanov, thartmann --- hotspot/src/share/vm/c1/c1_Canonicalizer.cpp | 16 ++++++++++------ .../compiler/c1/CanonicalizeArrayLength.java | 7 ++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp index f6e5baa0c28..033beb0d25e 100644 --- a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp +++ b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp @@ -224,6 +224,7 @@ void Canonicalizer::do_StoreField (StoreField* x) { void Canonicalizer::do_ArrayLength (ArrayLength* x) { NewArray* na; Constant* ct; + LoadField* lf; if ((na = x->array()->as_NewArray()) != NULL) { // New arrays might have the known length. @@ -244,12 +245,15 @@ void Canonicalizer::do_ArrayLength (ArrayLength* x) { set_constant(cnst->value()->length()); } -#ifdef ASSERT - } else { - LoadField* lf = x->array()->as_LoadField(); - bool is_static_constant = (lf != NULL) && lf->field()->is_constant() && lf->field()->is_static(); - assert(!is_static_constant, "Constant field loads are folded during parsing"); -#endif // ASSERT + } else if ((lf = x->array()->as_LoadField()) != NULL) { + ciField* field = lf->field(); + if (field->is_constant() && field->is_static()) { + assert(PatchALot || ScavengeRootsInCode < 2, "Constant field loads are folded during parsing"); + ciObject* c = field->constant_value().as_object(); + if (!c->is_null_object()) { + set_constant(c->as_array()->length()); + } + } } } diff --git a/hotspot/test/compiler/c1/CanonicalizeArrayLength.java b/hotspot/test/compiler/c1/CanonicalizeArrayLength.java index f8de9e595c9..9971d25bde8 100644 --- a/hotspot/test/compiler/c1/CanonicalizeArrayLength.java +++ b/hotspot/test/compiler/c1/CanonicalizeArrayLength.java @@ -23,12 +23,13 @@ /* * @test - * @bug 8150102 8150514 + * @bug 8150102 8150514 8150534 * @summary C1 crashes in Canonicalizer::do_ArrayLength() after fix for JDK-8150102 * @run main/othervm -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation CanonicalizeArrayLength - * + * @run main/othervm -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:+PatchALot CanonicalizeArrayLength + * @run main/othervm -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:ScavengeRootsInCode=0 CanonicalizeArrayLength + * @run main/othervm -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:ScavengeRootsInCode=1 CanonicalizeArrayLength */ - public class CanonicalizeArrayLength { int[] arr = new int[42]; int[] arrNull = null; From 88575c5de777893560d39060bc5e65725b2f1487 Mon Sep 17 00:00:00 2001 From: Christian Thalinger Date: Wed, 24 Feb 2016 09:22:45 -0800 Subject: [PATCH 026/129] 8150561: [AArch64] JVMCI improvements Reviewed-by: kvn --- hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp | 2 +- hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp | 7 +++++++ .../src/jdk/vm/ci/hotspot/HotSpotVMConfig.java | 7 ++----- hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp | 8 ++++++++ hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp | 8 ++++++++ hotspot/src/share/vm/runtime/frame.cpp | 4 ++-- 6 files changed, 28 insertions(+), 8 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp index 3e65f538de5..b302548557b 100644 --- a/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp @@ -74,7 +74,7 @@ void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, T void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, TRAPS) { address pc = _instructions->start() + pc_offset; NativeInstruction* inst = nativeInstruction_at(pc); - if (inst->is_adr_aligned()) { + if (inst->is_adr_aligned() || inst->is_ldr_literal()) { address dest = _constants->start() + data_offset; _instructions->relocate(pc, section_word_Relocation::spec((address) dest, CodeBuffer::SECT_CONSTS)); TRACE_jvmci_3("relocating at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset); diff --git a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp index 72c3479659c..d83017c1770 100644 --- a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp @@ -105,13 +105,20 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC { inline friend NativeInstruction* nativeInstruction_at(address address); static bool is_adrp_at(address instr); + static bool is_ldr_literal_at(address instr); + + bool is_ldr_literal() { + return is_ldr_literal_at(addr_at(0)); + } + static bool is_ldrw_to_zr(address instr); static bool is_call_at(address instr) { const uint32_t insn = (*(uint32_t*)instr); return (insn >> 26) == 0b100101; } + bool is_call() { return is_call_at(addr_at(0)); } diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 3e90a4d73b0..88da9e5b32a 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -1141,7 +1141,7 @@ public class HotSpotVMConfig { @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_sp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET) @Stable private int javaFrameAnchorLastJavaSpOffset; @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_pc", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable private int javaFrameAnchorLastJavaPcOffset; - @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_fp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET, archs = {"amd64"}) @Stable private int javaFrameAnchorLastJavaFpOffset; + @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_fp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET, archs = {"aarch64, amd64"}) @Stable private int javaFrameAnchorLastJavaFpOffset; @HotSpotVMField(name = "JavaFrameAnchor::_flags", type = "int", get = HotSpotVMField.Type.OFFSET, archs = {"sparc"}) @Stable private int javaFrameAnchorFlagsOffset; public int threadLastJavaSpOffset() { @@ -1152,11 +1152,8 @@ public class HotSpotVMConfig { return javaThreadAnchorOffset + javaFrameAnchorLastJavaPcOffset; } - /** - * This value is only valid on AMD64. - */ public int threadLastJavaFpOffset() { - // TODO add an assert for AMD64 + assert getHostArchitectureName().equals("aarch64") || getHostArchitectureName().equals("amd64"); return javaThreadAnchorOffset + javaFrameAnchorLastJavaFpOffset; } diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp index cb06c34d4b6..2043b59d5e1 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp @@ -551,6 +551,14 @@ JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Hand compiler, _debug_recorder, _dependencies, env, id, has_unsafe_access, _has_wide_vector, installed_code, compiled_code, speculation_log); cb = nm; + if (nm != NULL && env == NULL) { + DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, compiler); + bool printnmethods = directive->PrintAssemblyOption || directive->PrintNMethodsOption; + if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) { + nm->print_nmethod(printnmethods); + } + DirectivesStack::release(directive); + } } if (cb != NULL) { diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp index 9456f34a0eb..99a7fbd3ac9 100644 --- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp +++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp @@ -592,6 +592,14 @@ #endif // TARGET_OS_FAMILY_bsd +#ifdef TARGET_ARCH_aarch64 + +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) + +#endif // TARGET_ARCH_aarch64 + + #ifdef TARGET_ARCH_x86 #define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ diff --git a/hotspot/src/share/vm/runtime/frame.cpp b/hotspot/src/share/vm/runtime/frame.cpp index 3abf884cfbb..1a72cec46a8 100644 --- a/hotspot/src/share/vm/runtime/frame.cpp +++ b/hotspot/src/share/vm/runtime/frame.cpp @@ -662,14 +662,14 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose st->print("J %d%s %s ", nm->compile_id(), (nm->is_osr_method() ? "%" : ""), ((nm->compiler() != NULL) ? nm->compiler()->name() : "")); + st->print("%s (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+" INTPTR_FORMAT "]", + buf, m->code_size(), p2i(_pc), p2i(_cb->code_begin()), _pc - _cb->code_begin()); #if INCLUDE_JVMCI char* jvmciName = nm->jvmci_installed_code_name(buf, buflen); if (jvmciName != NULL) { st->print(" (%s)", jvmciName); } #endif - st->print("%s (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+" INTPTR_FORMAT "]", - buf, m->code_size(), p2i(_pc), p2i(_cb->code_begin()), _pc - _cb->code_begin()); } else { st->print("J " PTR_FORMAT, p2i(pc())); } From abebc2da5c26b42098d9bd95d9a7d790916183ab Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 26 Feb 2016 01:58:26 +0300 Subject: [PATCH 027/129] 8150186: Folding mismatched accesses with @Stable is incorrect Reviewed-by: kvn, jrose, shade --- hotspot/src/share/vm/ci/ciArray.cpp | 3 +- hotspot/src/share/vm/opto/memnode.cpp | 14 +++- .../unsafe/UnsafeGetStableArrayElement.java | 68 +++++++++++++++++++ 3 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java diff --git a/hotspot/src/share/vm/ci/ciArray.cpp b/hotspot/src/share/vm/ci/ciArray.cpp index f527d3ed538..04a6db8df3f 100644 --- a/hotspot/src/share/vm/ci/ciArray.cpp +++ b/hotspot/src/share/vm/ci/ciArray.cpp @@ -107,8 +107,9 @@ ciConstant ciArray::element_value_by_offset(intptr_t element_offset) { intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt); intptr_t index = (element_offset - header) >> shift; intptr_t offset = header + ((intptr_t)index << shift); - if (offset != element_offset || index != (jint)index) + if (offset != element_offset || index != (jint)index || index < 0 || index >= length()) { return ciConstant(); + } return element_value((jint) index); } diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 75a699349f8..55ca4581485 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -1582,6 +1582,15 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls, return NULL; } +static bool is_mismatched_access(ciConstant con, BasicType loadbt) { + BasicType conbt = con.basic_type(); + assert(conbt != T_NARROWOOP, "sanity"); + if (loadbt == T_NARROWOOP || loadbt == T_ARRAY) { + loadbt = T_OBJECT; + } + return (conbt != loadbt); +} + // Try to constant-fold a stable array element. static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) { assert(ary->const_oop(), "array should be constant"); @@ -1590,8 +1599,7 @@ static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicTyp // Decode the results of GraphKit::array_element_address. ciArray* aobj = ary->const_oop()->as_array(); ciConstant con = aobj->element_value_by_offset(off); - - if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) { + if (con.basic_type() != T_ILLEGAL && !is_mismatched_access(con, loadbt) && !con.is_null_or_zero()) { const Type* con_type = Type::make_from_constant(con); if (con_type != NULL) { if (con_type->isa_aryptr()) { @@ -1642,7 +1650,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { const bool off_beyond_header = ((uint)off >= (uint)min_base_off); // Try to constant-fold a stable array element. - if (FoldStableValues && ary->is_stable() && ary->const_oop() != NULL) { + if (FoldStableValues && !is_mismatched_access() && ary->is_stable() && ary->const_oop() != NULL) { // Make sure the reference is not into the header and the offset is constant if (off_beyond_header && adr->is_AddP() && off != Type::OffsetBot) { const Type* con_type = fold_stable_ary_elem(ary, off, memory_type()); diff --git a/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java new file mode 100644 index 00000000000..afdb1a6e7a3 --- /dev/null +++ b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary tests on constant folding of unsafe get operations + * @library /testlibrary /test/lib + * + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions + * -Xbatch -XX:-TieredCompilation + * -XX:+FoldStableValues + * UnsafeGetStableArrayElement + * + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions + * -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+FoldStableValues + * UnsafeGetStableArrayElement + */ +import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.Stable; +import java.util.concurrent.Callable; + +import static jdk.internal.misc.Unsafe.*; +import static jdk.test.lib.Asserts.*; + +public class UnsafeGetStableArrayElement { + @Stable static final byte[] STABLE_BYTE_ARRAY = new byte[] { 0, 1, -128, 127}; + + static final Unsafe U = Unsafe.getUnsafe(); + + static int testChar() { + return U.getChar(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET + 0 * ARRAY_CHAR_INDEX_SCALE) + + U.getChar(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET + 1 * ARRAY_CHAR_INDEX_SCALE); + } + + static void run(Callable c) throws Exception { + Object first = c.call(); + for (int i = 0; i < 20_000; i++) { + assertEQ(first, c.call()); + } + } + + public static void main(String[] args) throws Exception { + run(UnsafeGetStableArrayElement::testChar); + } +} From a7d78599d772bff1a3b24c179370a55bec9a1f63 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 26 Feb 2016 01:58:29 +0300 Subject: [PATCH 028/129] 8150436: Incorrect invocation mode when linkToInteface linker is eliminated Reviewed-by: kvn, shade --- .../src/share/vm/runtime/sharedRuntime.cpp | 19 +++++++++++++------ .../jsr292/NonInlinedCall/InvokeTest.java | 5 ++++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index 5b862a01fab..4adec0c45ca 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -1134,12 +1134,19 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread, MethodHandles::is_signature_polymorphic_intrinsic(id)) { bc = MethodHandles::signature_polymorphic_intrinsic_bytecode(id); - // Need to adjust invokehandle since inlining through signature-polymorphic - // method happened. - if (bc == Bytecodes::_invokehandle && - !MethodHandles::is_signature_polymorphic_method(attached_method())) { - bc = attached_method->is_static() ? Bytecodes::_invokestatic - : Bytecodes::_invokevirtual; + // Adjust invocation mode according to the attached method. + switch (bc) { + case Bytecodes::_invokeinterface: + if (!attached_method->method_holder()->is_interface()) { + bc = Bytecodes::_invokevirtual; + } + break; + case Bytecodes::_invokehandle: + if (!MethodHandles::is_signature_polymorphic_method(attached_method())) { + bc = attached_method->is_static() ? Bytecodes::_invokestatic + : Bytecodes::_invokevirtual; + } + break; } } } else { diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java index 02bdef91a10..90724b371a8 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java @@ -180,7 +180,10 @@ public class InvokeTest { static void testInterface() { System.out.println("linkToInterface"); - // Monomorphic case (optimized virtual call) + // Monomorphic case (optimized virtual call), concrete target method + run(() -> linkToInterface(new P1(), P1.class)); + + // Monomorphic case (optimized virtual call), default target method run(() -> linkToInterface(new T(), I.class)); // Megamorphic case (virtual call) From 782e6b33f2d63d73b14021f46fb36fdc218abed5 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 26 Feb 2016 15:54:55 +0300 Subject: [PATCH 029/129] 8068038: C2: large constant offsets aren't handled on SPARC Reviewed-by: kvn --- hotspot/src/cpu/sparc/vm/sparc.ad | 368 ++++++++++++++---------------- 1 file changed, 175 insertions(+), 193 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 6bbef4e5708..5cf884a5501 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -948,28 +948,28 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, PhaseRegAlloc* ra, const MachNode* n, } #endif - uint instr; - instr = (Assembler::ldst_op << 30) - | (dst_enc << 25) - | (primary << 19) - | (src1_enc << 14); + uint instr = (Assembler::ldst_op << 30) + | (dst_enc << 25) + | (primary << 19) + | (src1_enc << 14); uint index = src2_enc; int disp = disp32; if (src1_enc == R_SP_enc || src1_enc == R_FP_enc) { disp += STACK_BIAS; - // Quick fix for JDK-8029668: check that stack offset fits, bailout if not + // Check that stack offset fits, load into O7 if not if (!Assembler::is_simm13(disp)) { - ra->C->record_method_not_compilable("unable to handle large constant offsets"); - return; + MacroAssembler _masm(&cbuf); + __ set(disp, O7); + if (index != R_G0_enc) { + __ add(O7, reg_to_register_object(index), O7); + } + index = R_O7_enc; + disp = 0; } } - // We should have a compiler bailout here rather than a guarantee. - // Better yet would be some mechanism to handle variable-size matches correctly. - guarantee(Assembler::is_simm13(disp), "Do not match large constant offsets" ); - if( disp == 0 ) { // use reg-reg form // bit 13 is already zero @@ -983,7 +983,7 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, PhaseRegAlloc* ra, const MachNode* n, cbuf.insts()->emit_int32(instr); #ifdef ASSERT - { + if (VerifyOops) { MacroAssembler _masm(&cbuf); if (is_verified_oop_base) { __ verify_oop(reg_to_register_object(src1_enc)); @@ -1342,7 +1342,7 @@ int MachEpilogNode::safepoint_offset() const { // Figure out which register class each belongs in: rc_int, rc_float, rc_stack enum RC { rc_bad, rc_int, rc_float, rc_stack }; static enum RC rc_class( OptoReg::Name reg ) { - if( !OptoReg::is_valid(reg) ) return rc_bad; + if (!OptoReg::is_valid(reg)) return rc_bad; if (OptoReg::is_stack(reg)) return rc_stack; VMReg r = OptoReg::as_VMReg(reg); if (r->is_Register()) return rc_int; @@ -1350,66 +1350,79 @@ static enum RC rc_class( OptoReg::Name reg ) { return rc_float; } -static int impl_helper(const MachNode* mach, CodeBuffer* cbuf, PhaseRegAlloc* ra, bool do_size, bool is_load, int offset, int reg, int opcode, const char *op_str, int size, outputStream* st ) { +#ifndef PRODUCT +ATTRIBUTE_PRINTF(2, 3) +static void print_helper(outputStream* st, const char* format, ...) { + if (st->position() > 0) { + st->cr(); + st->sp(); + } + va_list ap; + va_start(ap, format); + st->vprint(format, ap); + va_end(ap); +} +#endif // !PRODUCT + +static void impl_helper(const MachNode* mach, CodeBuffer* cbuf, PhaseRegAlloc* ra, bool is_load, int offset, int reg, int opcode, const char *op_str, outputStream* st) { if (cbuf) { emit_form3_mem_reg(*cbuf, ra, mach, opcode, -1, R_SP_enc, offset, 0, Matcher::_regEncode[reg]); } #ifndef PRODUCT - else if (!do_size) { - if (size != 0) st->print("\n\t"); - if (is_load) st->print("%s [R_SP + #%d],R_%s\t! spill",op_str,offset,OptoReg::regname(reg)); - else st->print("%s R_%s,[R_SP + #%d]\t! spill",op_str,OptoReg::regname(reg),offset); + else { + if (is_load) { + print_helper(st, "%s [R_SP + #%d],R_%s\t! spill", op_str, offset, OptoReg::regname(reg)); + } else { + print_helper(st, "%s R_%s,[R_SP + #%d]\t! spill", op_str, OptoReg::regname(reg), offset); + } } #endif - return size+4; } -static int impl_mov_helper( CodeBuffer *cbuf, bool do_size, int src, int dst, int op1, int op2, const char *op_str, int size, outputStream* st ) { - if( cbuf ) emit3( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst], op1, 0, op2, Matcher::_regEncode[src] ); +static void impl_mov_helper(CodeBuffer *cbuf, int src, int dst, int op1, int op2, const char *op_str, outputStream* st) { + if (cbuf) { + emit3(*cbuf, Assembler::arith_op, Matcher::_regEncode[dst], op1, 0, op2, Matcher::_regEncode[src]); + } #ifndef PRODUCT - else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); - st->print("%s R_%s,R_%s\t! spill",op_str,OptoReg::regname(src),OptoReg::regname(dst)); + else { + print_helper(st, "%s R_%s,R_%s\t! spill", op_str, OptoReg::regname(src), OptoReg::regname(dst)); } #endif - return size+4; } -uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, - PhaseRegAlloc *ra_, - bool do_size, - outputStream* st ) const { +static void mach_spill_copy_implementation_helper(const MachNode* mach, + CodeBuffer *cbuf, + PhaseRegAlloc *ra_, + outputStream* st) { // Get registers to move - OptoReg::Name src_second = ra_->get_reg_second(in(1)); - OptoReg::Name src_first = ra_->get_reg_first(in(1)); - OptoReg::Name dst_second = ra_->get_reg_second(this ); - OptoReg::Name dst_first = ra_->get_reg_first(this ); + OptoReg::Name src_second = ra_->get_reg_second(mach->in(1)); + OptoReg::Name src_first = ra_->get_reg_first(mach->in(1)); + OptoReg::Name dst_second = ra_->get_reg_second(mach); + OptoReg::Name dst_first = ra_->get_reg_first(mach); enum RC src_second_rc = rc_class(src_second); - enum RC src_first_rc = rc_class(src_first); + enum RC src_first_rc = rc_class(src_first); enum RC dst_second_rc = rc_class(dst_second); - enum RC dst_first_rc = rc_class(dst_first); + enum RC dst_first_rc = rc_class(dst_first); - assert( OptoReg::is_valid(src_first) && OptoReg::is_valid(dst_first), "must move at least 1 register" ); + assert(OptoReg::is_valid(src_first) && OptoReg::is_valid(dst_first), "must move at least 1 register"); - // Generate spill code! - int size = 0; - - if( src_first == dst_first && src_second == dst_second ) - return size; // Self copy, no move + if (src_first == dst_first && src_second == dst_second) { + return; // Self copy, no move + } // -------------------------------------- // Check for mem-mem move. Load into unused float registers and fall into // the float-store case. - if( src_first_rc == rc_stack && dst_first_rc == rc_stack ) { + if (src_first_rc == rc_stack && dst_first_rc == rc_stack) { int offset = ra_->reg2offset(src_first); // Further check for aligned-adjacent pair, so we can use a double load - if( (src_first&1)==0 && src_first+1 == src_second ) { + if ((src_first&1) == 0 && src_first+1 == src_second) { src_second = OptoReg::Name(R_F31_num); src_second_rc = rc_float; - size = impl_helper(this,cbuf,ra_,do_size,true,offset,R_F30_num,Assembler::lddf_op3,"LDDF",size, st); + impl_helper(mach, cbuf, ra_, true, offset, R_F30_num, Assembler::lddf_op3, "LDDF", st); } else { - size = impl_helper(this,cbuf,ra_,do_size,true,offset,R_F30_num,Assembler::ldf_op3 ,"LDF ",size, st); + impl_helper(mach, cbuf, ra_, true, offset, R_F30_num, Assembler::ldf_op3, "LDF ", st); } src_first = OptoReg::Name(R_F30_num); src_first_rc = rc_float; @@ -1417,7 +1430,7 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, if( src_second_rc == rc_stack && dst_second_rc == rc_stack ) { int offset = ra_->reg2offset(src_second); - size = impl_helper(this,cbuf,ra_,do_size,true,offset,R_F31_num,Assembler::ldf_op3,"LDF ",size, st); + impl_helper(mach, cbuf, ra_, true, offset, R_F31_num, Assembler::ldf_op3, "LDF ", st); src_second = OptoReg::Name(R_F31_num); src_second_rc = rc_float; } @@ -1427,36 +1440,38 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, if (src_first_rc == rc_float && dst_first_rc == rc_int && UseVIS < 3) { int offset = frame::register_save_words*wordSize; if (cbuf) { - emit3_simm13( *cbuf, Assembler::arith_op, R_SP_enc, Assembler::sub_op3, R_SP_enc, 16 ); - impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stf_op3 ,"STF ",size, st); - impl_helper(this,cbuf,ra_,do_size,true ,offset,dst_first,Assembler::lduw_op3,"LDUW",size, st); - emit3_simm13( *cbuf, Assembler::arith_op, R_SP_enc, Assembler::add_op3, R_SP_enc, 16 ); + emit3_simm13(*cbuf, Assembler::arith_op, R_SP_enc, Assembler::sub_op3, R_SP_enc, 16); + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st); + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st); + emit3_simm13(*cbuf, Assembler::arith_op, R_SP_enc, Assembler::add_op3, R_SP_enc, 16); } #ifndef PRODUCT - else if (!do_size) { - if (size != 0) st->print("\n\t"); - st->print( "SUB R_SP,16,R_SP\n"); - impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stf_op3 ,"STF ",size, st); - impl_helper(this,cbuf,ra_,do_size,true ,offset,dst_first,Assembler::lduw_op3,"LDUW",size, st); - st->print("\tADD R_SP,16,R_SP\n"); + else { + print_helper(st, "SUB R_SP,16,R_SP"); + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st); + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st); + print_helper(st, "ADD R_SP,16,R_SP"); } #endif - size += 16; } // Check for float->int copy on T4 if (src_first_rc == rc_float && dst_first_rc == rc_int && UseVIS >= 3) { // Further check for aligned-adjacent pair, so we can use a double move - if ((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second) - return impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mdtox_opf,"MOVDTOX",size, st); - size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mstouw_opf,"MOVSTOUW",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mdtox_opf, "MOVDTOX", st); + return; + } + impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mstouw_opf, "MOVSTOUW", st); } // Check for int->float copy on T4 if (src_first_rc == rc_int && dst_first_rc == rc_float && UseVIS >= 3) { // Further check for aligned-adjacent pair, so we can use a double move - if ((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second) - return impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mxtod_opf,"MOVXTOD",size, st); - size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mwtos_opf,"MOVWTOS",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mxtod_opf, "MOVXTOD", st); + return; + } + impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mwtos_opf, "MOVWTOS", st); } // -------------------------------------- @@ -1466,10 +1481,10 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, // there. Misaligned sources only come from native-long-returns (handled // special below). #ifndef _LP64 - if( src_first_rc == rc_int && // source is already big-endian + if (src_first_rc == rc_int && // source is already big-endian src_second_rc != rc_bad && // 64-bit move - ((dst_first&1)!=0 || dst_second != dst_first+1) ) { // misaligned dst - assert( (src_first&1)==0 && src_second == src_first+1, "source must be aligned" ); + ((dst_first & 1) != 0 || dst_second != dst_first + 1)) { // misaligned dst + assert((src_first & 1) == 0 && src_second == src_first + 1, "source must be aligned"); // Do the big-endian flop. OptoReg::Name tmp = dst_first ; dst_first = dst_second ; dst_second = tmp ; enum RC tmp_rc = dst_first_rc; dst_first_rc = dst_second_rc; dst_second_rc = tmp_rc; @@ -1478,30 +1493,28 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, // -------------------------------------- // Check for integer reg-reg copy - if( src_first_rc == rc_int && dst_first_rc == rc_int ) { + if (src_first_rc == rc_int && dst_first_rc == rc_int) { #ifndef _LP64 - if( src_first == R_O0_num && src_second == R_O1_num ) { // Check for the evil O0/O1 native long-return case + if (src_first == R_O0_num && src_second == R_O1_num) { // Check for the evil O0/O1 native long-return case // Note: The _first and _second suffixes refer to the addresses of the the 2 halves of the 64-bit value // as stored in memory. On a big-endian machine like SPARC, this means that the _second // operand contains the least significant word of the 64-bit value and vice versa. OptoReg::Name tmp = OptoReg::Name(R_O7_num); - assert( (dst_first&1)==0 && dst_second == dst_first+1, "return a native O0/O1 long to an aligned-adjacent 64-bit reg" ); + assert((dst_first & 1) == 0 && dst_second == dst_first + 1, "return a native O0/O1 long to an aligned-adjacent 64-bit reg" ); // Shift O0 left in-place, zero-extend O1, then OR them into the dst - if( cbuf ) { - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[tmp], Assembler::sllx_op3, Matcher::_regEncode[src_first], 0x1020 ); - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[src_second], Assembler::srl_op3, Matcher::_regEncode[src_second], 0x0000 ); - emit3 ( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst_first], Assembler:: or_op3, Matcher::_regEncode[tmp], 0, Matcher::_regEncode[src_second] ); + if ( cbuf ) { + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[tmp], Assembler::sllx_op3, Matcher::_regEncode[src_first], 0x1020); + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[src_second], Assembler::srl_op3, Matcher::_regEncode[src_second], 0x0000); + emit3 (*cbuf, Assembler::arith_op, Matcher::_regEncode[dst_first], Assembler:: or_op3, Matcher::_regEncode[tmp], 0, Matcher::_regEncode[src_second]); #ifndef PRODUCT - } else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); - st->print("SLLX R_%s,32,R_%s\t! Move O0-first to O7-high\n\t", OptoReg::regname(src_first), OptoReg::regname(tmp)); - st->print("SRL R_%s, 0,R_%s\t! Zero-extend O1\n\t", OptoReg::regname(src_second), OptoReg::regname(src_second)); - st->print("OR R_%s,R_%s,R_%s\t! spill",OptoReg::regname(tmp), OptoReg::regname(src_second), OptoReg::regname(dst_first)); + } else { + print_helper(st, "SLLX R_%s,32,R_%s\t! Move O0-first to O7-high\n\t", OptoReg::regname(src_first), OptoReg::regname(tmp)); + print_helper(st, "SRL R_%s, 0,R_%s\t! Zero-extend O1\n\t", OptoReg::regname(src_second), OptoReg::regname(src_second)); + print_helper(st, "OR R_%s,R_%s,R_%s\t! spill",OptoReg::regname(tmp), OptoReg::regname(src_second), OptoReg::regname(dst_first)); #endif } - return size+12; - } - else if( dst_first == R_I0_num && dst_second == R_I1_num ) { + return; + } else if (dst_first == R_I0_num && dst_second == R_I1_num) { // returning a long value in I0/I1 // a SpillCopy must be able to target a return instruction's reg_class // Note: The _first and _second suffixes refer to the addresses of the the 2 halves of the 64-bit value @@ -1511,27 +1524,25 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, if (src_first == dst_first) { tdest = OptoReg::Name(R_O7_num); - size += 4; } - if( cbuf ) { - assert( (src_first&1) == 0 && (src_first+1) == src_second, "return value was in an aligned-adjacent 64-bit reg"); + if (cbuf) { + assert((src_first & 1) == 0 && (src_first + 1) == src_second, "return value was in an aligned-adjacent 64-bit reg"); // Shift value in upper 32-bits of src to lower 32-bits of I0; move lower 32-bits to I1 // ShrL_reg_imm6 - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[tdest], Assembler::srlx_op3, Matcher::_regEncode[src_second], 32 | 0x1000 ); + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[tdest], Assembler::srlx_op3, Matcher::_regEncode[src_second], 32 | 0x1000); // ShrR_reg_imm6 src, 0, dst - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst_second], Assembler::srl_op3, Matcher::_regEncode[src_first], 0x0000 ); + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[dst_second], Assembler::srl_op3, Matcher::_regEncode[src_first], 0x0000); if (tdest != dst_first) { - emit3 ( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst_first], Assembler::or_op3, 0/*G0*/, 0/*op2*/, Matcher::_regEncode[tdest] ); + emit3 (*cbuf, Assembler::arith_op, Matcher::_regEncode[dst_first], Assembler::or_op3, 0/*G0*/, 0/*op2*/, Matcher::_regEncode[tdest]); } } #ifndef PRODUCT - else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); // %%%%% !!!!! - st->print("SRLX R_%s,32,R_%s\t! Extract MSW\n\t",OptoReg::regname(src_second),OptoReg::regname(tdest)); - st->print("SRL R_%s, 0,R_%s\t! Extract LSW\n\t",OptoReg::regname(src_first),OptoReg::regname(dst_second)); + else { + print_helper(st, "SRLX R_%s,32,R_%s\t! Extract MSW\n\t",OptoReg::regname(src_second),OptoReg::regname(tdest)); + print_helper(st, "SRL R_%s, 0,R_%s\t! Extract LSW\n\t",OptoReg::regname(src_first),OptoReg::regname(dst_second)); if (tdest != dst_first) { - st->print("MOV R_%s,R_%s\t! spill\n\t", OptoReg::regname(tdest), OptoReg::regname(dst_first)); + print_helper(st, "MOV R_%s,R_%s\t! spill\n\t", OptoReg::regname(tdest), OptoReg::regname(dst_first)); } } #endif // PRODUCT @@ -1539,65 +1550,77 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, } #endif // !_LP64 // Else normal reg-reg copy - assert( src_second != dst_first, "smashed second before evacuating it" ); - size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::or_op3,0,"MOV ",size, st); - assert( (src_first&1) == 0 && (dst_first&1) == 0, "never move second-halves of int registers" ); + assert(src_second != dst_first, "smashed second before evacuating it"); + impl_mov_helper(cbuf, src_first, dst_first, Assembler::or_op3, 0, "MOV ", st); + assert((src_first & 1) == 0 && (dst_first & 1) == 0, "never move second-halves of int registers"); // This moves an aligned adjacent pair. // See if we are done. - if( src_first+1 == src_second && dst_first+1 == dst_second ) - return size; + if (src_first + 1 == src_second && dst_first + 1 == dst_second) { + return; + } } // Check for integer store - if( src_first_rc == rc_int && dst_first_rc == rc_stack ) { + if (src_first_rc == rc_int && dst_first_rc == rc_stack) { int offset = ra_->reg2offset(dst_first); // Further check for aligned-adjacent pair, so we can use a double store - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stx_op3,"STX ",size, st); - size = impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stw_op3,"STW ",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stx_op3, "STX ", st); + return; + } + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stw_op3, "STW ", st); } // Check for integer load - if( dst_first_rc == rc_int && src_first_rc == rc_stack ) { + if (dst_first_rc == rc_int && src_first_rc == rc_stack) { int offset = ra_->reg2offset(src_first); // Further check for aligned-adjacent pair, so we can use a double load - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_helper(this,cbuf,ra_,do_size,true,offset,dst_first,Assembler::ldx_op3 ,"LDX ",size, st); - size = impl_helper(this,cbuf,ra_,do_size,true,offset,dst_first,Assembler::lduw_op3,"LDUW",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::ldx_op3, "LDX ", st); + return; + } + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st); } // Check for float reg-reg copy - if( src_first_rc == rc_float && dst_first_rc == rc_float ) { + if (src_first_rc == rc_float && dst_first_rc == rc_float) { // Further check for aligned-adjacent pair, so we can use a double move - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::fpop1_op3,Assembler::fmovd_opf,"FMOVD",size, st); - size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::fpop1_op3,Assembler::fmovs_opf,"FMOVS",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_mov_helper(cbuf, src_first, dst_first, Assembler::fpop1_op3, Assembler::fmovd_opf, "FMOVD", st); + return; + } + impl_mov_helper(cbuf, src_first, dst_first, Assembler::fpop1_op3, Assembler::fmovs_opf, "FMOVS", st); } // Check for float store - if( src_first_rc == rc_float && dst_first_rc == rc_stack ) { + if (src_first_rc == rc_float && dst_first_rc == rc_stack) { int offset = ra_->reg2offset(dst_first); // Further check for aligned-adjacent pair, so we can use a double store - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stdf_op3,"STDF",size, st); - size = impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stf_op3 ,"STF ",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stdf_op3, "STDF", st); + return; + } + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st); } // Check for float load - if( dst_first_rc == rc_float && src_first_rc == rc_stack ) { + if (dst_first_rc == rc_float && src_first_rc == rc_stack) { int offset = ra_->reg2offset(src_first); // Further check for aligned-adjacent pair, so we can use a double load - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_helper(this,cbuf,ra_,do_size,true,offset,dst_first,Assembler::lddf_op3,"LDDF",size, st); - size = impl_helper(this,cbuf,ra_,do_size,true,offset,dst_first,Assembler::ldf_op3 ,"LDF ",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lddf_op3, "LDDF", st); + return; + } + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::ldf_op3, "LDF ", st); } // -------------------------------------------------------------------- // Check for hi bits still needing moving. Only happens for misaligned // arguments to native calls. - if( src_second == dst_second ) - return size; // Self copy; no move - assert( src_second_rc != rc_bad && dst_second_rc != rc_bad, "src_second & dst_second cannot be Bad" ); + if (src_second == dst_second) { + return; // Self copy; no move + } + assert(src_second_rc != rc_bad && dst_second_rc != rc_bad, "src_second & dst_second cannot be Bad"); #ifndef _LP64 // In the LP64 build, all registers can be moved as aligned/adjacent @@ -1609,52 +1632,57 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, // 32-bits of a 64-bit register, but are needed in low bits of another // register (else it's a hi-bits-to-hi-bits copy which should have // happened already as part of a 64-bit move) - if( src_second_rc == rc_int && dst_second_rc == rc_int ) { - assert( (src_second&1)==1, "its the evil O0/O1 native return case" ); - assert( (dst_second&1)==0, "should have moved with 1 64-bit move" ); + if (src_second_rc == rc_int && dst_second_rc == rc_int) { + assert((src_second & 1) == 1, "its the evil O0/O1 native return case"); + assert((dst_second & 1) == 0, "should have moved with 1 64-bit move"); // Shift src_second down to dst_second's low bits. - if( cbuf ) { - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst_second], Assembler::srlx_op3, Matcher::_regEncode[src_second-1], 0x1020 ); + if (cbuf) { + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[dst_second], Assembler::srlx_op3, Matcher::_regEncode[src_second-1], 0x1020); #ifndef PRODUCT - } else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); - st->print("SRLX R_%s,32,R_%s\t! spill: Move high bits down low",OptoReg::regname(src_second-1),OptoReg::regname(dst_second)); + } else { + print_helper(st, "SRLX R_%s,32,R_%s\t! spill: Move high bits down low", OptoReg::regname(src_second - 1), OptoReg::regname(dst_second)); #endif } - return size+4; + return; } // Check for high word integer store. Must down-shift the hi bits // into a temp register, then fall into the case of storing int bits. - if( src_second_rc == rc_int && dst_second_rc == rc_stack && (src_second&1)==1 ) { + if (src_second_rc == rc_int && dst_second_rc == rc_stack && (src_second & 1) == 1) { // Shift src_second down to dst_second's low bits. - if( cbuf ) { - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[R_O7_num], Assembler::srlx_op3, Matcher::_regEncode[src_second-1], 0x1020 ); + if (cbuf) { + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[R_O7_num], Assembler::srlx_op3, Matcher::_regEncode[src_second-1], 0x1020); #ifndef PRODUCT - } else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); - st->print("SRLX R_%s,32,R_%s\t! spill: Move high bits down low",OptoReg::regname(src_second-1),OptoReg::regname(R_O7_num)); + } else { + print_helper(st, "SRLX R_%s,32,R_%s\t! spill: Move high bits down low", OptoReg::regname(src_second-1), OptoReg::regname(R_O7_num)); #endif } - size+=4; src_second = OptoReg::Name(R_O7_num); // Not R_O7H_num! } // Check for high word integer load - if( dst_second_rc == rc_int && src_second_rc == rc_stack ) - return impl_helper(this,cbuf,ra_,do_size,true ,ra_->reg2offset(src_second),dst_second,Assembler::lduw_op3,"LDUW",size, st); + if (dst_second_rc == rc_int && src_second_rc == rc_stack) + return impl_helper(this, cbuf, ra_, true, ra_->reg2offset(src_second), dst_second, Assembler::lduw_op3, "LDUW", size, st); // Check for high word integer store - if( src_second_rc == rc_int && dst_second_rc == rc_stack ) - return impl_helper(this,cbuf,ra_,do_size,false,ra_->reg2offset(dst_second),src_second,Assembler::stw_op3 ,"STW ",size, st); + if (src_second_rc == rc_int && dst_second_rc == rc_stack) + return impl_helper(this, cbuf, ra_, false, ra_->reg2offset(dst_second), src_second, Assembler::stw_op3, "STW ", size, st); // Check for high word float store - if( src_second_rc == rc_float && dst_second_rc == rc_stack ) - return impl_helper(this,cbuf,ra_,do_size,false,ra_->reg2offset(dst_second),src_second,Assembler::stf_op3 ,"STF ",size, st); + if (src_second_rc == rc_float && dst_second_rc == rc_stack) + return impl_helper(this, cbuf, ra_, false, ra_->reg2offset(dst_second), src_second, Assembler::stf_op3, "STF ", size, st); #endif // !_LP64 Unimplemented(); +} + +uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, + PhaseRegAlloc *ra_, + bool do_size, + outputStream* st) const { + assert(!do_size, "not supported"); + mach_spill_copy_implementation_helper(this, cbuf, ra_, st); return 0; } @@ -1669,19 +1697,19 @@ void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { } uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { - return implementation( NULL, ra_, true, NULL ); + return MachNode::size(ra_); } //============================================================================= #ifndef PRODUCT -void MachNopNode::format( PhaseRegAlloc *, outputStream *st ) const { +void MachNopNode::format(PhaseRegAlloc *, outputStream *st) const { st->print("NOP \t# %d bytes pad for loops and calls", 4 * _count); } #endif -void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc * ) const { +void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *) const { MacroAssembler _masm(&cbuf); - for(int i = 0; i < _count; i += 1) { + for (int i = 0; i < _count; i += 1) { __ nop(); } } @@ -5197,7 +5225,6 @@ instruct stkI_to_regF(regF dst, stackSlotI src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDF $src,$dst\t! stkI to regF" %} opcode(Assembler::ldf_op3); ins_encode(simple_form3_mem_reg(src, dst)); @@ -5208,7 +5235,6 @@ instruct stkL_to_regD(regD dst, stackSlotL src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDDF $src,$dst\t! stkL to regD" %} opcode(Assembler::lddf_op3); ins_encode(simple_form3_mem_reg(src, dst)); @@ -5219,7 +5245,6 @@ instruct regF_to_stkI(stackSlotI dst, regF src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STF $src,$dst\t! regF to stkI" %} opcode(Assembler::stf_op3); ins_encode(simple_form3_mem_reg(dst, src)); @@ -5230,7 +5255,6 @@ instruct regD_to_stkL(stackSlotL dst, regD src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STDF $src,$dst\t! regD to stkL" %} opcode(Assembler::stdf_op3); ins_encode(simple_form3_mem_reg(dst, src)); @@ -5240,7 +5264,6 @@ instruct regD_to_stkL(stackSlotL dst, regD src) %{ instruct regI_to_stkLHi(stackSlotL dst, iRegI src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST*2); - size(8); format %{ "STW $src,$dst.hi\t! long\n\t" "STW R_G0,$dst.lo" %} opcode(Assembler::stw_op3); @@ -5252,7 +5275,6 @@ instruct regL_to_stkD(stackSlotD dst, iRegL src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$dst\t! regL to stkD" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -5266,7 +5288,6 @@ instruct stkI_to_regI( iRegI dst, stackSlotI src ) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDUW $src,$dst\t!stk" %} opcode(Assembler::lduw_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -5278,7 +5299,6 @@ instruct regI_to_stkI( stackSlotI dst, iRegI src ) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$dst\t!stk" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -5290,7 +5310,6 @@ instruct stkL_to_regL( iRegL dst, stackSlotL src ) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDX $src,$dst\t! long" %} opcode(Assembler::ldx_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -5302,7 +5321,6 @@ instruct regL_to_stkL(stackSlotL dst, iRegL src) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$dst\t! long" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -5314,7 +5332,6 @@ instruct regL_to_stkL(stackSlotL dst, iRegL src) %{ instruct stkP_to_regP( iRegP dst, stackSlotP src ) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDX $src,$dst\t!ptr" %} opcode(Assembler::ldx_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -5325,7 +5342,6 @@ instruct stkP_to_regP( iRegP dst, stackSlotP src ) %{ instruct regP_to_stkP(stackSlotP dst, iRegP src) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$dst\t!ptr" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -5771,7 +5787,6 @@ instruct loadL_unaligned(iRegL dst, memory mem, o7RegI tmp) %{ match(Set dst (LoadL_unaligned mem)); effect(KILL tmp); ins_cost(MEMORY_REF_COST*2+DEFAULT_COST); - size(16); format %{ "LDUW $mem+4,R_O7\t! misaligned long\n" "\tLDUW $mem ,$dst\n" "\tSLLX #32, $dst, $dst\n" @@ -5786,7 +5801,6 @@ instruct loadRange(iRegI dst, memory mem) %{ match(Set dst (LoadRange mem)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDUW $mem,$dst\t! range" %} opcode(Assembler::lduw_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); @@ -5797,7 +5811,6 @@ instruct loadRange(iRegI dst, memory mem) %{ instruct loadI_freg(regF dst, memory mem) %{ match(Set dst (LoadI mem)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDF $mem,$dst\t! for fitos/fitod" %} opcode(Assembler::ldf_op3); @@ -5876,7 +5889,6 @@ instruct loadD(regD dst, memory mem) %{ match(Set dst (LoadD mem)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDDF $mem,$dst" %} opcode(Assembler::lddf_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); @@ -5887,7 +5899,6 @@ instruct loadD(regD dst, memory mem) %{ instruct loadD_unaligned(regD_low dst, memory mem ) %{ match(Set dst (LoadD_unaligned mem)); ins_cost(MEMORY_REF_COST*2+DEFAULT_COST); - size(8); format %{ "LDF $mem ,$dst.hi\t! misaligned double\n" "\tLDF $mem+4,$dst.lo\t!" %} opcode(Assembler::ldf_op3); @@ -5900,7 +5911,6 @@ instruct loadF(regF dst, memory mem) %{ match(Set dst (LoadF mem)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDF $mem,$dst" %} opcode(Assembler::ldf_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); @@ -6119,7 +6129,6 @@ instruct prefetchAlloc( memory mem ) %{ predicate(AllocatePrefetchInstr == 0); match( PrefetchAllocation mem ); ins_cost(MEMORY_REF_COST); - size(4); format %{ "PREFETCH $mem,2\t! Prefetch allocation" %} opcode(Assembler::prefetch_op3); @@ -6175,7 +6184,6 @@ instruct storeB(memory mem, iRegI src) %{ match(Set mem (StoreB mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STB $src,$mem\t! byte" %} opcode(Assembler::stb_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6186,7 +6194,6 @@ instruct storeB0(memory mem, immI0 src) %{ match(Set mem (StoreB mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STB $src,$mem\t! byte" %} opcode(Assembler::stb_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6197,7 +6204,6 @@ instruct storeCM0(memory mem, immI0 src) %{ match(Set mem (StoreCM mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STB $src,$mem\t! CMS card-mark byte 0" %} opcode(Assembler::stb_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6209,7 +6215,6 @@ instruct storeC(memory mem, iRegI src) %{ match(Set mem (StoreC mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STH $src,$mem\t! short" %} opcode(Assembler::sth_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6220,7 +6225,6 @@ instruct storeC0(memory mem, immI0 src) %{ match(Set mem (StoreC mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STH $src,$mem\t! short" %} opcode(Assembler::sth_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6232,7 +6236,6 @@ instruct storeI(memory mem, iRegI src) %{ match(Set mem (StoreI mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$mem" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6243,7 +6246,6 @@ instruct storeI(memory mem, iRegI src) %{ instruct storeL(memory mem, iRegL src) %{ match(Set mem (StoreL mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$mem\t! long" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6254,7 +6256,6 @@ instruct storeI0(memory mem, immI0 src) %{ match(Set mem (StoreI mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$mem" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6265,7 +6266,6 @@ instruct storeL0(memory mem, immL0 src) %{ match(Set mem (StoreL mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$mem" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6277,7 +6277,6 @@ instruct storeI_Freg(memory mem, regF src) %{ match(Set mem (StoreI mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STF $src,$mem\t! after fstoi/fdtoi" %} opcode(Assembler::stf_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6288,7 +6287,6 @@ instruct storeI_Freg(memory mem, regF src) %{ instruct storeP(memory dst, sp_ptr_RegP src) %{ match(Set dst (StoreP dst src)); ins_cost(MEMORY_REF_COST); - size(4); #ifndef _LP64 format %{ "STW $src,$dst\t! ptr" %} @@ -6304,7 +6302,6 @@ instruct storeP(memory dst, sp_ptr_RegP src) %{ instruct storeP0(memory dst, immP0 src) %{ match(Set dst (StoreP dst src)); ins_cost(MEMORY_REF_COST); - size(4); #ifndef _LP64 format %{ "STW $src,$dst\t! ptr" %} @@ -6379,7 +6376,6 @@ instruct storeD( memory mem, regD src) %{ match(Set mem (StoreD mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STDF $src,$mem" %} opcode(Assembler::stdf_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6390,7 +6386,6 @@ instruct storeD0( memory mem, immD0 src) %{ match(Set mem (StoreD mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$mem" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6402,7 +6397,6 @@ instruct storeF( memory mem, regF src) %{ match(Set mem (StoreF mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STF $src,$mem" %} opcode(Assembler::stf_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6413,7 +6407,6 @@ instruct storeF0( memory mem, immF0 src) %{ match(Set mem (StoreF mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$mem\t! storeF0" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -7068,7 +7061,6 @@ instruct loadPLocked(iRegP dst, memory mem) %{ ins_cost(MEMORY_REF_COST); #ifndef _LP64 - size(4); format %{ "LDUW $mem,$dst\t! ptr" %} opcode(Assembler::lduw_op3, 0, REGP_OP); #else @@ -8138,7 +8130,6 @@ instruct MoveF2I_stack_reg(iRegI dst, stackSlotF src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDUW $src,$dst\t! MoveF2I" %} opcode(Assembler::lduw_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -8150,7 +8141,6 @@ instruct MoveI2F_stack_reg(regF dst, stackSlotI src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDF $src,$dst\t! MoveI2F" %} opcode(Assembler::ldf_op3); ins_encode(simple_form3_mem_reg(src, dst)); @@ -8162,7 +8152,6 @@ instruct MoveD2L_stack_reg(iRegL dst, stackSlotD src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDX $src,$dst\t! MoveD2L" %} opcode(Assembler::ldx_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -8174,7 +8163,6 @@ instruct MoveL2D_stack_reg(regD dst, stackSlotL src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDDF $src,$dst\t! MoveL2D" %} opcode(Assembler::lddf_op3); ins_encode(simple_form3_mem_reg(src, dst)); @@ -8186,7 +8174,6 @@ instruct MoveF2I_reg_stack(stackSlotI dst, regF src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STF $src,$dst\t! MoveF2I" %} opcode(Assembler::stf_op3); ins_encode(simple_form3_mem_reg(dst, src)); @@ -8198,7 +8185,6 @@ instruct MoveI2F_reg_stack(stackSlotF dst, iRegI src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$dst\t! MoveI2F" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -8210,7 +8196,6 @@ instruct MoveD2L_reg_stack(stackSlotL dst, regD src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STDF $src,$dst\t! MoveD2L" %} opcode(Assembler::stdf_op3); ins_encode(simple_form3_mem_reg(dst, src)); @@ -8222,7 +8207,6 @@ instruct MoveL2D_reg_stack(stackSlotD dst, iRegL src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$dst\t! MoveL2D" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -8427,7 +8411,6 @@ instruct convI2D_reg(regD_low dst, iRegI src) %{ instruct convI2D_mem(regD_low dst, memory mem) %{ match(Set dst (ConvI2D (LoadI mem))); ins_cost(DEFAULT_COST + MEMORY_REF_COST); - size(8); format %{ "LDF $mem,$dst\n\t" "FITOD $dst,$dst" %} opcode(Assembler::ldf_op3, Assembler::fitod_opf); @@ -8468,7 +8451,6 @@ instruct convI2F_reg(regF dst, iRegI src) %{ instruct convI2F_mem( regF dst, memory mem ) %{ match(Set dst (ConvI2F (LoadI mem))); ins_cost(DEFAULT_COST + MEMORY_REF_COST); - size(8); format %{ "LDF $mem,$dst\n\t" "FITOS $dst,$dst" %} opcode(Assembler::ldf_op3, Assembler::fitos_opf); From f9a6dbd5fd802b319c897b00c3cfda3e1e397d8a Mon Sep 17 00:00:00 2001 From: Christian Thalinger Date: Fri, 26 Feb 2016 11:13:25 -1000 Subject: [PATCH 030/129] 8150738: [JVMCI] runtime/CommandLine/TraceExceptionsTest.java fails with: java.lang.RuntimeException: '' missing Reviewed-by: coleenp --- hotspot/src/share/vm/jvmci/jvmciRuntime.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp index 716f73c06b1..d5a10f4660f 100644 --- a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp @@ -293,13 +293,11 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t // tracing if (log_is_enabled(Info, exceptions)) { ResourceMark rm; - log_info(exceptions)("Exception <%s> (" INTPTR_FORMAT ") thrown in" - " compiled method <%s> at PC " INTPTR_FORMAT - " for thread " INTPTR_FORMAT, - exception->print_value_string(), - p2i((address)exception()), - nm->method()->print_value_string(), p2i(pc), - p2i(thread)); + stringStream tempst; + tempst.print("compiled method <%s>\n" + " at PC" INTPTR_FORMAT " for thread " INTPTR_FORMAT, + nm->method()->print_value_string(), p2i(pc), p2i(thread)); + Exceptions::log_exception(exception, tempst); } // for AbortVMOnException flag NOT_PRODUCT(Exceptions::debug_check_abort(exception)); From babca8523287e182f5683992935c11bce2d754d6 Mon Sep 17 00:00:00 2001 From: Zoltan Majo Date: Mon, 29 Feb 2016 13:02:10 +0100 Subject: [PATCH 031/129] 8150349: Reduce the execution time of the hotspot_compiler_3 group Exclude long-running intrinsic-related tests that check functionality that is not likely to be changed soon. Reviewed-by: kvn, neliasso --- hotspot/test/TEST.groups | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups index f7d983f5a8f..11b95da776b 100644 --- a/hotspot/test/TEST.groups +++ b/hotspot/test/TEST.groups @@ -297,7 +297,8 @@ hotspot_compiler_3 = \ compiler/types/ \ compiler/uncommontrap/ \ compiler/unsafe/ \ - -compiler/intrinsics/bmi/verifycode \ + -compiler/intrinsics/adler32 \ + -compiler/intrinsics/bmi \ -compiler/intrinsics/mathexact \ -compiler/intrinsics/multiplytolen \ -compiler/intrinsics/sha \ From ea5a3565b8618fd0746082e0d82e423f47fcd7ce Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Mon, 29 Feb 2016 15:05:45 +0100 Subject: [PATCH 032/129] 8150720: Cleanup code around PrintOptoStatistics Reviewed-by: kvn, shade, vlivanov --- hotspot/src/share/vm/opto/graphKit.cpp | 17 ++++++---- hotspot/src/share/vm/opto/ifnode.cpp | 20 ++++++++---- hotspot/src/share/vm/opto/lcm.cpp | 2 ++ hotspot/src/share/vm/opto/matcher.cpp | 2 ++ hotspot/src/share/vm/opto/node.cpp | 28 ++-------------- hotspot/src/share/vm/opto/parse.hpp | 10 ------ hotspot/src/share/vm/opto/parse1.cpp | 45 ++++++++++++-------------- hotspot/src/share/vm/opto/parse2.cpp | 8 +++-- 8 files changed, 56 insertions(+), 76 deletions(-) diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index a47897db8c1..73f7c3e1254 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -1179,8 +1179,10 @@ Node* GraphKit::load_array_length(Node* array) { // Helper function to do a NULL pointer check. Returned value is // the incoming address with NULL casted away. You are allowed to use the // not-null value only if you are control dependent on the test. +#ifndef PRODUCT extern int explicit_null_checks_inserted, explicit_null_checks_elided; +#endif Node* GraphKit::null_check_common(Node* value, BasicType type, // optional arguments for variations: bool assert_null, @@ -1193,7 +1195,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, value = cast_not_null(value); // Make it appear to be non-null (4962416). return value; } - explicit_null_checks_inserted++; + NOT_PRODUCT(explicit_null_checks_inserted++); // Construct NULL check Node *chk = NULL; @@ -1233,7 +1235,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, // See if the type is contained in NULL_PTR. // If so, then the value is already null. if (t->higher_equal(TypePtr::NULL_PTR)) { - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); return value; // Elided null assert quickly! } } else { @@ -1242,7 +1244,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, // type. In other words, "value" was not-null. if (t->meet(TypePtr::NULL_PTR) != t->remove_speculative()) { // same as: if (!TypePtr::NULL_PTR->higher_equal(t)) ... - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); return value; // Elided null check quickly! } } @@ -1282,7 +1284,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, set_control(cfg); Node *res = cast_not_null(value); set_control(oldcontrol); - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); return res; } cfg = IfNode::up_one_dom(cfg, /*linear_only=*/ true); @@ -1326,15 +1328,18 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, IfNode* iff = create_and_map_if(control(), tst, ok_prob, COUNT_UNKNOWN); Node* null_true = _gvn.transform( new IfFalseNode(iff)); set_control( _gvn.transform( new IfTrueNode(iff))); - if (null_true == top()) +#ifndef PRODUCT + if (null_true == top()) { explicit_null_checks_elided++; + } +#endif (*null_control) = null_true; } else { BuildCutout unless(this, tst, ok_prob); // Check for optimizer eliding test at parse time if (stopped()) { // Failure not possible; do not bother making uncommon trap. - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); } else if (assert_null) { uncommon_trap(reason, Deoptimization::Action_make_not_entrant, diff --git a/hotspot/src/share/vm/opto/ifnode.cpp b/hotspot/src/share/vm/opto/ifnode.cpp index a2cea88273f..9e315739008 100644 --- a/hotspot/src/share/vm/opto/ifnode.cpp +++ b/hotspot/src/share/vm/opto/ifnode.cpp @@ -40,7 +40,9 @@ // Optimization - Graph Style +#ifndef PRODUCT extern int explicit_null_checks_elided; +#endif //============================================================================= //------------------------------Value------------------------------------------ @@ -1504,24 +1506,28 @@ Node* IfNode::search_identical(int dist) { Node* prev_dom = this; int op = Opcode(); // Search up the dominator tree for an If with an identical test - while( dom->Opcode() != op || // Not same opcode? + while (dom->Opcode() != op || // Not same opcode? dom->in(1) != in(1) || // Not same input 1? (req() == 3 && dom->in(2) != in(2)) || // Not same input 2? - prev_dom->in(0) != dom ) { // One path of test does not dominate? - if( dist < 0 ) return NULL; + prev_dom->in(0) != dom) { // One path of test does not dominate? + if (dist < 0) return NULL; dist--; prev_dom = dom; - dom = up_one_dom( dom ); - if( !dom ) return NULL; + dom = up_one_dom(dom); + if (!dom) return NULL; } // Check that we did not follow a loop back to ourselves - if( this == dom ) + if (this == dom) { return NULL; + } - if( dist > 2 ) // Add to count of NULL checks elided +#ifndef PRODUCT + if (dist > 2) { // Add to count of NULL checks elided explicit_null_checks_elided++; + } +#endif return prev_dom; } diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp index 3edfc5e0ef0..431bba14c7e 100644 --- a/hotspot/src/share/vm/opto/lcm.cpp +++ b/hotspot/src/share/vm/opto/lcm.cpp @@ -348,8 +348,10 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo } // ---- Found an implicit null check +#ifndef PRODUCT extern int implicit_null_checks; implicit_null_checks++; +#endif if( is_decoden ) { // Check if we need to hoist decodeHeapOop_not_null first. diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index edb69afb43d..1df9f7ca1c0 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -2415,8 +2415,10 @@ void Matcher::collect_null_checks( Node *proj, Node *orig_proj ) { bool push_it = false; if( proj->Opcode() == Op_IfTrue ) { +#ifndef PRODUCT extern int all_null_checks_found; all_null_checks_found++; +#endif if( b->_test._test == BoolTest::ne ) { push_it = true; } diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp index 42ca23d212a..78dcacc550b 100644 --- a/hotspot/src/share/vm/opto/node.cpp +++ b/hotspot/src/share/vm/opto/node.cpp @@ -576,17 +576,11 @@ void Node::setup_is_top() { //------------------------------~Node------------------------------------------ // Fancy destructor; eagerly attempt to reclaim Node numberings and storage -extern int reclaim_idx ; -extern int reclaim_in ; -extern int reclaim_node; void Node::destruct() { // Eagerly reclaim unique Node numberings Compile* compile = Compile::current(); if ((uint)_idx+1 == compile->unique()) { compile->set_unique(compile->unique()-1); -#ifdef ASSERT - reclaim_idx++; -#endif } // Clear debug info: Node_Notes* nn = compile->node_notes_at(_idx); @@ -604,43 +598,25 @@ void Node::destruct() { int out_edge_size = _outmax*sizeof(void*); char *edge_end = ((char*)_in) + edge_size; char *out_array = (char*)(_out == NO_OUT_ARRAY? NULL: _out); - char *out_edge_end = out_array + out_edge_size; int node_size = size_of(); // Free the output edge array if (out_edge_size > 0) { -#ifdef ASSERT - if( out_edge_end == compile->node_arena()->hwm() ) - reclaim_in += out_edge_size; // count reclaimed out edges with in edges -#endif compile->node_arena()->Afree(out_array, out_edge_size); } // Free the input edge array and the node itself if( edge_end == (char*)this ) { -#ifdef ASSERT - if( edge_end+node_size == compile->node_arena()->hwm() ) { - reclaim_in += edge_size; - reclaim_node+= node_size; - } -#else // It was; free the input array and object all in one hit +#ifndef ASSERT compile->node_arena()->Afree(_in,edge_size+node_size); #endif } else { - // Free just the input array -#ifdef ASSERT - if( edge_end == compile->node_arena()->hwm() ) - reclaim_in += edge_size; -#endif compile->node_arena()->Afree(_in,edge_size); // Free just the object -#ifdef ASSERT - if( ((char*)this) + node_size == compile->node_arena()->hwm() ) - reclaim_node+= node_size; -#else +#ifndef ASSERT compile->node_arena()->Afree(this,node_size); #endif } diff --git a/hotspot/src/share/vm/opto/parse.hpp b/hotspot/src/share/vm/opto/parse.hpp index c8a35c9ba53..b26a59f8497 100644 --- a/hotspot/src/share/vm/opto/parse.hpp +++ b/hotspot/src/share/vm/opto/parse.hpp @@ -104,13 +104,6 @@ public: // For temporary (stack-allocated, stateless) ilts: InlineTree(Compile* c, ciMethod* callee_method, JVMState* caller_jvms, float site_invoke_ratio, int max_inline_level); - // InlineTree enum - enum InlineStyle { - Inline_do_not_inline = 0, // - Inline_cha_is_monomorphic = 1, // - Inline_type_profile_monomorphic = 2 // - }; - // See if it is OK to inline. // The receiver is the inline tree for the caller. // @@ -349,9 +342,6 @@ class Parse : public GraphKit { Block* _block; // block currently getting parsed ciBytecodeStream _iter; // stream of this method's bytecodes - int _blocks_merged; // Progress meter: state merges from BB preds - int _blocks_parsed; // Progress meter: BBs actually parsed - const FastLockNode* _synch_lock; // FastLockNode for synchronized method #ifndef PRODUCT diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index e051b5e1e5c..503f3c7f400 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -45,6 +45,7 @@ // the most. Some of the non-static variables are needed in bytecodeInfo.cpp // and eventually should be encapsulated in a proper class (gri 8/18/98). +#ifndef PRODUCT int nodes_created = 0; int methods_parsed = 0; int methods_seen = 0; @@ -53,42 +54,42 @@ int blocks_seen = 0; int explicit_null_checks_inserted = 0; int explicit_null_checks_elided = 0; -int all_null_checks_found = 0, implicit_null_checks = 0; -int implicit_null_throws = 0; +int all_null_checks_found = 0; +int implicit_null_checks = 0; -int reclaim_idx = 0; -int reclaim_in = 0; -int reclaim_node = 0; - -#ifndef PRODUCT bool Parse::BytecodeParseHistogram::_initialized = false; uint Parse::BytecodeParseHistogram::_bytecodes_parsed [Bytecodes::number_of_codes]; uint Parse::BytecodeParseHistogram::_nodes_constructed[Bytecodes::number_of_codes]; uint Parse::BytecodeParseHistogram::_nodes_transformed[Bytecodes::number_of_codes]; uint Parse::BytecodeParseHistogram::_new_values [Bytecodes::number_of_codes]; -#endif //------------------------------print_statistics------------------------------- -#ifndef PRODUCT void Parse::print_statistics() { tty->print_cr("--- Compiler Statistics ---"); tty->print("Methods seen: %d Methods parsed: %d", methods_seen, methods_parsed); tty->print(" Nodes created: %d", nodes_created); tty->cr(); - if (methods_seen != methods_parsed) + if (methods_seen != methods_parsed) { tty->print_cr("Reasons for parse failures (NOT cumulative):"); + } tty->print_cr("Blocks parsed: %d Blocks seen: %d", blocks_parsed, blocks_seen); - if( explicit_null_checks_inserted ) - tty->print_cr("%d original NULL checks - %d elided (%2d%%); optimizer leaves %d,", explicit_null_checks_inserted, explicit_null_checks_elided, (100*explicit_null_checks_elided)/explicit_null_checks_inserted, all_null_checks_found); - if( all_null_checks_found ) + if (explicit_null_checks_inserted) { + tty->print_cr("%d original NULL checks - %d elided (%2d%%); optimizer leaves %d,", + explicit_null_checks_inserted, explicit_null_checks_elided, + (100*explicit_null_checks_elided)/explicit_null_checks_inserted, + all_null_checks_found); + } + if (all_null_checks_found) { tty->print_cr("%d made implicit (%2d%%)", implicit_null_checks, (100*implicit_null_checks)/all_null_checks_found); - if( implicit_null_throws ) + } + if (SharedRuntime::_implicit_null_throws) { tty->print_cr("%d implicit null exceptions at runtime", - implicit_null_throws); + SharedRuntime::_implicit_null_throws); + } - if( PrintParseStatistics && BytecodeParseHistogram::initialized() ) { + if (PrintParseStatistics && BytecodeParseHistogram::initialized()) { BytecodeParseHistogram::print(); } } @@ -495,7 +496,7 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) C->dependencies()->assert_evol_method(method()); } - methods_seen++; + NOT_PRODUCT(methods_seen++); // Do some special top-level things. if (depth() == 1 && C->is_osr_compilation()) { @@ -530,8 +531,8 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) } #endif - methods_parsed++; #ifndef PRODUCT + methods_parsed++; // add method size here to guarantee that inlined methods are added too if (CITime) _total_bytes_compiled += method()->code_size(); @@ -652,7 +653,7 @@ void Parse::do_all_blocks() { continue; } - blocks_parsed++; + NOT_PRODUCT(blocks_parsed++); progress = true; if (block->is_loop_head() || block->is_handler() || has_irreducible && !block->is_ready()) { @@ -712,9 +713,9 @@ void Parse::do_all_blocks() { } } +#ifndef PRODUCT blocks_seen += block_count(); -#ifndef PRODUCT // Make sure there are no half-processed blocks remaining. // Every remaining unprocessed block is dead and may be ignored now. for (int rpo = 0; rpo < block_count(); rpo++) { @@ -1446,7 +1447,6 @@ void Parse::do_one_block() { assert(block()->is_merged(), "must be merged before being parsed"); block()->mark_parsed(); - ++_blocks_parsed; // Set iterator to start of block. iter().reset_to_bci(block()->start()); @@ -1596,9 +1596,6 @@ void Parse::merge_common(Parse::Block* target, int pnum) { return; } - // Record that a new block has been merged. - ++_blocks_merged; - // Make a region if we know there are multiple or unpredictable inputs. // (Also, if this is a plain fall-through, we might see another region, // which must not be allowed into this block's map.) diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp index e03abd4f931..8004ef246e5 100644 --- a/hotspot/src/share/vm/opto/parse2.cpp +++ b/hotspot/src/share/vm/opto/parse2.cpp @@ -44,8 +44,10 @@ #include "runtime/deoptimization.hpp" #include "runtime/sharedRuntime.hpp" +#ifndef PRODUCT extern int explicit_null_checks_inserted, explicit_null_checks_elided; +#endif //---------------------------------array_load---------------------------------- void Parse::array_load(BasicType elem_type) { @@ -997,7 +999,7 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { return; } - explicit_null_checks_inserted++; + NOT_PRODUCT(explicit_null_checks_inserted++); // Generate real control flow Node *tst = _gvn.transform( new BoolNode( c, btest ) ); @@ -1013,7 +1015,7 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { set_control(iftrue); if (stopped()) { // Path is dead? - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); if (C->eliminate_boxing()) { // Mark the successor block as parsed branch_block->next_path_num(); @@ -1033,7 +1035,7 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { set_control(iffalse); if (stopped()) { // Path is dead? - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); if (C->eliminate_boxing()) { // Mark the successor block as parsed next_block->next_path_num(); From bb51ea7a06a1c95184940b26e45957731b2ae5f1 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Mon, 29 Feb 2016 23:46:55 +0300 Subject: [PATCH 033/129] 8150543: Mismatched access detection is inaccurate Reviewed-by: kvn, shade --- hotspot/src/share/vm/opto/library_call.cpp | 8 +- hotspot/src/share/vm/opto/memnode.cpp | 18 +- .../unsafe/UnsafeGetConstantField.java | 3 + .../unsafe/UnsafeGetStableArrayElement.java | 278 +++++++++++++++++- 4 files changed, 284 insertions(+), 23 deletions(-) diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index de751bc1a97..240321cb231 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -2541,10 +2541,12 @@ bool LibraryCallKit::inline_unsafe_access(const bool is_native_ptr, bool is_stor if (alias_type->element() != NULL || alias_type->field() != NULL) { BasicType bt; if (alias_type->element() != NULL) { - const Type* element = alias_type->element(); + // Use address type to get the element type. Alias type doesn't provide + // enough information (e.g., doesn't differentiate between byte[] and boolean[]). + const Type* element = adr_type->is_aryptr()->elem(); bt = element->isa_narrowoop() ? T_OBJECT : element->array_element_basic_type(); } else { - bt = alias_type->field()->type()->basic_type(); + bt = alias_type->field()->layout_type(); } if (bt == T_ARRAY) { // accessing an array field with getObject is not a mismatch @@ -2561,7 +2563,7 @@ bool LibraryCallKit::inline_unsafe_access(const bool is_native_ptr, bool is_stor // Try to constant fold a load from a constant field ciField* field = alias_type->field(); if (heap_base_oop != top() && - field != NULL && field->is_constant() && field->layout_type() == type) { + field != NULL && field->is_constant() && !mismatched) { // final or stable field const Type* con_type = Type::make_constant(alias_type->field(), heap_base_oop); if (con_type != NULL) { diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 55ca4581485..2d2b40d334e 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -1582,14 +1582,22 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls, return NULL; } +#ifdef ASSERT static bool is_mismatched_access(ciConstant con, BasicType loadbt) { BasicType conbt = con.basic_type(); - assert(conbt != T_NARROWOOP, "sanity"); - if (loadbt == T_NARROWOOP || loadbt == T_ARRAY) { - loadbt = T_OBJECT; + switch (conbt) { + case T_BOOLEAN: conbt = T_BYTE; break; + case T_ARRAY: conbt = T_OBJECT; break; + } + switch (loadbt) { + case T_BOOLEAN: loadbt = T_BYTE; break; + case T_NARROWOOP: loadbt = T_OBJECT; break; + case T_ARRAY: loadbt = T_OBJECT; break; + case T_ADDRESS: loadbt = T_OBJECT; break; } return (conbt != loadbt); } +#endif // ASSERT // Try to constant-fold a stable array element. static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) { @@ -1599,7 +1607,9 @@ static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicTyp // Decode the results of GraphKit::array_element_address. ciArray* aobj = ary->const_oop()->as_array(); ciConstant con = aobj->element_value_by_offset(off); - if (con.basic_type() != T_ILLEGAL && !is_mismatched_access(con, loadbt) && !con.is_null_or_zero()) { + if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) { + assert(!is_mismatched_access(con, loadbt), + "conbt=%s; loadbt=%s", type2name(con.basic_type()), type2name(loadbt)); const Type* con_type = Type::make_from_constant(con); if (con_type != NULL) { if (con_type->isa_aryptr()) { diff --git a/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java b/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java index 8c144143d62..c1d6b057e14 100644 --- a/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java +++ b/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java @@ -27,6 +27,9 @@ * @test * @summary tests on constant folding of unsafe get operations * @library /testlibrary /test/lib + * + * @requires vm.flavor != "client" + * * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions * -Xbatch -XX:-TieredCompilation * -XX:+FoldStableValues diff --git a/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java index afdb1a6e7a3..0cf5f44dc85 100644 --- a/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java +++ b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java @@ -25,17 +25,15 @@ /* * @test - * @summary tests on constant folding of unsafe get operations + * @summary tests on constant folding of unsafe get operations from stable arrays * @library /testlibrary /test/lib * + * @requires vm.flavor != "client" + * * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions * -Xbatch -XX:-TieredCompilation * -XX:+FoldStableValues - * UnsafeGetStableArrayElement - * - * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions - * -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+FoldStableValues + * -XX:CompileCommand=dontinline,*Test::test* * UnsafeGetStableArrayElement */ import jdk.internal.misc.Unsafe; @@ -46,23 +44,271 @@ import static jdk.internal.misc.Unsafe.*; import static jdk.test.lib.Asserts.*; public class UnsafeGetStableArrayElement { - @Stable static final byte[] STABLE_BYTE_ARRAY = new byte[] { 0, 1, -128, 127}; + @Stable static final boolean[] STABLE_BOOLEAN_ARRAY = new boolean[16]; + @Stable static final byte[] STABLE_BYTE_ARRAY = new byte[16]; + @Stable static final short[] STABLE_SHORT_ARRAY = new short[8]; + @Stable static final char[] STABLE_CHAR_ARRAY = new char[8]; + @Stable static final int[] STABLE_INT_ARRAY = new int[4]; + @Stable static final long[] STABLE_LONG_ARRAY = new long[2]; + @Stable static final float[] STABLE_FLOAT_ARRAY = new float[4]; + @Stable static final double[] STABLE_DOUBLE_ARRAY = new double[2]; + @Stable static final Object[] STABLE_OBJECT_ARRAY = new Object[4]; + static { + Setter.reset(); + } static final Unsafe U = Unsafe.getUnsafe(); - static int testChar() { - return U.getChar(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET + 0 * ARRAY_CHAR_INDEX_SCALE) + - U.getChar(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET + 1 * ARRAY_CHAR_INDEX_SCALE); - } + static class Setter { + private static void setZ(boolean defaultVal) { STABLE_BOOLEAN_ARRAY[0] = defaultVal ? false : true; } + private static void setB(boolean defaultVal) { STABLE_BYTE_ARRAY[0] = defaultVal ? 0 : Byte.MAX_VALUE; } + private static void setS(boolean defaultVal) { STABLE_SHORT_ARRAY[0] = defaultVal ? 0 : Short.MAX_VALUE; } + private static void setC(boolean defaultVal) { STABLE_CHAR_ARRAY[0] = defaultVal ? 0 : Character.MAX_VALUE; } + private static void setI(boolean defaultVal) { STABLE_INT_ARRAY[0] = defaultVal ? 0 : Integer.MAX_VALUE; } + private static void setJ(boolean defaultVal) { STABLE_LONG_ARRAY[0] = defaultVal ? 0 : Long.MAX_VALUE; } + private static void setF(boolean defaultVal) { STABLE_FLOAT_ARRAY[0] = defaultVal ? 0 : Float.MAX_VALUE; } + private static void setD(boolean defaultVal) { STABLE_DOUBLE_ARRAY[0] = defaultVal ? 0 : Double.MAX_VALUE; } + private static void setL(boolean defaultVal) { STABLE_OBJECT_ARRAY[0] = defaultVal ? null : new Object(); } - static void run(Callable c) throws Exception { - Object first = c.call(); - for (int i = 0; i < 20_000; i++) { - assertEQ(first, c.call()); + static void reset() { + setZ(false); + setB(false); + setS(false); + setC(false); + setI(false); + setJ(false); + setF(false); + setD(false); + setL(false); } } + static class Test { + static void changeZ() { Setter.setZ(true); } + static void changeB() { Setter.setB(true); } + static void changeS() { Setter.setS(true); } + static void changeC() { Setter.setC(true); } + static void changeI() { Setter.setI(true); } + static void changeJ() { Setter.setJ(true); } + static void changeF() { Setter.setF(true); } + static void changeD() { Setter.setD(true); } + static void changeL() { Setter.setL(true); } + + static boolean testZ_Z() { return U.getBoolean(STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static byte testZ_B() { return U.getByte( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static short testZ_S() { return U.getShort( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static char testZ_C() { return U.getChar( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static int testZ_I() { return U.getInt( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static long testZ_J() { return U.getLong( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static float testZ_F() { return U.getFloat( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static double testZ_D() { return U.getDouble( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + + static boolean testB_Z() { return U.getBoolean(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static byte testB_B() { return U.getByte( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static short testB_S() { return U.getShort( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static char testB_C() { return U.getChar( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static int testB_I() { return U.getInt( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static long testB_J() { return U.getLong( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static float testB_F() { return U.getFloat( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static double testB_D() { return U.getDouble( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + + static boolean testS_Z() { return U.getBoolean(STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static byte testS_B() { return U.getByte( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static short testS_S() { return U.getShort( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static char testS_C() { return U.getChar( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static int testS_I() { return U.getInt( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static long testS_J() { return U.getLong( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static float testS_F() { return U.getFloat( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static double testS_D() { return U.getDouble( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + + static boolean testC_Z() { return U.getBoolean(STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static byte testC_B() { return U.getByte( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static short testC_S() { return U.getShort( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static char testC_C() { return U.getChar( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static int testC_I() { return U.getInt( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static long testC_J() { return U.getLong( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static float testC_F() { return U.getFloat( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static double testC_D() { return U.getDouble( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + + static boolean testI_Z() { return U.getBoolean(STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static byte testI_B() { return U.getByte( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static short testI_S() { return U.getShort( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static char testI_C() { return U.getChar( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static int testI_I() { return U.getInt( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static long testI_J() { return U.getLong( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static float testI_F() { return U.getFloat( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static double testI_D() { return U.getDouble( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + + static boolean testJ_Z() { return U.getBoolean(STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static byte testJ_B() { return U.getByte( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static short testJ_S() { return U.getShort( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static char testJ_C() { return U.getChar( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static int testJ_I() { return U.getInt( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static long testJ_J() { return U.getLong( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static float testJ_F() { return U.getFloat( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static double testJ_D() { return U.getDouble( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + + static boolean testF_Z() { return U.getBoolean(STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static byte testF_B() { return U.getByte( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static short testF_S() { return U.getShort( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static char testF_C() { return U.getChar( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static int testF_I() { return U.getInt( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static long testF_J() { return U.getLong( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static float testF_F() { return U.getFloat( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static double testF_D() { return U.getDouble( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + + static boolean testD_Z() { return U.getBoolean(STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static byte testD_B() { return U.getByte( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static short testD_S() { return U.getShort( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static char testD_C() { return U.getChar( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static int testD_I() { return U.getInt( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static long testD_J() { return U.getLong( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static float testD_F() { return U.getFloat( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static double testD_D() { return U.getDouble( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + + static Object testL_L() { return U.getObject( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static boolean testL_Z() { return U.getBoolean(STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static byte testL_B() { return U.getByte( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static short testL_S() { return U.getShort( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static char testL_C() { return U.getChar( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static int testL_I() { return U.getInt( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static long testL_J() { return U.getLong( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static float testL_F() { return U.getFloat( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static double testL_D() { return U.getDouble( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + + static short testS_U() { return U.getShortUnaligned(STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET + 1); } + static char testC_U() { return U.getCharUnaligned( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET + 1); } + static int testI_U() { return U.getIntUnaligned( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET + 1); } + static long testJ_U() { return U.getLongUnaligned( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET + 1); } + } + + static void run(Callable c, Runnable sameResultAction, Runnable changeResultAction) throws Exception { + Object first = c.call(); + + // Trigger compilation. + for (int i = 0; i < 20_000; i++) { + // Don't compare results here, since most of Test::testL_* results vary across iterations (due to GC). + c.call(); + } + + if (sameResultAction != null) { + sameResultAction.run(); + assertEQ(first, c.call()); + } + + if (changeResultAction != null) { + changeResultAction.run(); + assertNE(first, c.call()); + assertEQ(c.call(), c.call()); + } + } + + static void testMatched(Callable c, Runnable setDefaultAction) throws Exception { + run(c, setDefaultAction, null); + Setter.reset(); + } + + static void testMismatched(Callable c, Runnable setDefaultAction) throws Exception { + run(c, null, setDefaultAction); + Setter.reset(); + } + public static void main(String[] args) throws Exception { - run(UnsafeGetStableArrayElement::testChar); + // boolean[], aligned accesses + testMatched( Test::testZ_Z, Test::changeZ); + testMismatched(Test::testZ_B, Test::changeZ); + testMismatched(Test::testZ_S, Test::changeZ); + testMismatched(Test::testZ_C, Test::changeZ); + testMismatched(Test::testZ_I, Test::changeZ); + testMismatched(Test::testZ_J, Test::changeZ); + testMismatched(Test::testZ_F, Test::changeZ); + testMismatched(Test::testZ_D, Test::changeZ); + + // byte[], aligned accesses + testMismatched(Test::testB_Z, Test::changeB); + testMatched( Test::testB_B, Test::changeB); + testMismatched(Test::testB_S, Test::changeB); + testMismatched(Test::testB_C, Test::changeB); + testMismatched(Test::testB_I, Test::changeB); + testMismatched(Test::testB_J, Test::changeB); + testMismatched(Test::testB_F, Test::changeB); + testMismatched(Test::testB_D, Test::changeB); + + // short[], aligned accesses + testMismatched(Test::testS_Z, Test::changeS); + testMismatched(Test::testS_B, Test::changeS); + testMatched( Test::testS_S, Test::changeS); + testMismatched(Test::testS_C, Test::changeS); + testMismatched(Test::testS_I, Test::changeS); + testMismatched(Test::testS_J, Test::changeS); + testMismatched(Test::testS_F, Test::changeS); + testMismatched(Test::testS_D, Test::changeS); + + // char[], aligned accesses + testMismatched(Test::testC_Z, Test::changeC); + testMismatched(Test::testC_B, Test::changeC); + testMismatched(Test::testC_S, Test::changeC); + testMatched( Test::testC_C, Test::changeC); + testMismatched(Test::testC_I, Test::changeC); + testMismatched(Test::testC_J, Test::changeC); + testMismatched(Test::testC_F, Test::changeC); + testMismatched(Test::testC_D, Test::changeC); + + // int[], aligned accesses + testMismatched(Test::testI_Z, Test::changeI); + testMismatched(Test::testI_B, Test::changeI); + testMismatched(Test::testI_S, Test::changeI); + testMismatched(Test::testI_C, Test::changeI); + testMatched( Test::testI_I, Test::changeI); + testMismatched(Test::testI_J, Test::changeI); + testMismatched(Test::testI_F, Test::changeI); + testMismatched(Test::testI_D, Test::changeI); + + // long[], aligned accesses + testMismatched(Test::testJ_Z, Test::changeJ); + testMismatched(Test::testJ_B, Test::changeJ); + testMismatched(Test::testJ_S, Test::changeJ); + testMismatched(Test::testJ_C, Test::changeJ); + testMismatched(Test::testJ_I, Test::changeJ); + testMatched( Test::testJ_J, Test::changeJ); + testMismatched(Test::testJ_F, Test::changeJ); + testMismatched(Test::testJ_D, Test::changeJ); + + // float[], aligned accesses + testMismatched(Test::testF_Z, Test::changeF); + testMismatched(Test::testF_B, Test::changeF); + testMismatched(Test::testF_S, Test::changeF); + testMismatched(Test::testF_C, Test::changeF); + testMismatched(Test::testF_I, Test::changeF); + testMismatched(Test::testF_J, Test::changeF); + testMatched( Test::testF_F, Test::changeF); + testMismatched(Test::testF_D, Test::changeF); + + // double[], aligned accesses + testMismatched(Test::testD_Z, Test::changeD); + testMismatched(Test::testD_B, Test::changeD); + testMismatched(Test::testD_S, Test::changeD); + testMismatched(Test::testD_C, Test::changeD); + testMismatched(Test::testD_I, Test::changeD); + testMismatched(Test::testD_J, Test::changeD); + testMismatched(Test::testD_F, Test::changeD); + testMatched( Test::testD_D, Test::changeD); + + // Object[], aligned accesses + testMismatched(Test::testL_Z, Test::changeL); + testMismatched(Test::testL_B, Test::changeL); + testMismatched(Test::testL_S, Test::changeL); + testMismatched(Test::testL_C, Test::changeL); + testMismatched(Test::testL_I, Test::changeL); + testMismatched(Test::testL_J, Test::changeL); + testMismatched(Test::testL_F, Test::changeL); + testMismatched(Test::testL_D, Test::changeL); + testMatched( Test::testL_L, Test::changeL); + + // Unaligned accesses + testMismatched(Test::testS_U, Test::changeS); + testMismatched(Test::testC_U, Test::changeC); + testMismatched(Test::testI_U, Test::changeI); + testMismatched(Test::testJ_U, Test::changeJ); } } From f73f7433d015641095e8a10b5f2c6ea15153214e Mon Sep 17 00:00:00 2001 From: Hui Shi Date: Wed, 24 Feb 2016 04:45:50 -0800 Subject: [PATCH 034/129] 8149733: AArch64: refactor array_equals/string_equals Combine similar code for string_equals/char_array_equals/byte_array_equals into same implemenation Reviewed-by: aph, shade --- hotspot/src/cpu/aarch64/vm/aarch64.ad | 25 +- .../cpu/aarch64/vm/macroAssembler_aarch64.cpp | 297 ++++++------------ .../cpu/aarch64/vm/macroAssembler_aarch64.hpp | 12 +- 3 files changed, 118 insertions(+), 216 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index 18ba1e44cf3..e980a2332f3 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -14783,19 +14783,19 @@ instruct string_indexof_con(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, %} instruct string_equals(iRegP_R1 str1, iRegP_R3 str2, iRegI_R4 cnt, - iRegI_R0 result, iRegP_R10 tmp, rFlagsReg cr) + iRegI_R0 result, rFlagsReg cr) %{ predicate(!CompactStrings); match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(KILL tmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); - format %{ "String Equals $str1,$str2,$cnt -> $result // KILL $tmp" %} + format %{ "String Equals $str1,$str2,$cnt -> $result" %} ins_encode %{ // Count is in 8-bit bytes; non-Compact chars are 16 bits. __ asrw($cnt$$Register, $cnt$$Register, 1); - __ string_equals($str1$$Register, $str2$$Register, - $cnt$$Register, $result$$Register, - $tmp$$Register); + __ arrays_equals($str1$$Register, $str2$$Register, + $result$$Register, $cnt$$Register, + 2, /*is_string*/true); %} ins_pipe(pipe_class_memory); %} @@ -14809,9 +14809,10 @@ instruct array_equalsB(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, format %{ "Array Equals $ary1,ary2 -> $result // KILL $tmp" %} ins_encode %{ - __ byte_arrays_equals($ary1$$Register, $ary2$$Register, - $result$$Register, $tmp$$Register); - %} + __ arrays_equals($ary1$$Register, $ary2$$Register, + $result$$Register, $tmp$$Register, + 1, /*is_string*/false); + %} ins_pipe(pipe_class_memory); %} @@ -14824,12 +14825,14 @@ instruct array_equalsC(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, format %{ "Array Equals $ary1,ary2 -> $result // KILL $tmp" %} ins_encode %{ - __ char_arrays_equals($ary1$$Register, $ary2$$Register, - $result$$Register, $tmp$$Register); + __ arrays_equals($ary1$$Register, $ary2$$Register, + $result$$Register, $tmp$$Register, + 2, /*is_string*/false); %} ins_pipe(pipe_class_memory); %} + // encode char[] to byte[] in ISO_8859_1 instruct encode_iso_array(iRegP_R2 src, iRegP_R1 dst, iRegI_R3 len, vRegD_V0 Vtmp1, vRegD_V1 Vtmp2, diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index 8c7f9465622..942518b116b 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -4481,225 +4481,126 @@ void MacroAssembler::string_compare(Register str1, Register str2, BLOCK_COMMENT("} string_compare"); } +// Compare Strings or char/byte arrays. -void MacroAssembler::string_equals(Register str1, Register str2, - Register cnt, Register result, - Register tmp1) { - Label SAME_CHARS, DONE, SHORT_LOOP, SHORT_STRING, - NEXT_WORD; +// is_string is true iff this is a string comparison. - const Register tmp2 = rscratch1; - assert_different_registers(str1, str2, cnt, result, tmp1, tmp2, rscratch2); +// For Strings we're passed the address of the first characters in a1 +// and a2 and the length in cnt1. - BLOCK_COMMENT("string_equals {"); +// For byte and char arrays we're passed the arrays themselves and we +// have to extract length fields and do null checks here. - // Start by assuming that the strings are not equal. - mov(result, zr); +// elem_size is the element size in bytes: either 1 or 2. - // A very short string - cmpw(cnt, 4); - br(Assembler::LT, SHORT_STRING); +// There are two implementations. For arrays >= 8 bytes, all +// comparisons (including the final one, which may overlap) are +// performed 8 bytes at a time. For arrays < 8 bytes, we compare a +// halfword, then a short, and then a byte. - // Check if the strings start at the same location. - cmp(str1, str2); - br(Assembler::EQ, SAME_CHARS); +void MacroAssembler::arrays_equals(Register a1, Register a2, + Register result, Register cnt1, + int elem_size, bool is_string) +{ + Label SAME, DONE, SHORT, NEXT_WORD, ONE; + Register tmp1 = rscratch1; + Register tmp2 = rscratch2; + Register cnt2 = tmp2; // cnt2 only used in array length compare + int elem_per_word = wordSize/elem_size; + int log_elem_size = exact_log2(elem_size); + int length_offset = arrayOopDesc::length_offset_in_bytes(); + int base_offset + = arrayOopDesc::base_offset_in_bytes(elem_size == 2 ? T_CHAR : T_BYTE); - // Compare longwords - { - subw(cnt, cnt, 4); // The last longword is a special case + assert(elem_size == 1 || elem_size == 2, "must be char or byte"); + assert_different_registers(a1, a2, result, cnt1, rscratch1, rscratch2); - // Move both string pointers to the last longword of their - // strings, negate the remaining count, and convert it to bytes. - lea(str1, Address(str1, cnt, Address::uxtw(1))); - lea(str2, Address(str2, cnt, Address::uxtw(1))); - sub(cnt, zr, cnt, LSL, 1); + BLOCK_COMMENT(is_string ? "string_equals {" : "array_equals {"); - // Loop, loading longwords and comparing them into rscratch2. - bind(NEXT_WORD); - ldr(tmp1, Address(str1, cnt)); - ldr(tmp2, Address(str2, cnt)); - adds(cnt, cnt, wordSize); - eor(rscratch2, tmp1, tmp2); - cbnz(rscratch2, DONE); - br(Assembler::LT, NEXT_WORD); + mov(result, false); - // Last longword. In the case where length == 4 we compare the - // same longword twice, but that's still faster than another - // conditional branch. + if (!is_string) { + // if (a==a2) + // return true; + eor(rscratch1, a1, a2); + cbz(rscratch1, SAME); + // if (a==null || a2==null) + // return false; + cbz(a1, DONE); + cbz(a2, DONE); + // if (a1.length != a2.length) + // return false; + ldrw(cnt1, Address(a1, length_offset)); + ldrw(cnt2, Address(a2, length_offset)); + eorw(tmp1, cnt1, cnt2); + cbnzw(tmp1, DONE); - ldr(tmp1, Address(str1)); - ldr(tmp2, Address(str2)); - eor(rscratch2, tmp1, tmp2); - cbz(rscratch2, SAME_CHARS); - b(DONE); + lea(a1, Address(a1, base_offset)); + lea(a2, Address(a2, base_offset)); } - bind(SHORT_STRING); - // Is the length zero? - cbz(cnt, SAME_CHARS); - - bind(SHORT_LOOP); - load_unsigned_short(tmp1, Address(post(str1, 2))); - load_unsigned_short(tmp2, Address(post(str2, 2))); - subw(tmp1, tmp1, tmp2); + // Check for short strings, i.e. smaller than wordSize. + subs(cnt1, cnt1, elem_per_word); + br(Assembler::LT, SHORT); + // Main 8 byte comparison loop. + bind(NEXT_WORD); { + ldr(tmp1, Address(post(a1, wordSize))); + ldr(tmp2, Address(post(a2, wordSize))); + subs(cnt1, cnt1, elem_per_word); + eor(tmp1, tmp1, tmp2); + cbnz(tmp1, DONE); + } br(GT, NEXT_WORD); + // Last longword. In the case where length == 4 we compare the + // same longword twice, but that's still faster than another + // conditional branch. + // cnt1 could be 0, -1, -2, -3, -4 for chars; -4 only happens when + // length == 4. + if (log_elem_size > 0) + lsl(cnt1, cnt1, log_elem_size); + ldr(tmp1, Address(a1, cnt1)); + ldr(tmp2, Address(a2, cnt1)); + eor(tmp1, tmp1, tmp2); cbnz(tmp1, DONE); - sub(cnt, cnt, 1); - cbnz(cnt, SHORT_LOOP); + b(SAME); - // Strings are equal. - bind(SAME_CHARS); + bind(SHORT); + Label TAIL03, TAIL01; + + tbz(cnt1, 2 - log_elem_size, TAIL03); // 0-7 bytes left. + { + ldrw(tmp1, Address(post(a1, 4))); + ldrw(tmp2, Address(post(a2, 4))); + eorw(tmp1, tmp1, tmp2); + cbnzw(tmp1, DONE); + } + bind(TAIL03); + tbz(cnt1, 1 - log_elem_size, TAIL01); // 0-3 bytes left. + { + ldrh(tmp1, Address(post(a1, 2))); + ldrh(tmp2, Address(post(a2, 2))); + eorw(tmp1, tmp1, tmp2); + cbnzw(tmp1, DONE); + } + bind(TAIL01); + if (elem_size == 1) { // Only needed when comparing byte arrays. + tbz(cnt1, 0, SAME); // 0-1 bytes left. + { + ldrb(tmp1, a1); + ldrb(tmp2, a2); + eorw(tmp1, tmp1, tmp2); + cbnzw(tmp1, DONE); + } + } + // Arrays are equal. + bind(SAME); mov(result, true); - // That's it + // That's it. bind(DONE); - - BLOCK_COMMENT("} string_equals"); + BLOCK_COMMENT(is_string ? "} string_equals" : "} array_equals"); } -void MacroAssembler::byte_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1) -{ - Register cnt1 = rscratch1; - Register cnt2 = rscratch2; - Register tmp2 = rscratch2; - - Label SAME, DIFFER, NEXT, TAIL07, TAIL03, TAIL01; - - int length_offset = arrayOopDesc::length_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_BYTE); - - BLOCK_COMMENT("byte_arrays_equals {"); - - // different until proven equal - mov(result, false); - - // same array? - cmp(ary1, ary2); - br(Assembler::EQ, SAME); - - // ne if either null - cbz(ary1, DIFFER); - cbz(ary2, DIFFER); - - // lengths ne? - ldrw(cnt1, Address(ary1, length_offset)); - ldrw(cnt2, Address(ary2, length_offset)); - cmp(cnt1, cnt2); - br(Assembler::NE, DIFFER); - - lea(ary1, Address(ary1, base_offset)); - lea(ary2, Address(ary2, base_offset)); - - subs(cnt1, cnt1, 8); - br(LT, TAIL07); - - BIND(NEXT); - ldr(tmp1, Address(post(ary1, 8))); - ldr(tmp2, Address(post(ary2, 8))); - subs(cnt1, cnt1, 8); - eor(tmp1, tmp1, tmp2); - cbnz(tmp1, DIFFER); - br(GE, NEXT); - - BIND(TAIL07); // 0-7 bytes left, cnt1 = #bytes left - 4 - tst(cnt1, 0b100); - br(EQ, TAIL03); - ldrw(tmp1, Address(post(ary1, 4))); - ldrw(tmp2, Address(post(ary2, 4))); - cmp(tmp1, tmp2); - br(NE, DIFFER); - - BIND(TAIL03); // 0-3 bytes left, cnt1 = #bytes left - 4 - tst(cnt1, 0b10); - br(EQ, TAIL01); - ldrh(tmp1, Address(post(ary1, 2))); - ldrh(tmp2, Address(post(ary2, 2))); - cmp(tmp1, tmp2); - br(NE, DIFFER); - BIND(TAIL01); // 0-1 byte left - tst(cnt1, 0b01); - br(EQ, SAME); - ldrb(tmp1, ary1); - ldrb(tmp2, ary2); - cmp(tmp1, tmp2); - br(NE, DIFFER); - - BIND(SAME); - mov(result, true); - BIND(DIFFER); // result already set - - BLOCK_COMMENT("} byte_arrays_equals"); -} - -// Compare char[] arrays aligned to 4 bytes -void MacroAssembler::char_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1) -{ - Register cnt1 = rscratch1; - Register cnt2 = rscratch2; - Register tmp2 = rscratch2; - - Label SAME, DIFFER, NEXT, TAIL03, TAIL01; - - int length_offset = arrayOopDesc::length_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); - - BLOCK_COMMENT("char_arrays_equals {"); - - // different until proven equal - mov(result, false); - - // same array? - cmp(ary1, ary2); - br(Assembler::EQ, SAME); - - // ne if either null - cbz(ary1, DIFFER); - cbz(ary2, DIFFER); - - // lengths ne? - ldrw(cnt1, Address(ary1, length_offset)); - ldrw(cnt2, Address(ary2, length_offset)); - cmp(cnt1, cnt2); - br(Assembler::NE, DIFFER); - - lea(ary1, Address(ary1, base_offset)); - lea(ary2, Address(ary2, base_offset)); - - subs(cnt1, cnt1, 4); - br(LT, TAIL03); - - BIND(NEXT); - ldr(tmp1, Address(post(ary1, 8))); - ldr(tmp2, Address(post(ary2, 8))); - subs(cnt1, cnt1, 4); - eor(tmp1, tmp1, tmp2); - cbnz(tmp1, DIFFER); - br(GE, NEXT); - - BIND(TAIL03); // 0-3 chars left, cnt1 = #chars left - 4 - tst(cnt1, 0b10); - br(EQ, TAIL01); - ldrw(tmp1, Address(post(ary1, 4))); - ldrw(tmp2, Address(post(ary2, 4))); - cmp(tmp1, tmp2); - br(NE, DIFFER); - BIND(TAIL01); // 0-1 chars left - tst(cnt1, 0b01); - br(EQ, SAME); - ldrh(tmp1, ary1); - ldrh(tmp2, ary2); - cmp(tmp1, tmp2); - br(NE, DIFFER); - - BIND(SAME); - mov(result, true); - BIND(DIFFER); // result already set - - BLOCK_COMMENT("} char_arrays_equals"); -} - // encode char[] to byte[] in ISO_8859_1 void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, Register result, diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp index d22c581bc41..e042b5055eb 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp @@ -1186,13 +1186,11 @@ public: void string_compare(Register str1, Register str2, Register cnt1, Register cnt2, Register result, Register tmp1); - void string_equals(Register str1, Register str2, - Register cnt, Register result, - Register tmp1); - void char_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1); - void byte_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1); + + void arrays_equals(Register a1, Register a2, + Register result, Register cnt1, + int elem_size, bool is_string); + void encode_iso_array(Register src, Register dst, Register len, Register result, FloatRegister Vtmp1, FloatRegister Vtmp2, From a30c46aa74610773458947247315459e487ec9f3 Mon Sep 17 00:00:00 2001 From: Felix Yang Date: Wed, 17 Feb 2016 20:19:24 +0800 Subject: [PATCH 035/129] 8150038: aarch64: make use of CBZ and CBNZ when comparing narrow pointer with zero Aarch64: c2 make use of CBZ and CBNZ when comparing narrow pointer with zero Reviewed-by: aph --- hotspot/src/cpu/aarch64/vm/aarch64.ad | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index e980a2332f3..8483c709564 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -14191,6 +14191,25 @@ instruct cmpP_imm0_branch(cmpOp cmp, iRegP op1, immP0 op2, label labl, rFlagsReg ins_pipe(pipe_cmp_branch); %} +instruct cmpN_imm0_branch(cmpOp cmp, iRegN op1, immN0 op2, label labl, rFlagsReg cr) %{ + match(If cmp (CmpN op1 op2)); + predicate(n->in(1)->as_Bool()->_test._test == BoolTest::ne + || n->in(1)->as_Bool()->_test._test == BoolTest::eq); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "cbw$cmp $op1, $labl" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; + if (cond == Assembler::EQ) + __ cbzw($op1$$Register, *L); + else + __ cbnzw($op1$$Register, *L); + %} + ins_pipe(pipe_cmp_branch); +%} + instruct cmpP_narrowOop_imm0_branch(cmpOp cmp, iRegN oop, immP0 zero, label labl, rFlagsReg cr) %{ match(If cmp (CmpP (DecodeN oop) zero)); predicate(n->in(1)->as_Bool()->_test._test == BoolTest::ne From 40cdd7a181d53e5a533b1a6644fdcc58a2601664 Mon Sep 17 00:00:00 2001 From: Felix Yang Date: Thu, 18 Feb 2016 21:53:24 +0800 Subject: [PATCH 036/129] 8149907: aarch64: use load/store pair instructions in call_stub Aarch64: make use of load/store pair instructions in call_stub to save space Reviewed-by: aph --- .../cpu/aarch64/vm/stubGenerator_aarch64.cpp | 94 +++++-------------- 1 file changed, 26 insertions(+), 68 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp index 64833c5ccc4..942d7bc5cb7 100644 --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp @@ -163,30 +163,20 @@ class StubGenerator: public StubCodeGenerator { sp_after_call_off = -26, d15_off = -26, - d14_off = -25, d13_off = -24, - d12_off = -23, d11_off = -22, - d10_off = -21, d9_off = -20, - d8_off = -19, r28_off = -18, - r27_off = -17, r26_off = -16, - r25_off = -15, r24_off = -14, - r23_off = -13, r22_off = -12, - r21_off = -11, r20_off = -10, - r19_off = -9, call_wrapper_off = -8, result_off = -7, result_type_off = -6, method_off = -5, entry_point_off = -4, - parameters_off = -3, parameter_size_off = -2, thread_off = -1, fp_f = 0, @@ -208,30 +198,20 @@ class StubGenerator: public StubCodeGenerator { const Address result_type (rfp, result_type_off * wordSize); const Address method (rfp, method_off * wordSize); const Address entry_point (rfp, entry_point_off * wordSize); - const Address parameters (rfp, parameters_off * wordSize); const Address parameter_size(rfp, parameter_size_off * wordSize); const Address thread (rfp, thread_off * wordSize); const Address d15_save (rfp, d15_off * wordSize); - const Address d14_save (rfp, d14_off * wordSize); const Address d13_save (rfp, d13_off * wordSize); - const Address d12_save (rfp, d12_off * wordSize); const Address d11_save (rfp, d11_off * wordSize); - const Address d10_save (rfp, d10_off * wordSize); const Address d9_save (rfp, d9_off * wordSize); - const Address d8_save (rfp, d8_off * wordSize); const Address r28_save (rfp, r28_off * wordSize); - const Address r27_save (rfp, r27_off * wordSize); const Address r26_save (rfp, r26_off * wordSize); - const Address r25_save (rfp, r25_off * wordSize); const Address r24_save (rfp, r24_off * wordSize); - const Address r23_save (rfp, r23_off * wordSize); const Address r22_save (rfp, r22_off * wordSize); - const Address r21_save (rfp, r21_off * wordSize); const Address r20_save (rfp, r20_off * wordSize); - const Address r19_save (rfp, r19_off * wordSize); // stub code @@ -254,31 +234,20 @@ class StubGenerator: public StubCodeGenerator { // rthread because we want to sanity check rthread later __ str(c_rarg7, thread); __ strw(c_rarg6, parameter_size); - __ str(c_rarg5, parameters); - __ str(c_rarg4, entry_point); - __ str(c_rarg3, method); - __ str(c_rarg2, result_type); - __ str(c_rarg1, result); - __ str(c_rarg0, call_wrapper); - __ str(r19, r19_save); - __ str(r20, r20_save); - __ str(r21, r21_save); - __ str(r22, r22_save); - __ str(r23, r23_save); - __ str(r24, r24_save); - __ str(r25, r25_save); - __ str(r26, r26_save); - __ str(r27, r27_save); - __ str(r28, r28_save); + __ stp(c_rarg4, c_rarg5, entry_point); + __ stp(c_rarg2, c_rarg3, result_type); + __ stp(c_rarg0, c_rarg1, call_wrapper); - __ strd(v8, d8_save); - __ strd(v9, d9_save); - __ strd(v10, d10_save); - __ strd(v11, d11_save); - __ strd(v12, d12_save); - __ strd(v13, d13_save); - __ strd(v14, d14_save); - __ strd(v15, d15_save); + __ stp(r20, r19, r20_save); + __ stp(r22, r21, r22_save); + __ stp(r24, r23, r24_save); + __ stp(r26, r25, r26_save); + __ stp(r28, r27, r28_save); + + __ stpd(v9, v8, d9_save); + __ stpd(v11, v10, d11_save); + __ stpd(v13, v12, d13_save); + __ stpd(v15, v14, d15_save); // install Java thread in global register now we have saved // whatever value it held @@ -385,33 +354,22 @@ class StubGenerator: public StubCodeGenerator { #endif // restore callee-save registers - __ ldrd(v15, d15_save); - __ ldrd(v14, d14_save); - __ ldrd(v13, d13_save); - __ ldrd(v12, d12_save); - __ ldrd(v11, d11_save); - __ ldrd(v10, d10_save); - __ ldrd(v9, d9_save); - __ ldrd(v8, d8_save); + __ ldpd(v15, v14, d15_save); + __ ldpd(v13, v12, d13_save); + __ ldpd(v11, v10, d11_save); + __ ldpd(v9, v8, d9_save); - __ ldr(r28, r28_save); - __ ldr(r27, r27_save); - __ ldr(r26, r26_save); - __ ldr(r25, r25_save); - __ ldr(r24, r24_save); - __ ldr(r23, r23_save); - __ ldr(r22, r22_save); - __ ldr(r21, r21_save); - __ ldr(r20, r20_save); - __ ldr(r19, r19_save); - __ ldr(c_rarg0, call_wrapper); - __ ldr(c_rarg1, result); + __ ldp(r28, r27, r28_save); + __ ldp(r26, r25, r26_save); + __ ldp(r24, r23, r24_save); + __ ldp(r22, r21, r22_save); + __ ldp(r20, r19, r20_save); + + __ ldp(c_rarg0, c_rarg1, call_wrapper); __ ldrw(c_rarg2, result_type); __ ldr(c_rarg3, method); - __ ldr(c_rarg4, entry_point); - __ ldr(c_rarg5, parameters); - __ ldr(c_rarg6, parameter_size); - __ ldr(c_rarg7, thread); + __ ldp(c_rarg4, c_rarg5, entry_point); + __ ldp(c_rarg6, c_rarg7, parameter_size); #ifndef PRODUCT // tell the simulator we are about to end Java execution From 35a916a2a186a093ef4c4b759edc1164793ef82a Mon Sep 17 00:00:00 2001 From: Andreas Eriksson Date: Thu, 18 Feb 2016 16:15:28 +0100 Subject: [PATCH 037/129] 8149743: JVM crash after debugger hotswap with lambdas Reviewed-by: sspitsyn, coleenp, dcubed --- hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp index 8823e6670a6..6b176ec1f70 100644 --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3940,6 +3940,10 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass, scratch_class->set_methods(_old_methods); // To prevent potential GCing of the old methods, // and to be able to undo operation easily. + Array* old_ordering = the_class->method_ordering(); + the_class->set_method_ordering(scratch_class->method_ordering()); + scratch_class->set_method_ordering(old_ordering); + ConstantPool* old_constants = the_class->constants(); the_class->set_constants(scratch_class->constants()); scratch_class->set_constants(old_constants); // See the previous comment. From d466ce4948fd6b5099da43453621a1437a40fc18 Mon Sep 17 00:00:00 2001 From: Felix Yang Date: Fri, 19 Feb 2016 17:12:14 +0800 Subject: [PATCH 038/129] 8150229: aarch64: pipeline class for several instructions is not set correctly Aarch64: c2 fix pipeline class for several instructions. Reviewed-by: aph --- hotspot/src/cpu/aarch64/vm/aarch64.ad | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index 8483c709564..acc65080e2f 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -13281,7 +13281,7 @@ instruct MoveF2I_reg_reg(iRegINoSp dst, vRegF src) %{ __ fmovs($dst$$Register, as_FloatRegister($src$$reg)); %} - ins_pipe(pipe_class_memory); + ins_pipe(fp_f2i); %} @@ -13299,7 +13299,7 @@ instruct MoveI2F_reg_reg(vRegF dst, iRegI src) %{ __ fmovs(as_FloatRegister($dst$$reg), $src$$Register); %} - ins_pipe(pipe_class_memory); + ins_pipe(fp_i2f); %} @@ -13317,7 +13317,7 @@ instruct MoveD2L_reg_reg(iRegLNoSp dst, vRegD src) %{ __ fmovd($dst$$Register, as_FloatRegister($src$$reg)); %} - ins_pipe(pipe_class_memory); + ins_pipe(fp_d2l); %} @@ -13335,7 +13335,7 @@ instruct MoveL2D_reg_reg(vRegD dst, iRegL src) %{ __ fmovd(as_FloatRegister($dst$$reg), $src$$Register); %} - ins_pipe(pipe_class_memory); + ins_pipe(fp_l2d); %} @@ -16502,7 +16502,7 @@ instruct vsll2I(vecD dst, vecD src, vecX shift) %{ as_FloatRegister($src$$reg), as_FloatRegister($shift$$reg)); %} - ins_pipe(vshift64_imm); + ins_pipe(vshift64); %} instruct vsll4I(vecX dst, vecX src, vecX shift) %{ @@ -16516,7 +16516,7 @@ instruct vsll4I(vecX dst, vecX src, vecX shift) %{ as_FloatRegister($src$$reg), as_FloatRegister($shift$$reg)); %} - ins_pipe(vshift128_imm); + ins_pipe(vshift128); %} instruct vsrl2I(vecD dst, vecD src, vecX shift) %{ @@ -16529,7 +16529,7 @@ instruct vsrl2I(vecD dst, vecD src, vecX shift) %{ as_FloatRegister($src$$reg), as_FloatRegister($shift$$reg)); %} - ins_pipe(vshift64_imm); + ins_pipe(vshift64); %} instruct vsrl4I(vecX dst, vecX src, vecX shift) %{ @@ -16542,7 +16542,7 @@ instruct vsrl4I(vecX dst, vecX src, vecX shift) %{ as_FloatRegister($src$$reg), as_FloatRegister($shift$$reg)); %} - ins_pipe(vshift128_imm); + ins_pipe(vshift128); %} instruct vsll2I_imm(vecD dst, vecD src, immI shift) %{ @@ -16660,7 +16660,7 @@ instruct vsll2L_imm(vecX dst, vecX src, immI shift) %{ as_FloatRegister($src$$reg), (int)$shift$$constant & 63); %} - ins_pipe(vshift128); + ins_pipe(vshift128_imm); %} instruct vsra2L_imm(vecX dst, vecX src, immI shift) %{ From 516438f368d53be93596baaf2d1f35d26770934c Mon Sep 17 00:00:00 2001 From: Konstantin Shefov Date: Sat, 20 Feb 2016 11:43:13 +0300 Subject: [PATCH 039/129] 8141616: Add new methods to the java Whitebox API Reviewed-by: kvn, dpochepk --- test/lib/sun/hotspot/WhiteBox.java | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/lib/sun/hotspot/WhiteBox.java b/test/lib/sun/hotspot/WhiteBox.java index 6b7863ad938..9964831c3c9 100644 --- a/test/lib/sun/hotspot/WhiteBox.java +++ b/test/lib/sun/hotspot/WhiteBox.java @@ -119,6 +119,28 @@ public class WhiteBox { return getConstantPool0(aClass); } + private native int getConstantPoolCacheIndexTag0(); + public int getConstantPoolCacheIndexTag() { + return getConstantPoolCacheIndexTag0(); + } + + private native int getConstantPoolCacheLength0(Class aClass); + public int getConstantPoolCacheLength(Class aClass) { + Objects.requireNonNull(aClass); + return getConstantPoolCacheLength0(aClass); + } + + private native int remapInstructionOperandFromCPCache0(Class aClass, int index); + public int remapInstructionOperandFromCPCache(Class aClass, int index) { + Objects.requireNonNull(aClass); + return remapInstructionOperandFromCPCache0(aClass, index); + } + + private native int encodeConstantPoolIndyIndex0(int index); + public int encodeConstantPoolIndyIndex(int index) { + return encodeConstantPoolIndyIndex0(index); + } + // JVMTI private native void addToBootstrapClassLoaderSearch0(String segment); public void addToBootstrapClassLoaderSearch(String segment){ From 44c03b15e225c4817560ed09e497cc7c3166b49f Mon Sep 17 00:00:00 2001 From: Timo Kinnunen Date: Tue, 23 Feb 2016 18:58:36 -0500 Subject: [PATCH 040/129] 8150426: Wrong cast in metadata_at_put Fix cast. Reviewed-by: dholmes, coleenp, jprovino --- hotspot/src/share/vm/oops/typeArrayOop.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/oops/typeArrayOop.hpp b/hotspot/src/share/vm/oops/typeArrayOop.hpp index e4670a8949b..8ab2f4d1f74 100644 --- a/hotspot/src/share/vm/oops/typeArrayOop.hpp +++ b/hotspot/src/share/vm/oops/typeArrayOop.hpp @@ -129,7 +129,7 @@ class typeArrayOopDesc : public arrayOopDesc { Metadata* metadata_at(int which) const { return (Metadata*)*long_at_addr(which); } void metadata_at_put(int which, Metadata* contents) { - *long_at_addr(which) = (long)contents; + *long_at_addr(which) = (jlong)contents; } #else Metadata* metadata_at(int which) const { From 3634fb9df2a8f1b117ecce947f14a3079e1cd783 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Wed, 24 Feb 2016 18:06:34 +0100 Subject: [PATCH 041/129] 8149036: Add tracing for thread related events at os level Reviewed-by: coleenp, mlarsson, dholmes --- hotspot/src/os/aix/vm/os_aix.cpp | 49 ++++++++++-------------- hotspot/src/os/bsd/vm/os_bsd.cpp | 22 +++++++++-- hotspot/src/os/linux/vm/os_linux.cpp | 21 ++++++++-- hotspot/src/os/posix/vm/os_posix.cpp | 13 +++++++ hotspot/src/os/posix/vm/os_posix.hpp | 5 +++ hotspot/src/os/solaris/vm/os_solaris.cpp | 42 ++++++++++++++++++-- hotspot/src/os/windows/vm/os_windows.cpp | 44 ++++++++++++++++++++- hotspot/src/share/vm/logging/logTag.hpp | 1 + hotspot/src/share/vm/runtime/thread.cpp | 34 +++++++++++++--- 9 files changed, 187 insertions(+), 44 deletions(-) diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index f63a789b89c..c38d2a3fbd0 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -36,6 +36,7 @@ #include "compiler/compileBroker.hpp" #include "interpreter/interpreter.hpp" #include "jvm_aix.h" +#include "logging/log.hpp" #include "libo4.hpp" #include "libperfstat_aix.hpp" #include "libodm_aix.hpp" @@ -791,13 +792,8 @@ static void *java_start(Thread *thread) { const pthread_t pthread_id = ::pthread_self(); const tid_t kernel_thread_id = ::thread_self(); - trcVerbose("newborn Thread : pthread-id %u, ktid " UINT64_FORMAT - ", stack %p ... %p, stacksize 0x%IX (%IB)", - pthread_id, kernel_thread_id, - thread->stack_end(), - thread->stack_base(), - thread->stack_size(), - thread->stack_size()); + log_info(os, thread)("Thread is alive (pthread id " UINTX_FORMAT ", tid " UINTX_FORMAT ")", + (uintx) pthread_id, (uintx) kernel_thread_id); // Normally, pthread stacks on AIX live in the data segment (are allocated with malloc() // by the pthread library). In rare cases, this may not be the case, e.g. when third-party @@ -805,7 +801,7 @@ static void *java_start(Thread *thread) { // guard pages on those stacks, because the stacks may reside in memory which is not // protectable (shmated). if (thread->stack_base() > ::sbrk(0)) { - trcVerbose("Thread " UINT64_FORMAT ": stack not in data segment.", (uint64_t) pthread_id); + log_warning(os, thread)("Thread " UINTX_FORMAT ": stack not in data segment.", (uintx)pthread_id); } // Try to randomize the cache line index of hot stack frames. @@ -839,8 +835,8 @@ static void *java_start(Thread *thread) { // Call one more level start routine. thread->run(); - trcVerbose("Thread finished : pthread-id %u, ktid " UINT64_FORMAT ".", - pthread_id, kernel_thread_id); + log_info(os, thread)("Thread finished (pthread id " UINTX_FORMAT ", tid " UINTX_FORMAT ").", + (uintx) pthread_id, (uintx) kernel_thread_id); return 0; } @@ -908,20 +904,19 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { pthread_t tid; int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread); + + char buf[64]; + if (ret == 0) { + log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } else { + log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.", + strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } + pthread_attr_destroy(&attr); - if (ret == 0) { - trcVerbose("Created New Thread : pthread-id %u", tid); - } else { - if (os::Aix::on_pase()) { - // QIBM_MULTI_THREADED=Y is needed when the launcher is started on iSeries - // using QSH. Otherwise pthread_create fails with errno=11. - trcVerbose("(Please make sure you set the environment variable " - "QIBM_MULTI_THREADED=Y before running this program.)"); - } - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("pthread_create()"); - } + if (ret != 0) { // Need to clean up stuff we've allocated so far thread->set_osthread(NULL); delete osthread; @@ -958,13 +953,6 @@ bool os::create_attached_thread(JavaThread* thread) { const pthread_t pthread_id = ::pthread_self(); const tid_t kernel_thread_id = ::thread_self(); - trcVerbose("attaching Thread : pthread-id %u, ktid " UINT64_FORMAT ", stack %p ... %p, stacksize 0x%IX (%IB)", - pthread_id, kernel_thread_id, - thread->stack_end(), - thread->stack_base(), - thread->stack_size(), - thread->stack_size()); - // OSThread::thread_id is the pthread id. osthread->set_thread_id(pthread_id); @@ -990,6 +978,9 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Aix::hotspot_sigmask(thread); + log_info(os, thread)("Thread attached (pthread id " UINTX_FORMAT ", tid " UINTX_FORMAT ")", + (uintx) pthread_id, (uintx) kernel_thread_id); + return true; } diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 8fdc6bc63b7..51fce416eda 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -32,6 +32,7 @@ #include "compiler/disassembler.hpp" #include "interpreter/interpreter.hpp" #include "jvm_bsd.h" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "mutex_bsd.inline.hpp" @@ -681,6 +682,9 @@ static void *java_start(Thread *thread) { osthread->set_thread_id(os::Bsd::gettid()); + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ".", + os::current_thread_id(), (uintx) pthread_self()); + #ifdef __APPLE__ uint64_t unique_thread_id = locate_unique_thread_id(osthread->thread_id()); guarantee(unique_thread_id != 0, "unique thread id was not found"); @@ -716,6 +720,9 @@ static void *java_start(Thread *thread) { // call one more level start routine thread->run(); + log_info(os, thread)("Thread finished (tid " UINTX_FORMAT ", pthread id " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) pthread_self()); + return 0; } @@ -776,12 +783,18 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { pthread_t tid; int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread); + char buf[64]; + if (ret == 0) { + log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } else { + log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.", + strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } + pthread_attr_destroy(&attr); if (ret != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("pthread_create()"); - } // Need to clean up stuff we've allocated so far thread->set_osthread(NULL); delete osthread; @@ -858,6 +871,9 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Bsd::hotspot_sigmask(thread); + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ".", + os::current_thread_id(), (uintx) pthread_self()); + return true; } diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 3783351c345..5bf366d3997 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -662,6 +662,9 @@ static void *java_start(Thread *thread) { osthread->set_thread_id(os::current_thread_id()); + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) pthread_self()); + if (UseNUMA) { int lgrp_id = os::numa_get_group_id(); if (lgrp_id != -1) { @@ -691,6 +694,9 @@ static void *java_start(Thread *thread) { // call one more level start routine thread->run(); + log_info(os, thread)("Thread finished (tid " UINTX_FORMAT ", pthread id " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) pthread_self()); + return 0; } @@ -756,12 +762,18 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, pthread_t tid; int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread); + char buf[64]; + if (ret == 0) { + log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } else { + log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.", + strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } + pthread_attr_destroy(&attr); if (ret != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("pthread_create()"); - } // Need to clean up stuff we've allocated so far thread->set_osthread(NULL); delete osthread; @@ -858,6 +870,9 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Linux::hotspot_sigmask(thread); + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) pthread_self()); + return true; } diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp index 8cccda34d21..85407bd3cad 100644 --- a/hotspot/src/os/posix/vm/os_posix.cpp +++ b/hotspot/src/os/posix/vm/os_posix.cpp @@ -1071,6 +1071,19 @@ void os::Posix::ucontext_set_pc(ucontext_t* ctx, address pc) { #endif } +char* os::Posix::describe_pthread_attr(char* buf, size_t buflen, const pthread_attr_t* attr) { + size_t stack_size = 0; + size_t guard_size = 0; + int detachstate = 0; + pthread_attr_getstacksize(attr, &stack_size); + pthread_attr_getguardsize(attr, &guard_size); + pthread_attr_getdetachstate(attr, &detachstate); + jio_snprintf(buf, buflen, "stacksize: " SIZE_FORMAT "k, guardsize: " SIZE_FORMAT "k, %s", + stack_size / 1024, guard_size / 1024, + (detachstate == PTHREAD_CREATE_DETACHED ? "detached" : "joinable")); + return buf; +} + 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 be464ea8fa1..0196e989456 100644 --- a/hotspot/src/os/posix/vm/os_posix.hpp +++ b/hotspot/src/os/posix/vm/os_posix.hpp @@ -76,6 +76,11 @@ public: static address ucontext_get_pc(const ucontext_t* ctx); // Set PC into context. Needed for continuation after signal. static void ucontext_set_pc(ucontext_t* ctx, address pc); + + // Helper function; describes pthread attributes as short string. String is written + // to buf with len buflen; buf is returned. + static char* describe_pthread_attr(char* buf, size_t buflen, const pthread_attr_t* attr); + }; /* diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index ae008b6dbe9..e454ed165c7 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -32,6 +32,7 @@ #include "compiler/disassembler.hpp" #include "interpreter/interpreter.hpp" #include "jvm_solaris.h" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "mutex_solaris.inline.hpp" @@ -68,6 +69,7 @@ #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" #include "utilities/vmError.hpp" // put OS-includes here @@ -736,6 +738,9 @@ extern "C" void* java_start(void* thread_addr) { osthr->set_lwp_id(_lwp_self()); // Store lwp in case we are bound thread->_schedctl = (void *) schedctl_init(); + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ").", + os::current_thread_id()); + if (UseNUMA) { int lgrp_id = os::numa_get_group_id(); if (lgrp_id != -1) { @@ -781,6 +786,8 @@ extern "C" void* java_start(void* thread_addr) { Atomic::dec(&os::Solaris::_os_thread_count); } + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ").", os::current_thread_id()); + if (UseDetachedThreads) { thr_exit(NULL); ShouldNotReachHere(); @@ -853,6 +860,9 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Solaris::hotspot_sigmask(thread); + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ").", + os::current_thread_id()); + return true; } @@ -879,6 +889,25 @@ bool os::create_main_thread(JavaThread* thread) { return true; } +// Helper function to trace thread attributes, similar to os::Posix::describe_pthread_attr() +static char* describe_thr_create_attributes(char* buf, size_t buflen, + size_t stacksize, long flags) +{ + stringStream ss(buf, buflen); + ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024); + ss.print("flags: "); + #define PRINT_FLAG(f) if (flags & f) ss.print( XSTR(f) " "); + #define ALL(X) \ + X(THR_SUSPENDED) \ + X(THR_DETACHED) \ + X(THR_BOUND) \ + X(THR_NEW_LWP) \ + X(THR_DAEMON) + ALL(PRINT_FLAG) + #undef ALL + #undef PRINT_FLAG + return buf; +} bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { @@ -974,10 +1003,17 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, osthread->set_thread_id(-1); status = thr_create(NULL, stack_size, java_start, thread, flags, &tid); + + char buf[64]; + if (status == 0) { + log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + (uintx) tid, describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); + } else { + log_warning(os, thread)("Failed to start thread - thr_create failed (%s) for attributes: %s.", + strerror(status), describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); + } + if (status != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("os::create_thread"); - } thread->set_osthread(NULL); // Need to clean up stuff we've allocated so far delete osthread; diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 19d7319e7e1..cc15183b186 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -35,6 +35,7 @@ #include "compiler/disassembler.hpp" #include "interpreter/interpreter.hpp" #include "jvm_windows.h" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "mutex_windows.inline.hpp" @@ -71,6 +72,7 @@ #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" #include "utilities/vmError.hpp" #ifdef _DEBUG @@ -436,6 +438,8 @@ static unsigned __stdcall java_start(Thread* thread) { res = 20115; // java thread } + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ").", os::current_thread_id()); + // Install a win32 structured exception handler around every thread created // by VM, so VM can generate error dump when an exception occurred in non- // Java thread (e.g. VM thread). @@ -446,6 +450,8 @@ static unsigned __stdcall java_start(Thread* thread) { // Nothing to do. } + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ").", os::current_thread_id()); + // One less thread is executing // When the VMThread gets here, the main thread may have already exited // which frees the CodeHeap containing the Atomic::add code @@ -509,6 +515,10 @@ bool os::create_attached_thread(JavaThread* thread) { osthread->set_state(RUNNABLE); thread->set_osthread(osthread); + + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ").", + os::current_thread_id()); + return true; } @@ -530,6 +540,28 @@ bool os::create_main_thread(JavaThread* thread) { return true; } +// Helper function to trace _beginthreadex attributes, +// similar to os::Posix::describe_pthread_attr() +static char* describe_beginthreadex_attributes(char* buf, size_t buflen, + size_t stacksize, unsigned initflag) +{ + stringStream ss(buf, buflen); + if (stacksize == 0) { + ss.print("stacksize: default, "); + } else { + ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024); + } + ss.print("flags: "); + #define PRINT_FLAG(f) if (initflag & f) ss.print( XSTR(f) " "); + #define ALL(X) \ + X(CREATE_SUSPENDED) \ + X(STACK_SIZE_PARAM_IS_A_RESERVATION) + ALL(PRINT_FLAG) + #undef ALL + #undef PRINT_FLAG + return buf; +} + // Allocate and initialize a new OSThread bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { @@ -596,14 +628,24 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, // document because JVM uses C runtime library. The good news is that the // flag appears to work with _beginthredex() as well. + const unsigned initflag = CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION; HANDLE thread_handle = (HANDLE)_beginthreadex(NULL, (unsigned)stack_size, (unsigned (__stdcall *)(void*)) java_start, thread, - CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, + initflag, &thread_id); + char buf[64]; + if (thread_handle != NULL) { + log_info(os, thread)("Thread started (tid: %u, attributes: %s)", + thread_id, describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag)); + } else { + log_warning(os, thread)("Failed to start thread - _beginthreadex failed (%s) for attributes: %s.", + strerror(errno), describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag)); + } + if (thread_handle == NULL) { // Need to clean up stuff we've allocated so far CloseHandle(osthread->interrupt_event()); diff --git a/hotspot/src/share/vm/logging/logTag.hpp b/hotspot/src/share/vm/logging/logTag.hpp index 60e39f710f5..16a91cfbddf 100644 --- a/hotspot/src/share/vm/logging/logTag.hpp +++ b/hotspot/src/share/vm/logging/logTag.hpp @@ -81,6 +81,7 @@ LOG_TAG(survivor) \ LOG_TAG(sweep) \ LOG_TAG(task) \ + LOG_TAG(thread) \ LOG_TAG(tlab) \ LOG_TAG(time) \ LOG_TAG(verify) \ diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 267c6584c37..654aebd9e70 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -324,6 +324,10 @@ void Thread::record_stack_base_and_size() { // record thread's native stack, stack grows downward MemTracker::record_thread_stack(stack_end(), stack_size()); #endif // INCLUDE_NMT + log_debug(os, thread)("Thread " UINTX_FORMAT " stack dimensions: " + PTR_FORMAT "-" PTR_FORMAT " (" SIZE_FORMAT "k).", + os::current_thread_id(), p2i(stack_base() - stack_size()), + p2i(stack_base()), stack_size()/1024); } @@ -1802,6 +1806,10 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { // Call after last event on thread EVENT_THREAD_EXIT(this); + log_info(os, thread)("Thread " UINTX_FORMAT " %s.", + os::current_thread_id(), + exit_type == JavaThread::normal_exit ? "exiting" : "detaching"); + // Call Thread.exit(). We try 3 times in case we got another Thread.stop during // the execution of the method. If that is not enough, then we don't really care. Thread.stop // is deprecated anyhow. @@ -2491,18 +2499,25 @@ void JavaThread::create_stack_guard_pages() { // warning("Guarding at " PTR_FORMAT " for len " SIZE_FORMAT "\n", low_addr, len); if (allocate && !os::create_stack_guard_pages((char *) low_addr, len)) { - warning("Attempt to allocate stack guard pages failed."); + log_warning(os, thread)("Attempt to allocate stack guard pages failed."); return; } if (os::guard_memory((char *) low_addr, len)) { _stack_guard_state = stack_guard_enabled; } else { - warning("Attempt to protect stack guard pages failed."); + log_warning(os, thread)("Attempt to protect stack guard pages failed (" + PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len)); if (os::uncommit_memory((char *) low_addr, len)) { - warning("Attempt to deallocate stack guard pages failed."); + log_warning(os, thread)("Attempt to deallocate stack guard pages failed."); } + return; } + + log_debug(os, thread)("Thread " UINTX_FORMAT " stack guard pages activated: " + PTR_FORMAT "-" PTR_FORMAT ".", + os::current_thread_id(), p2i(low_addr), p2i(low_addr + len)); + } void JavaThread::remove_stack_guard_pages() { @@ -2515,16 +2530,25 @@ void JavaThread::remove_stack_guard_pages() { if (os::remove_stack_guard_pages((char *) low_addr, len)) { _stack_guard_state = stack_guard_unused; } else { - warning("Attempt to deallocate stack guard pages failed."); + log_warning(os, thread)("Attempt to deallocate stack guard pages failed (" + PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len)); + return; } } else { if (_stack_guard_state == stack_guard_unused) return; if (os::unguard_memory((char *) low_addr, len)) { _stack_guard_state = stack_guard_unused; } else { - warning("Attempt to unprotect stack guard pages failed."); + log_warning(os, thread)("Attempt to unprotect stack guard pages failed (" + PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len)); + return; } } + + log_debug(os, thread)("Thread " UINTX_FORMAT " stack guard pages removed: " + PTR_FORMAT "-" PTR_FORMAT ".", + os::current_thread_id(), p2i(low_addr), p2i(low_addr + len)); + } void JavaThread::enable_stack_reserved_zone() { From 5d5113046a2273da15da3eb65e5dd6a7e5478393 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 24 Feb 2016 13:18:54 -0500 Subject: [PATCH 042/129] 8150419: Cleanup BufferNode API Fewer public functions, cleanup allocation. Reviewed-by: tschatzl, drwhite --- hotspot/src/share/vm/gc/g1/ptrQueue.cpp | 60 +++++++++++++++++-------- hotspot/src/share/vm/gc/g1/ptrQueue.hpp | 55 ++++++++++------------- 2 files changed, 65 insertions(+), 50 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp index 756b9599fb8..55b41a0b605 100644 --- a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,8 @@ #include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" +#include + PtrQueue::PtrQueue(PtrQueueSet* qset, bool permanent, bool active) : _qset(qset), _buf(NULL), _index(0), _sz(0), _active(active), _permanent(permanent), _lock(NULL) @@ -87,6 +89,19 @@ void PtrQueue::locking_enqueue_completed_buffer(void** buf) { } +BufferNode* BufferNode::allocate(size_t byte_size) { + assert(byte_size > 0, "precondition"); + assert(is_size_aligned(byte_size, sizeof(void**)), + "Invalid buffer size " SIZE_FORMAT, byte_size); + void* data = NEW_C_HEAP_ARRAY(char, buffer_offset() + byte_size, mtGC); + return new (data) BufferNode; +} + +void BufferNode::deallocate(BufferNode* node) { + node->~BufferNode(); + FREE_C_HEAP_ARRAY(char, node); +} + PtrQueueSet::PtrQueueSet(bool notify_when_complete) : _max_completed_queue(0), _cbl_mon(NULL), _fl_lock(NULL), @@ -123,17 +138,23 @@ void PtrQueueSet::initialize(Monitor* cbl_mon, void** PtrQueueSet::allocate_buffer() { assert(_sz > 0, "Didn't set a buffer size."); - MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag); - if (_fl_owner->_buf_free_list != NULL) { - void** res = BufferNode::make_buffer_from_node(_fl_owner->_buf_free_list); - _fl_owner->_buf_free_list = _fl_owner->_buf_free_list->next(); - _fl_owner->_buf_free_list_sz--; - return res; - } else { - // Allocate space for the BufferNode in front of the buffer. - char *b = NEW_C_HEAP_ARRAY(char, _sz + BufferNode::aligned_size(), mtGC); - return BufferNode::make_buffer_from_block(b); + BufferNode* node = NULL; + { + MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag); + node = _fl_owner->_buf_free_list; + if (node != NULL) { + _fl_owner->_buf_free_list = node->next(); + _fl_owner->_buf_free_list_sz--; + } } + if (node == NULL) { + node = BufferNode::allocate(_sz); + } else { + // Reinitialize buffer obtained from free list. + node->set_index(0); + node->set_next(NULL); + } + return BufferNode::make_buffer_from_node(node); } void PtrQueueSet::deallocate_buffer(void** buf) { @@ -150,13 +171,13 @@ void PtrQueueSet::reduce_free_list() { // For now we'll adopt the strategy of deleting half. MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag); size_t n = _buf_free_list_sz / 2; - while (n > 0) { - assert(_buf_free_list != NULL, "_buf_free_list_sz must be wrong."); - void* b = BufferNode::make_block_from_node(_buf_free_list); - _buf_free_list = _buf_free_list->next(); - FREE_C_HEAP_ARRAY(char, b); - _buf_free_list_sz --; - n--; + for (size_t i = 0; i < n; ++i) { + assert(_buf_free_list != NULL, + "_buf_free_list_sz is wrong: " SIZE_FORMAT, _buf_free_list_sz); + BufferNode* node = _buf_free_list; + _buf_free_list = node->next(); + _buf_free_list_sz--; + BufferNode::deallocate(node); } } @@ -236,8 +257,9 @@ bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) { void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) { MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); - BufferNode* cbn = BufferNode::new_from_buffer(buf); + BufferNode* cbn = BufferNode::make_node_from_buffer(buf); cbn->set_index(index); + cbn->set_next(NULL); if (_completed_buffers_tail == NULL) { assert(_completed_buffers_head == NULL, "Well-formedness"); _completed_buffers_head = cbn; diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp index 707d591c0c0..a2207641238 100644 --- a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,9 +33,6 @@ // the addresses of modified old-generation objects. This type supports // this operation. -// The definition of placement operator new(size_t, void*) in the . -#include - class PtrQueueSet; class PtrQueue VALUE_OBJ_CLASS_SPEC { friend class VMStructs; @@ -168,42 +165,38 @@ protected: class BufferNode { size_t _index; BufferNode* _next; -public: + void* _buffer[1]; // Pseudo flexible array member. + BufferNode() : _index(0), _next(NULL) { } + ~BufferNode() { } + + static size_t buffer_offset() { + return offset_of(BufferNode, _buffer); + } + +public: BufferNode* next() const { return _next; } void set_next(BufferNode* n) { _next = n; } size_t index() const { return _index; } void set_index(size_t i) { _index = i; } - // Align the size of the structure to the size of the pointer - static size_t aligned_size() { - static const size_t alignment = round_to(sizeof(BufferNode), sizeof(void*)); - return alignment; + // Allocate a new BufferNode with the "buffer" having size bytes. + static BufferNode* allocate(size_t byte_size); + + // Free a BufferNode. + static void deallocate(BufferNode* node); + + // Return the BufferNode containing the buffer. + static BufferNode* make_node_from_buffer(void** buffer) { + return reinterpret_cast( + reinterpret_cast(buffer) - buffer_offset()); } - // BufferNode is allocated before the buffer. - // The chunk of memory that holds both of them is a block. - - // Produce a new BufferNode given a buffer. - static BufferNode* new_from_buffer(void** buf) { - return new (make_block_from_buffer(buf)) BufferNode; - } - - // The following are the required conversion routines: - static BufferNode* make_node_from_buffer(void** buf) { - return (BufferNode*)make_block_from_buffer(buf); - } + // Return the buffer for node. static void** make_buffer_from_node(BufferNode *node) { - return make_buffer_from_block(node); - } - static void* make_block_from_node(BufferNode *node) { - return (void*)node; - } - static void** make_buffer_from_block(void* p) { - return (void**)((char*)p + aligned_size()); - } - static void* make_block_from_buffer(void** p) { - return (void*)((char*)p - aligned_size()); + // &_buffer[0] might lead to index out of bounds warnings. + return reinterpret_cast( + reinterpret_cast(node) + buffer_offset()); } }; From 453c5ef3758028d9c4cf4707e2487e5266352e69 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 24 Feb 2016 16:04:51 -0500 Subject: [PATCH 043/129] 8150506: Remove unused locks Reviewed-by: mgronlun, tschatzl, mgerdin, coleenp --- hotspot/src/share/vm/runtime/fprofiler.cpp | 5 ++--- hotspot/src/share/vm/runtime/mutex.cpp | 5 +---- hotspot/src/share/vm/runtime/mutexLocker.cpp | 14 +------------- hotspot/src/share/vm/runtime/mutexLocker.hpp | 7 +------ 4 files changed, 5 insertions(+), 26 deletions(-) diff --git a/hotspot/src/share/vm/runtime/fprofiler.cpp b/hotspot/src/share/vm/runtime/fprofiler.cpp index fbc51b4047d..fc687618e03 100644 --- a/hotspot/src/share/vm/runtime/fprofiler.cpp +++ b/hotspot/src/share/vm/runtime/fprofiler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -836,8 +836,7 @@ void FlatProfiler::record_vm_tick() { vm_thread_profiler->inc_thread_ticks(); // Get a snapshot of a current VMThread pc (and leave it running!) - // The call may fail if, for instance the VM thread is interrupted while - // holding the Interrupt_lock or for other reasons. + // The call may fail in some circumstances epc = os::get_thread_pc(VMThread::vm_thread()); if(epc.pc() != NULL) { if (os::dll_address_to_function_name(epc.pc(), buf, sizeof(buf), NULL)) { diff --git a/hotspot/src/share/vm/runtime/mutex.cpp b/hotspot/src/share/vm/runtime/mutex.cpp index 81fa378d05c..ef6ac43b5d6 100644 --- a/hotspot/src/share/vm/runtime/mutex.cpp +++ b/hotspot/src/share/vm/runtime/mutex.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1320,15 +1320,12 @@ void Monitor::set_owner_implementation(Thread *new_owner) { // The rank Mutex::native is an exception in that it is not subject // to the verification rules. // Here are some further notes relating to mutex acquisition anomalies: - // . under Solaris, the interrupt lock gets acquired when doing - // profiling, so any lock could be held. // . it is also ok to acquire Safepoint_lock at the very end while we // already hold Terminator_lock - may happen because of periodic safepoints if (this->rank() != Mutex::native && this->rank() != Mutex::suspend_resume && locks != NULL && locks->rank() <= this->rank() && !SafepointSynchronize::is_at_safepoint() && - this != Interrupt_lock && this != ProfileVM_lock && !(this == Safepoint_lock && contains(locks, Terminator_lock) && SafepointSynchronize::is_synchronizing())) { new_owner->print_owned_locks(); diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index ae1d213b6e5..fa1aea26a55 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,6 @@ Mutex* JmethodIdCreation_lock = NULL; Mutex* JfieldIdCreation_lock = NULL; Monitor* JNICritical_lock = NULL; Mutex* JvmtiThreadState_lock = NULL; -Monitor* JvmtiPendingEvent_lock = NULL; Monitor* Heap_lock = NULL; Mutex* ExpandHeap_lock = NULL; Mutex* AdapterHandlerLibrary_lock = NULL; @@ -73,8 +72,6 @@ Monitor* CGC_lock = NULL; Monitor* STS_lock = NULL; Monitor* SLT_lock = NULL; Monitor* FullGCCount_lock = NULL; -Monitor* CMark_lock = NULL; -Mutex* CMRegionStack_lock = NULL; Mutex* SATB_Q_FL_lock = NULL; Monitor* SATB_Q_CBL_mon = NULL; Mutex* Shared_SATB_Q_lock = NULL; @@ -94,11 +91,8 @@ Mutex* MultiArray_lock = NULL; Monitor* Terminator_lock = NULL; Monitor* BeforeExit_lock = NULL; Monitor* Notify_lock = NULL; -Monitor* Interrupt_lock = NULL; -Monitor* ProfileVM_lock = NULL; Mutex* ProfilePrint_lock = NULL; Mutex* ExceptionCache_lock = NULL; -Monitor* ObjAllocPost_lock = NULL; Mutex* OsrList_lock = NULL; #ifndef PRODUCT @@ -184,8 +178,6 @@ void mutex_init() { } if (UseG1GC) { - def(CMark_lock , Monitor, nonleaf, true, Monitor::_safepoint_check_never); // coordinate concurrent mark thread - def(CMRegionStack_lock , Mutex, leaf, true, Monitor::_safepoint_check_never); def(SATB_Q_FL_lock , Mutex , special, true, Monitor::_safepoint_check_never); def(SATB_Q_CBL_mon , Monitor, nonleaf, true, Monitor::_safepoint_check_never); def(Shared_SATB_Q_lock , Mutex, nonleaf, true, Monitor::_safepoint_check_never); @@ -206,12 +198,10 @@ void mutex_init() { def(ParGCRareEvent_lock , Mutex , leaf , true, Monitor::_safepoint_check_sometimes); def(DerivedPointerTableGC_lock , Mutex, leaf, true, Monitor::_safepoint_check_never); def(CodeCache_lock , Mutex , special, true, Monitor::_safepoint_check_never); - def(Interrupt_lock , Monitor, special, true, Monitor::_safepoint_check_never); // used for interrupt processing def(RawMonitor_lock , Mutex, special, true, Monitor::_safepoint_check_never); def(OopMapCacheAlloc_lock , Mutex, leaf, true, Monitor::_safepoint_check_always); // used for oop_map_cache allocation. def(Patching_lock , Mutex , special, true, Monitor::_safepoint_check_never); // used for safepointing and code patching. - def(ObjAllocPost_lock , Monitor, special, false, Monitor::_safepoint_check_never); def(Service_lock , Monitor, special, true, Monitor::_safepoint_check_never); // used for service thread operations def(JmethodIdCreation_lock , Mutex , leaf, true, Monitor::_safepoint_check_always); // used for creating jmethodIDs. @@ -267,7 +257,6 @@ void mutex_init() { def(MultiArray_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // locks SymbolTable_lock def(JvmtiThreadState_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // Used by JvmtiThreadState/JvmtiEventController - def(JvmtiPendingEvent_lock , Monitor, nonleaf, false, Monitor::_safepoint_check_never); // Used by JvmtiCodeBlobEvents def(Management_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // used for JVM management def(Compile_lock , Mutex , nonleaf+3, true, Monitor::_safepoint_check_sometimes); @@ -277,7 +266,6 @@ void mutex_init() { def(MethodCompileQueue_lock , Monitor, nonleaf+4, true, Monitor::_safepoint_check_always); def(Debug2_lock , Mutex , nonleaf+4, true, Monitor::_safepoint_check_never); def(Debug3_lock , Mutex , nonleaf+4, true, Monitor::_safepoint_check_never); - def(ProfileVM_lock , Monitor, special, false, Monitor::_safepoint_check_never); // used for profiling of the VMThread def(CompileThread_lock , Monitor, nonleaf+5, false, Monitor::_safepoint_check_always); def(PeriodicTask_lock , Monitor, nonleaf+5, true, Monitor::_safepoint_check_sometimes); if (WhiteBoxAPI) { diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp index bbf6f143312..eccd3ca7314 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,6 @@ extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI metho extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers extern Monitor* JNICritical_lock; // a lock used while entering and exiting JNI critical regions, allows GC to sometimes get in extern Mutex* JvmtiThreadState_lock; // a lock on modification of JVMTI thread data -extern Monitor* JvmtiPendingEvent_lock; // a lock on the JVMTI pending events list extern Monitor* Heap_lock; // a lock on the heap extern Mutex* ExpandHeap_lock; // a lock on expanding the heap extern Mutex* AdapterHandlerLibrary_lock; // a lock on the AdapterHandlerLibrary @@ -68,8 +67,6 @@ extern Monitor* CGC_lock; // used for coordination betwee extern Monitor* STS_lock; // used for joining/leaving SuspendibleThreadSet. extern Monitor* SLT_lock; // used in CMS GC for acquiring PLL extern Monitor* FullGCCount_lock; // in support of "concurrent" full gc -extern Monitor* CMark_lock; // used for concurrent mark thread coordination -extern Mutex* CMRegionStack_lock; // used for protecting accesses to the CM region stack extern Mutex* SATB_Q_FL_lock; // Protects SATB Q // buffer free list. extern Monitor* SATB_Q_CBL_mon; // Protects SATB Q @@ -98,8 +95,6 @@ extern Mutex* MultiArray_lock; // a lock used to guard allocat extern Monitor* Terminator_lock; // a lock used to guard termination of the vm extern Monitor* BeforeExit_lock; // a lock used to guard cleanups and shutdown hooks extern Monitor* Notify_lock; // a lock used to synchronize the start-up of the vm -extern Monitor* Interrupt_lock; // a lock used for condition variable mediated interrupt processing -extern Monitor* ProfileVM_lock; // a lock used for profiling the VMThread extern Mutex* ProfilePrint_lock; // a lock used to serialize the printing of profiles extern Mutex* ExceptionCache_lock; // a lock used to synchronize exception cache updates extern Mutex* OsrList_lock; // a lock used to serialize access to OSR queues From c25e32cc70d50a0a9938f75b664ffb3eb887e5e0 Mon Sep 17 00:00:00 2001 From: Christian Tornqvist Date: Wed, 24 Feb 2016 16:34:25 -0500 Subject: [PATCH 044/129] 8150490: Update OS detection code to recognize Windows Server 2016 Reviewed-by: mgronlun, alanb, dholmes --- hotspot/src/os/windows/vm/os_windows.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 19d7319e7e1..72faa4b63a6 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -1668,8 +1668,7 @@ void os::win32::print_windows_version(outputStream* st) { if (is_workstation) { st->print("10"); } else { - // The server version name of Windows 10 is not known at this time - st->print("%d.%d", major_version, minor_version); + st->print("Server 2016"); } break; From 8961912c749a2542a391c7e0946dbb74de7f7b01 Mon Sep 17 00:00:00 2001 From: Derek White Date: Wed, 24 Feb 2016 09:25:39 +0100 Subject: [PATCH 045/129] 8134992: vm/gc/compact/Compact_InternedStrings_Strings failed due to a malloc() failure Reviewed-by: mgerdin, brutisso --- hotspot/src/share/vm/gc/shared/collectedHeap.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp index 9bba8daf55e..f132d75e860 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp @@ -405,7 +405,9 @@ size_t CollectedHeap::max_tlab_size() const { oop CollectedHeap::new_store_pre_barrier(JavaThread* thread, oop new_obj) { // If a previous card-mark was deferred, flush it now. flush_deferred_store_barrier(thread); - if (can_elide_initializing_store_barrier(new_obj)) { + if (can_elide_initializing_store_barrier(new_obj) || + new_obj->is_typeArray()) { + // Arrays of non-references don't need a pre-barrier. // The deferred_card_mark region should be empty // following the flush above. assert(thread->deferred_card_mark().is_empty(), "Error"); From 306361b2920760ba73a4075836b30be8b54066e6 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Mon, 7 Mar 2016 13:45:38 -0500 Subject: [PATCH 046/129] 8139474: -release 7 -verbose causes Javac exception Reviewed-by: jjg --- .../com/sun/tools/javac/code/ClassFinder.java | 27 ++++++++-------- .../sun/tools/javac/file/RelativePath.java | 3 +- .../JavacProcessingEnvironment.java | 15 +++++---- .../T8139474/DashRelease7DashVerboseTest.java | 31 +++++++++++++++++++ 4 files changed, 54 insertions(+), 22 deletions(-) create mode 100644 langtools/test/tools/javac/T8139474/DashRelease7DashVerboseTest.java diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java index 0c602c4c16a..466a41d7635 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ package com.sun.tools.javac.code; import java.io.IOException; -import java.io.File; +import java.nio.file.Path; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; @@ -45,7 +45,6 @@ import com.sun.tools.javac.code.Symbol.CompletionFailure; import com.sun.tools.javac.code.Symbol.PackageSymbol; import com.sun.tools.javac.code.Symbol.TypeSymbol; import com.sun.tools.javac.comp.Annotate; -import com.sun.tools.javac.comp.Enter; import com.sun.tools.javac.file.JRTIndex; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.jvm.ClassReader; @@ -535,25 +534,25 @@ public class ClassFinder { if (fileManager instanceof StandardJavaFileManager) { StandardJavaFileManager fm = (StandardJavaFileManager)fileManager; if (haveSourcePath && wantSourceFiles) { - List path = List.nil(); - for (File file : fm.getLocation(SOURCE_PATH)) { - path = path.prepend(file); + List path = List.nil(); + for (Path sourcePath : fm.getLocationAsPaths(SOURCE_PATH)) { + path = path.prepend(sourcePath); } log.printVerbose("sourcepath", path.reverse().toString()); } else if (wantSourceFiles) { - List path = List.nil(); - for (File file : fm.getLocation(CLASS_PATH)) { - path = path.prepend(file); + List path = List.nil(); + for (Path classPath : fm.getLocationAsPaths(CLASS_PATH)) { + path = path.prepend(classPath); } log.printVerbose("sourcepath", path.reverse().toString()); } if (wantClassFiles) { - List path = List.nil(); - for (File file : fm.getLocation(PLATFORM_CLASS_PATH)) { - path = path.prepend(file); + List path = List.nil(); + for (Path platformPath : fm.getLocationAsPaths(PLATFORM_CLASS_PATH)) { + path = path.prepend(platformPath); } - for (File file : fm.getLocation(CLASS_PATH)) { - path = path.prepend(file); + for (Path classPath : fm.getLocationAsPaths(CLASS_PATH)) { + path = path.prepend(classPath); } log.printVerbose("classpath", path.reverse().toString()); } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RelativePath.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RelativePath.java index 59d79df9ac1..3e541b884f1 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RelativePath.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RelativePath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package com.sun.tools.javac.file; -import java.io.File; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.InvalidPathException; diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 94ed6da8d11..9165f9b2cb9 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -31,6 +31,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URL; +import java.nio.file.Path; import java.util.*; import java.util.regex.*; import java.util.stream.Collectors; @@ -42,6 +43,7 @@ import javax.lang.model.util.*; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; + import static javax.tools.StandardLocation.*; import com.sun.source.util.TaskEvent; @@ -79,6 +81,7 @@ import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Names; import com.sun.tools.javac.util.Options; import com.sun.tools.javac.util.ServiceLoader; + import static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING; import static com.sun.tools.javac.code.Kinds.Kind.*; import static com.sun.tools.javac.main.Option.*; @@ -317,9 +320,9 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea if (fileManager instanceof JavacFileManager) { StandardJavaFileManager standardFileManager = (JavacFileManager) fileManager; - Iterable workingPath = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH) - ? standardFileManager.getLocation(ANNOTATION_PROCESSOR_PATH) - : standardFileManager.getLocation(CLASS_PATH); + Iterable workingPath = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH) + ? standardFileManager.getLocationAsPaths(ANNOTATION_PROCESSOR_PATH) + : standardFileManager.getLocationAsPaths(CLASS_PATH); if (needClassLoader(options.get(PROCESSOR), workingPath) ) handleException(key, e); @@ -1298,14 +1301,14 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea * Called retroactively to determine if a class loader was required, * after we have failed to create one. */ - private boolean needClassLoader(String procNames, Iterable workingpath) { + private boolean needClassLoader(String procNames, Iterable workingpath) { if (procNames != null) return true; URL[] urls = new URL[1]; - for(File pathElement : workingpath) { + for(Path pathElement : workingpath) { try { - urls[0] = pathElement.toURI().toURL(); + urls[0] = pathElement.toUri().toURL(); if (ServiceProxy.hasService(Processor.class, urls)) return true; } catch (MalformedURLException ex) { diff --git a/langtools/test/tools/javac/T8139474/DashRelease7DashVerboseTest.java b/langtools/test/tools/javac/T8139474/DashRelease7DashVerboseTest.java new file mode 100644 index 00000000000..5e0c19cddb3 --- /dev/null +++ b/langtools/test/tools/javac/T8139474/DashRelease7DashVerboseTest.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * bug 8139474 + * @summary -release 7 -verbose causes Javac exception + * @compile -release 7 -verbose DashRelease7DashVerboseTest.java +*/ + +public class DashRelease7DashVerboseTest {} From 528c1dfc4ee4a8b2d98395949ccddf0b35d72f87 Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Tue, 8 Mar 2016 11:37:00 -0800 Subject: [PATCH 047/129] 8148187: Remove OS X-specific com.apple.concurrent package Removed jdk.deploy.osx module (including com.apple.concurrent) Reviewed-by: alanb, erikj, mchung --- .../share/classes/com/sun/tools/javac/resources/ct.properties | 1 - .../jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/ct.properties b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/ct.properties index 135646a3fdb..b94ead7665b 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/ct.properties +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/ct.properties @@ -1,6 +1,5 @@ apple.laf.*: hidden apple.security.*: hidden -com.apple.concurrent.*: hidden com.apple.eawt.*: hidden com.apple.eawt.event.*: hidden com.apple.eio.*: hidden diff --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java index bd70ec841b1..1c45a2fd54f 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java @@ -38,7 +38,7 @@ enum Profile { "jdk.httpserver", "jdk.security.auth", "jdk.naming.dns", "jdk.naming.rmi", "jdk.management"), - FULL_JRE("Full JRE", 4, "java.se", "jdk.deploy.osx", "jdk.charsets", + FULL_JRE("Full JRE", 4, "java.se", "jdk.charsets", "jdk.crypto.ec", "jdk.crypto.pkcs11", "jdk.crypto.mscapi", "jdk.crypto.ucrypto", "jdk.jvmstat", "jdk.localedata", "jdk.scripting.nashorn", "jdk.zipfs"); From 51ea08084f757c2f33b9815a97b4328a3b64b1dc Mon Sep 17 00:00:00 2001 From: Robert Field Date: Tue, 8 Mar 2016 11:53:35 -0800 Subject: [PATCH 048/129] 8148316: jshell tool: Configurable output format 8148317: jshell tool: unify commands into /set 8149524: JShell: CompletenessAnalysis fails on class Case, E2 extends Enum, E3 extends Enum> {} Reviewed-by: jlahoda --- .../internal/jshell/tool/ArgTokenizer.java | 271 +++++ .../jdk/internal/jshell/tool/Feedback.java | 1049 +++++++++++++++++ .../jdk/internal/jshell/tool/JShellTool.java | 778 ++++++------ .../jdk/jshell/CompletenessAnalyzer.java | 4 +- .../jdk/jshell/CommandCompletionTest.java | 8 +- .../test/jdk/jshell/CompletenessTest.java | 4 +- .../test/jdk/jshell/ExternalEditorTest.java | 8 +- .../test/jdk/jshell/ReplToolTesting.java | 43 +- langtools/test/jdk/jshell/ToolBasicTest.java | 97 +- langtools/test/jdk/jshell/ToolFormatTest.java | 159 +++ 10 files changed, 1996 insertions(+), 425 deletions(-) create mode 100644 langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ArgTokenizer.java create mode 100644 langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java create mode 100644 langtools/test/jdk/jshell/ToolFormatTest.java diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ArgTokenizer.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ArgTokenizer.java new file mode 100644 index 00000000000..2e86d9de290 --- /dev/null +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ArgTokenizer.java @@ -0,0 +1,271 @@ +/* + * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.jshell.tool; + +import java.util.Arrays; +import java.util.stream.Stream; + +/** + * Parse command arguments, derived from StreamTokenizer by + * @author James Gosling + */ +class ArgTokenizer { + + private final String str; + private final int length; + private int next = 0; + private char buf[] = new char[20]; + private int mark; + + private final byte ctype[] = new byte[256]; + private static final byte CT_ALPHA = 0; + private static final byte CT_WHITESPACE = 1; + private static final byte CT_QUOTE = 8; + + private String sval; + private boolean isQuoted = false; + + ArgTokenizer(String arg) { + this.str = arg; + this.length = arg.length(); + quoteChar('"'); + quoteChar('\''); + whitespaceChars(0x09, 0x0D); + whitespaceChars(0x1C, 0x20); + whitespaceChars(0x85, 0x85); + whitespaceChars(0xA0, 0xA0); + } + + String next() { + nextToken(); + return sval; + } + + String[] next(String... strings) { + return next(Arrays.stream(strings)); + } + + String[] next(Stream stream) { + nextToken(); + if (sval == null) { + return null; + } + String[] matches = stream + .filter(s -> s.startsWith(sval)) + .toArray(size -> new String[size]); + return matches; + } + + String val() { + return sval; + } + + boolean isQuoted() { + return isQuoted; + } + + String whole() { + return str; + } + + void mark() { + mark = next; + } + + void rewind() { + next = mark; + } + + /** + * Reads a single character. + * + * @return The character read, or -1 if the end of the stream has been + * reached + */ + private int read() { + if (next >= length) { + return -1; + } + return str.charAt(next++); + } + + /** + * Specifies that all characters c in the range + * low <= c <= high + * are white space characters. White space characters serve only to + * separate tokens in the input stream. + * + *

Any other attribute settings for the characters in the specified + * range are cleared. + * + * @param low the low end of the range. + * @param hi the high end of the range. + */ + private void whitespaceChars(int low, int hi) { + if (low < 0) + low = 0; + if (hi >= ctype.length) + hi = ctype.length - 1; + while (low <= hi) + ctype[low++] = CT_WHITESPACE; + } + + /** + * Specifies that matching pairs of this character delimit string + * constants in this tokenizer. + *

+ * If a string quote character is encountered, then a string is + * recognized, consisting of all characters after (but not including) + * the string quote character, up to (but not including) the next + * occurrence of that same string quote character, or a line + * terminator, or end of file. The usual escape sequences such as + * {@code "\u005Cn"} and {@code "\u005Ct"} are recognized and + * converted to single characters as the string is parsed. + * + *

Any other attribute settings for the specified character are cleared. + * + * @param ch the character. + */ + private void quoteChar(int ch) { + if (ch >= 0 && ch < ctype.length) + ctype[ch] = CT_QUOTE; + } + + private int unicode2ctype(int c) { + switch (c) { + case 0x1680: + case 0x180E: + case 0x200A: + case 0x202F: + case 0x205F: + case 0x3000: + return CT_WHITESPACE; + default: + return CT_ALPHA; + } + } + + /** + * Parses the next token of this tokenizer. + */ + public void nextToken() { + byte ct[] = ctype; + int c; + int lctype; + sval = null; + isQuoted = false; + + do { + c = read(); + if (c < 0) { + return; + } + lctype = (c < 256) ? ct[c] : unicode2ctype(c); + } while (lctype == CT_WHITESPACE); + + if (lctype == CT_ALPHA) { + int i = 0; + do { + if (i >= buf.length) { + buf = Arrays.copyOf(buf, buf.length * 2); + } + buf[i++] = (char) c; + c = read(); + lctype = c < 0 ? CT_WHITESPACE : (c < 256)? ct[c] : unicode2ctype(c); + } while (lctype == CT_ALPHA); + if (c >= 0) --next; // push last back + sval = String.copyValueOf(buf, 0, i); + return; + } + + if (lctype == CT_QUOTE) { + int quote = c; + int i = 0; + /* Invariants (because \Octal needs a lookahead): + * (i) c contains char value + * (ii) d contains the lookahead + */ + int d = read(); + while (d >= 0 && d != quote) { + if (d == '\\') { + c = read(); + int first = c; /* To allow \377, but not \477 */ + if (c >= '0' && c <= '7') { + c = c - '0'; + int c2 = read(); + if ('0' <= c2 && c2 <= '7') { + c = (c << 3) + (c2 - '0'); + c2 = read(); + if ('0' <= c2 && c2 <= '7' && first <= '3') { + c = (c << 3) + (c2 - '0'); + d = read(); + } else + d = c2; + } else + d = c2; + } else { + switch (c) { + case 'a': + c = 0x7; + break; + case 'b': + c = '\b'; + break; + case 'f': + c = 0xC; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'v': + c = 0xB; + break; + } + d = read(); + } + } else { + c = d; + d = read(); + } + if (i >= buf.length) { + buf = Arrays.copyOf(buf, buf.length * 2); + } + buf[i++] = (char)c; + } + + if (d == quote) { + isQuoted = true; + } + sval = String.copyValueOf(buf, 0, i); + } + } +} diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java new file mode 100644 index 00000000000..9089dfc86aa --- /dev/null +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java @@ -0,0 +1,1049 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.jshell.tool; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Feedback customization support + * + * @author Robert Field + */ +class Feedback { + + // Patern for substituted fields within a customized format string + private static final Pattern FIELD_PATTERN = Pattern.compile("\\{(.*?)\\}"); + + // Current mode + private Mode mode = new Mode("", false); // initial value placeholder during start-up + + // Mapping of mode names to mode modes + private final Map modeMap = new HashMap<>(); + + public boolean shouldDisplayCommandFluff() { + return mode.commandFluff; + } + + public String getPre() { + return mode.pre; + } + + public String getPost() { + return mode.post; + } + + public String getErrorPre() { + return mode.errorPre; + } + + public String getErrorPost() { + return mode.errorPost; + } + + public String getFormat(FormatCase fc, FormatWhen fw, FormatAction fa, FormatResolve fr, + boolean hasName, boolean hasType, boolean hasResult) { + return mode.getFormat(fc, fw, fa, fr, hasName, hasType, hasResult); + } + + public String getPrompt(String nextId) { + return mode.getPrompt(nextId); + } + + public String getContinuationPrompt(String nextId) { + return mode.getContinuationPrompt(nextId); + } + + public boolean setFeedback(JShellTool tool, ArgTokenizer at) { + return new FormatSetter(tool, at).setFeedback(); + } + + public boolean setField(JShellTool tool, ArgTokenizer at) { + return new FormatSetter(tool, at).setField(); + } + + public boolean setFormat(JShellTool tool, ArgTokenizer at) { + return new FormatSetter(tool, at).setFormat(); + } + + public boolean setNewMode(JShellTool tool, ArgTokenizer at) { + return new FormatSetter(tool, at).setNewMode(); + } + + public boolean setPrompt(JShellTool tool, ArgTokenizer at) { + return new FormatSetter(tool, at).setPrompt(); + } + + public void printFeedbackHelp(JShellTool tool) { + new FormatSetter(tool, null).printFeedbackHelp(); + } + + public void printFieldHelp(JShellTool tool) { + new FormatSetter(tool, null).printFieldHelp(); + } + + public void printFormatHelp(JShellTool tool) { + new FormatSetter(tool, null).printFormatHelp(); + } + + public void printNewModeHelp(JShellTool tool) { + new FormatSetter(tool, null).printNewModeHelp(); + } + + public void printPromptHelp(JShellTool tool) { + new FormatSetter(tool, null).printPromptHelp(); + } + + /** + * Holds all the context of a mode mode + */ + private class Mode { + + // Use name of mode mode + + final String name; + + // Display command verification/information + final boolean commandFluff; + + // event cases: class, method + final EnumMap>> cases; + + // action names: add. modified, replaced, ... + final EnumMap> actions; + + // resolution status description format with %s for unresolved + final EnumMap> resolves; + + // primary snippet vs update + final EnumMap whens; + + // fixed map of how to get format string for a field, given a specific formatting contet + final EnumMap> fields; + + // format wrappers for name, type, and result + String fname = "%s"; + String ftype = "%s"; + String fresult = "%s"; + + // start and end, also used by hard-coded output + String pre = "| "; + String post = "\n"; + String errorPre = "| Error: "; + String errorPost = "\n"; + + String prompt = "\n-> "; + String continuationPrompt = ">> "; + + /** + * The context of a specific mode to potentially display. + */ + class Context { + + final FormatCase fc; + final FormatAction fa; + final FormatResolve fr; + final FormatWhen fw; + final boolean hasName; + final boolean hasType; + final boolean hasResult; + + Context(FormatCase fc, FormatWhen fw, FormatAction fa, FormatResolve fr, + boolean hasName, boolean hasType, boolean hasResult) { + this.fc = fc; + this.fa = fa; + this.fr = fr; + this.fw = fw; + this.hasName = hasName; + this.hasType = hasType; + this.hasResult = hasResult; + } + + String when() { + return whens.get(fw); + } + + String action() { + return actions.get(fa).get(fw); + } + + String resolve() { + return String.format(resolves.get(fr).get(fw), FormatField.RESOLVE.form); + } + + String name() { + return hasName + ? String.format(fname, FormatField.NAME.form) + : ""; + } + + String type() { + return hasType + ? String.format(ftype, FormatField.TYPE.form) + : ""; + } + + String result() { + return hasResult + ? String.format(fresult, FormatField.RESULT.form) + : ""; + } + + /** + * Lookup format based on case, action, and whether it update. + * Replace fields with context specific formats. + * + * @return format string + */ + String format() { + String format = cases.get(fc).get(fa).get(fw); + if (format == null) { + return ""; + } + Matcher m = FIELD_PATTERN.matcher(format); + StringBuffer sb = new StringBuffer(format.length()); + while (m.find()) { + String fieldName = m.group(1).toUpperCase(Locale.US); + String sub = null; + for (FormatField f : FormatField.values()) { + if (f.name().startsWith(fieldName)) { + sub = fields.get(f).apply(this); + break; + } + } + if (sub != null) { + m.appendReplacement(sb, Matcher.quoteReplacement(sub)); + } + } + m.appendTail(sb); + return sb.toString(); + } + } + + { + // set fixed mappings of fields + fields = new EnumMap<>(FormatField.class); + fields.put(FormatField.WHEN, c -> c.when()); + fields.put(FormatField.ACTION, c -> c.action()); + fields.put(FormatField.RESOLVE, c -> c.resolve()); + fields.put(FormatField.NAME, c -> c.name()); + fields.put(FormatField.TYPE, c -> c.type()); + fields.put(FormatField.RESULT, c -> c.result()); + fields.put(FormatField.PRE, c -> pre); + fields.put(FormatField.POST, c -> post); + fields.put(FormatField.ERRORPRE, c -> errorPre); + fields.put(FormatField.ERRORPOST, c -> errorPost); + } + + /** + * Set up an empty mode. + * + * @param name + * @param commandFluff True if should display command fluff messages + */ + Mode(String name, boolean commandFluff) { + this.name = name; + this.commandFluff = commandFluff; + cases = new EnumMap<>(FormatCase.class); + for (FormatCase fc : FormatCase.values()) { + EnumMap> ac = new EnumMap<>(FormatAction.class); + cases.put(fc, ac); + for (FormatAction fa : FormatAction.values()) { + EnumMap aw = new EnumMap<>(FormatWhen.class); + ac.put(fa, aw); + for (FormatWhen fw : FormatWhen.values()) { + aw.put(fw, ""); + } + } + } + + actions = new EnumMap<>(FormatAction.class); + for (FormatAction fa : FormatAction.values()) { + EnumMap afw = new EnumMap<>(FormatWhen.class); + actions.put(fa, afw); + for (FormatWhen fw : FormatWhen.values()) { + afw.put(fw, fa.name() + "-" + fw.name()); + } + } + + resolves = new EnumMap<>(FormatResolve.class); + for (FormatResolve fr : FormatResolve.values()) { + EnumMap arw = new EnumMap<>(FormatWhen.class); + resolves.put(fr, arw); + for (FormatWhen fw : FormatWhen.values()) { + arw.put(fw, fr.name() + "-" + fw.name() + ": %s"); + } + } + + whens = new EnumMap<>(FormatWhen.class); + for (FormatWhen fw : FormatWhen.values()) { + whens.put(fw, fw.name()); + } + } + + /** + * Set up a copied mode. + * + * @param name + * @param commandFluff True if should display command fluff messages + * @param m Mode to copy + */ + Mode(String name, boolean commandFluff, Mode m) { + this.name = name; + this.commandFluff = commandFluff; + cases = new EnumMap<>(FormatCase.class); + for (FormatCase fc : FormatCase.values()) { + EnumMap> ac = new EnumMap<>(FormatAction.class); + EnumMap> mc = m.cases.get(fc); + cases.put(fc, ac); + for (FormatAction fa : FormatAction.values()) { + EnumMap aw = new EnumMap<>(mc.get(fa)); + ac.put(fa, aw); + } + } + + actions = new EnumMap<>(FormatAction.class); + for (FormatAction fa : FormatAction.values()) { + EnumMap afw = new EnumMap<>(m.actions.get(fa)); + actions.put(fa, afw); + } + + resolves = new EnumMap<>(FormatResolve.class); + for (FormatResolve fr : FormatResolve.values()) { + EnumMap arw = new EnumMap<>(m.resolves.get(fr)); + resolves.put(fr, arw); + } + + whens = new EnumMap<>(m.whens); + + this.fname = m.fname; + this.ftype = m.ftype; + this.fresult = m.fresult; + this.pre = m.pre; + this.post = m.post; + this.errorPre = m.errorPre; + this.errorPost = m.errorPost; + this.prompt = m.prompt; + this.continuationPrompt = m.continuationPrompt; + } + + String getFormat(FormatCase fc, FormatWhen fw, FormatAction fa, FormatResolve fr, + boolean hasName, boolean hasType, boolean hasResult) { + Context context = new Context(fc, fw, fa, fr, + hasName, hasType, hasResult); + return context.format(); + } + + void setCases(String format, Collection cc, Collection ca, Collection cw) { + for (FormatCase fc : cc) { + EnumMap> ma = cases.get(fc); + for (FormatAction fa : ca) { + EnumMap mw = ma.get(fa); + for (FormatWhen fw : cw) { + mw.put(fw, format); + } + } + } + } + + void setActions(String format, Collection ca, Collection cw) { + for (FormatAction fa : ca) { + EnumMap mw = actions.get(fa); + for (FormatWhen fw : cw) { + mw.put(fw, format); + } + } + } + + void setResolves(String format, Collection cr, Collection cw) { + for (FormatResolve fr : cr) { + EnumMap mw = resolves.get(fr); + for (FormatWhen fw : cw) { + mw.put(fw, format); + } + } + } + + void setWhens(String format, Collection cw) { + for (FormatWhen fw : cw) { + whens.put(fw, format); + } + } + + void setName(String s) { + fname = s; + } + + void setType(String s) { + ftype = s; + } + + void setResult(String s) { + fresult = s; + } + + void setPre(String s) { + pre = s; + } + + void setPost(String s) { + post = s; + } + + void setErrorPre(String s) { + errorPre = s; + } + + void setErrorPost(String s) { + errorPost = s; + } + + String getPre() { + return pre; + } + + String getPost() { + return post; + } + + String getErrorPre() { + return errorPre; + } + + String getErrorPost() { + return errorPost; + } + + void setPrompts(String prompt, String continuationPrompt) { + this.prompt = prompt; + this.continuationPrompt = continuationPrompt; + } + + String getPrompt(String nextId) { + return String.format(prompt, nextId); + } + + String getContinuationPrompt(String nextId) { + return String.format(continuationPrompt, nextId); + } + } + + /** + * The brace delimited substitutions + */ + public enum FormatField { + WHEN, + ACTION, + RESOLVE("%1$s"), + NAME("%2$s"), + TYPE("%3$s"), + RESULT("%4$s"), + PRE, + POST, + ERRORPRE, + ERRORPOST; + String form; + + FormatField(String s) { + this.form = s; + } + + FormatField() { + this.form = null; + } + } + + /** + * The event cases + */ + public enum FormatCase { + IMPORT("import declaration: {action} {name}"), + CLASS("class, interface, enum, or annotation declaration: {action} {name} {resolve}"), + INTERFACE("class, interface, enum, or annotation declaration: {action} {name} {resolve}"), + ENUM("class, interface, enum, or annotation declaration: {action} {name} {resolve}"), + ANNOTATION("annotation interface declaration: {action} {name} {resolve}"), + METHOD("method declaration: {action} {name} {type}==parameter-types {resolve}"), + VARDECL("variable declaration: {action} {name} {type} {resolve}"), + VARDECLRECOVERABLE("recoverably failed variable declaration: {action} {name} {resolve}"), + VARINIT("variable declaration with init: {action} {name} {type} {resolve} {result}"), + VARRESET("variable reset on update: {action} {name}"), + EXPRESSION("expression: {action}=='Saved to scratch variable' {name} {type} {result}"), + VARVALUE("variable value expression: {action} {name} {type} {result}"), + ASSIGNMENT("assign variable: {action} {name} {type} {result}"), + STATEMENT("statement: {action}"); + String doc; + + private FormatCase(String doc) { + this.doc = doc; + } + } + + /** + * The event actions + */ + public enum FormatAction { + ADDED("snippet has been added"), + MODIFIED("an existing snippet has been modified"), + REPLACED("an existing snippet has been replaced with a new snippet"), + OVERWROTE("an existing snippet has been overwritten"), + DROPPED("snippet has been dropped"), + REJECTED("snippet has failed and been rejected"); + String doc; + + private FormatAction(String doc) { + this.doc = doc; + } + } + + /** + * When the event occurs: primary or update + */ + public enum FormatWhen { + PRIMARY("the entered snippet"), + UPDATE("an update to a dependent snippet"); + String doc; + + private FormatWhen(String doc) { + this.doc = doc; + } + } + + /** + * Resolution problems with event + */ + public enum FormatResolve { + OK("resolved correctly"), + DEFINED("defined despite recoverably unresolved references"), + NOTDEFINED("not defined because of recoverably unresolved references"); + String doc; + + private FormatResolve(String doc) { + this.doc = doc; + } + } + + // Class used to set custom eval output formats + // For both /set format and /set field -- Parse arguments, setting custom format, or printing error + private class FormatSetter { + + private final ArgTokenizer at; + private final JShellTool tool; + boolean valid = true; + + class Case, E2 extends Enum, E3 extends Enum> { + + Set e1; + Set e2; + Set e3; + + Case(Set e1, Set e2, Set e3) { + this.e1 = e1; + this.e2 = e2; + this.e3 = e3; + } + + Case(Set e1, Set e2) { + this.e1 = e1; + this.e2 = e2; + } + } + + FormatSetter(JShellTool tool, ArgTokenizer at) { + this.tool = tool; + this.at = at; + } + + void hard(String format, Object... args) { + tool.hard(format, args); + } + + > void hardEnums(EnumSet es, Function e2s) { + hardPairs(es.stream(), ev -> ev.name().toLowerCase(Locale.US), e2s); + } + + void hardPairs(Stream stream, Function a, Function b) { + tool.hardPairs(stream, a, b); + } + + void fluff(String format, Object... args) { + tool.fluff(format, args); + } + + void error(String format, Object... args) { + tool.error(format, args); + } + + void errorat(String format, Object... args) { + Object[] a2 = Arrays.copyOf(args, args.length + 1); + a2[args.length] = at.whole(); + tool.error(format + " -- /set %s", a2); + } + + void fluffRaw(String format, Object... args) { + tool.fluffRaw(format, args); + } + + // For /set prompt "" "" + boolean setPrompt() { + Mode m = nextMode(); + String prompt = nextFormat(); + String continuationPrompt = nextFormat(); + if (valid) { + m.setPrompts(prompt, continuationPrompt); + } else { + fluff("See '/help /set prompt' for help"); + } + return valid; + } + + // For /set newmode [command|quiet []] + boolean setNewMode() { + String umode = at.next(); + if (umode == null) { + errorat("Expected new feedback mode"); + valid = false; + } + if (modeMap.containsKey(umode)) { + errorat("Expected a new feedback mode name. %s is a known feedback mode", umode); + valid = false; + } + String[] fluffOpt = at.next("command", "quiet"); + boolean fluff = fluffOpt == null || fluffOpt.length != 1 || "command".equals(fluffOpt[0]); + if (fluffOpt != null && fluffOpt.length != 1) { + errorat("Specify either 'command' or 'quiet'"); + valid = false; + } + Mode om = null; + String omode = at.next(); + if (omode != null) { + om = toMode(omode); + } + if (valid) { + Mode nm = (om != null) + ? new Mode(umode, fluff, om) + : new Mode(umode, fluff); + modeMap.put(umode, nm); + fluff("Created new feedback mode: %s", nm.name); + } else { + fluff("See '/help /set newmode' for help"); + } + return valid; + } + + // For /set feedback + boolean setFeedback() { + Mode m = nextMode(); + if (valid && m != null) { + mode = m; + fluff("Feedback mode: %s", mode.name); + } else { + fluff("See '/help /set feedback' for help"); + } + return valid; + } + + // For /set format "" ... + boolean setFormat() { + Mode m = nextMode(); + String format = nextFormat(); + if (valid) { + List> specs = new ArrayList<>(); + String s; + while ((s = at.next()) != null) { + String[] d = s.split("-"); + specs.add(new Case<>( + parseFormatCase(d, 0), + parseFormatAction(d, 1), + parseFormatWhen(d, 2) + )); + } + if (valid && specs.isEmpty()) { + errorat("At least one selector required"); + valid = false; + } + if (valid) { + // set the format in the specified cases + specs.stream() + .forEach(c -> m.setCases(format, c.e1, c.e2, c.e3)); + } + } + if (!valid) { + fluff("See '/help /set format' for help"); + } + return valid; + } + + // For /set field mode "" ... + boolean setField() { + Mode m = nextMode(); + String fieldName = at.next(); + FormatField field = parseFormatSelector(fieldName, EnumSet.allOf(FormatField.class), "field"); + String format = nextFormat(); + if (valid) { + switch (field) { + case ACTION: { + List> specs = new ArrayList<>(); + String s; + while ((s = at.next()) != null) { + String[] d = s.split("-"); + specs.add(new Case<>( + parseFormatAction(d, 0), + parseFormatWhen(d, 1) + )); + } + if (valid && specs.isEmpty()) { + errorat("At least one selector required"); + valid = false; + } + if (valid) { + // set the format of the specified actions + specs.stream() + .forEach(c -> m.setActions(format, c.e1, c.e2)); + } + break; + } + case RESOLVE: { + List> specs = new ArrayList<>(); + String s; + while ((s = at.next()) != null) { + String[] d = s.split("-"); + specs.add(new Case<>( + parseFormatResolve(d, 0), + parseFormatWhen(d, 1) + )); + } + if (valid && specs.isEmpty()) { + errorat("At least one selector required"); + valid = false; + } + if (valid) { + // set the format of the specified resolves + specs.stream() + .forEach(c -> m.setResolves(format, c.e1, c.e2)); + } + break; + } + case WHEN: { + List> specs = new ArrayList<>(); + String s; + while ((s = at.next()) != null) { + String[] d = s.split("-"); + specs.add(new Case<>( + parseFormatWhen(d, 1), + null + )); + } + if (valid && specs.isEmpty()) { + errorat("At least one selector required"); + valid = false; + } + if (valid) { + // set the format of the specified whens + specs.stream() + .forEach(c -> m.setWhens(format, c.e1)); + } + break; + } + case NAME: { + m.setName(format); + break; + } + case TYPE: { + m.setType(format); + break; + } + case RESULT: { + m.setResult(format); + break; + } + case PRE: { + m.setPre(format); + break; + } + case POST: { + m.setPost(format); + break; + } + case ERRORPRE: { + m.setErrorPre(format); + break; + } + case ERRORPOST: { + m.setErrorPost(format); + break; + } + } + } + if (!valid) { + fluff("See '/help /set field' for help"); + } + return valid; + } + + Mode nextMode() { + String umode = at.next(); + return toMode(umode); + } + + Mode toMode(String umode) { + if (umode == null) { + errorat("Expected a feedback mode"); + valid = false; + return null; + } + Mode m = modeMap.get(umode); + if (m != null) { + return m; + } + // Failing an exact match, go searching + Mode[] matches = modeMap.entrySet().stream() + .filter(e -> e.getKey().startsWith(umode)) + .map(e -> e.getValue()) + .toArray(size -> new Mode[size]); + if (matches.length == 1) { + return matches[0]; + } else { + valid = false; + if (matches.length == 0) { + errorat("Does not match any current feedback mode: %s", umode); + } else { + errorat("Matchs more then one current feedback mode: %s", umode); + } + fluff("The feedback mode should be one of the following:"); + modeMap.keySet().stream() + .forEach(mk -> fluff(" %s", mk)); + fluff("You may also use just enough letters to make it unique."); + return null; + } + } + + // Test if the format string is correctly + final String nextFormat() { + String format = at.next(); + if (format == null) { + errorat("Expected format missing"); + valid = false; + return null; + } + if (!at.isQuoted()) { + errorat("Format '%s' must be quoted", format); + valid = false; + return null; + } + return format; + } + + final Set parseFormatCase(String[] s, int i) { + return parseFormatSelectorStar(s, i, FormatCase.class, EnumSet.allOf(FormatCase.class), "case"); + } + + final Set parseFormatAction(String[] s, int i) { + return parseFormatSelectorStar(s, i, FormatAction.class, + EnumSet.of(FormatAction.ADDED, FormatAction.MODIFIED, FormatAction.REPLACED), "action"); + } + + final Set parseFormatResolve(String[] s, int i) { + return parseFormatSelectorStar(s, i, FormatResolve.class, + EnumSet.of(FormatResolve.DEFINED, FormatResolve.NOTDEFINED), "resolve"); + } + + final Set parseFormatWhen(String[] s, int i) { + return parseFormatSelectorStar(s, i, FormatWhen.class, EnumSet.of(FormatWhen.PRIMARY), "when"); + } + + /** + * In a selector x-y-z , parse x, y, or z -- whether they are missing, + * or a comma separated list of identifiers and stars. + * + * @param The enum this selector should belong to + * @param sa The array of selector strings + * @param i The index of which selector string to use + * @param klass The class of the enum that should be used + * @param defaults The set of enum values to use if the selector is + * missing + * @return The set of enum values specified by this selector + */ + final > Set parseFormatSelectorStar(String[] sa, int i, Class klass, EnumSet defaults, String label) { + String s = sa.length > i + ? sa[i] + : null; + if (s == null || s.isEmpty()) { + return defaults; + } + Set set = EnumSet.noneOf(klass); + EnumSet values = EnumSet.allOf(klass); + for (String as : s.split(",")) { + if (as.equals("*")) { + set.addAll(values); + } else if (!as.isEmpty()) { + set.add(parseFormatSelector(as, values, label)); + } + } + return set; + } + + /** + * In a x-y-a,b selector, parse an x, y, a, or b -- that is an + * identifier + * + * @param The enum this selector should belong to + * @param s The string to parse: x, y, or z + * @param values The allowed of this enum + * @return The enum value + */ + final > E parseFormatSelector(String s, EnumSet values, String label) { + if (s == null) { + valid = false; + return null; + } + String u = s.toUpperCase(Locale.US); + for (E c : values) { + if (c.name().startsWith(u)) { + return c; + } + } + + errorat("Not a valid %s: %s, must be one of: %s", label, s, + values.stream().map(v -> v.name().toLowerCase(Locale.US)).collect(Collectors.joining(" "))); + valid = false; + return values.iterator().next(); + } + + final void printFormatHelp() { + hard("Set the format for reporting a snippet event."); + hard(""); + hard("/set format \"\" ..."); + hard(""); + hard("Where is the name of a previously defined feedback mode -- see '/help /set newmode'."); + hard("Where is a quoted string which will have these field substitutions:"); + hard(" {action} == The action, e.g.: Added, Modified, Assigned, ..."); + hard(" {name} == The name, e.g.: the variable name, ..."); + hard(" {type} == The type name"); + hard(" {resolve} == Unresolved info, e.g.: ', however, it cannot be invoked until'"); + hard(" {result} == The result value"); + hard(" {when} == The entered snippet or a resultant update"); + hard(" {pre} == The feedback prefix"); + hard(" {post} == The feedback postfix"); + hard(" {errorpre} == The error prefix"); + hard(" {errorpost} == The error postfix"); + hard("Use '/set field' to set the format of these substitutions."); + hard("Where is the context in which the format is applied."); + hard("The structure of selector is: [-[-]]"); + hard("Where each field component may be missing (indicating defaults),"); + hard("star (indicating all), or a comma separated list of field values."); + hard("For case, the field values are:"); + hardEnums(EnumSet.allOf(FormatCase.class), ev -> ev.doc); + hard("For action, the field values are:"); + hardEnums(EnumSet.allOf(FormatAction.class), ev -> ev.doc); + hard("For when, the field values are:"); + hardEnums(EnumSet.allOf(FormatWhen.class), ev -> ev.doc); + hard(""); + hard("Example:"); + hard(" /set format example '{pre}{action} variable {name}, reset to null{post}' varreset-*-update"); + } + + final void printFieldHelp() { + hard("Set the format of a field substitution as used in '/set format'."); + hard(""); + hard("/set field \"\" ..."); + hard(""); + hard("Where is the name of a previously defined feedback mode -- see '/set newmode'."); + hard("Where is context-specific format to set, each with its own selector structure:"); + hard(" action == The action. The selector: -."); + hard(" name == The name. '%%s' is the name. No selectors."); + hard(" type == The type name. '%%s' is the type. No selectors."); + hard(" resolve == Unresolved info. '%%s' is the unresolved list. The selector: -."); + hard(" result == The result value. '%%s' is the result value. No selectors."); + hard(" when == The entered snippet or a resultant update. The selector: "); + hard(" pre == The feedback prefix. No selectors."); + hard(" post == The feedback postfix. No selectors."); + hard(" errorpre == The error prefix. No selectors."); + hard(" errorpost == The error postfix. No selectors."); + hard("Where is a quoted string -- see the description specific to the field (above)."); + hard("Where is the context in which the format is applied (see above)."); + hard("For action, the field values are:"); + hardEnums(EnumSet.allOf(FormatAction.class), ev -> ev.doc); + hard("For when, the field values are:"); + hardEnums(EnumSet.allOf(FormatWhen.class), ev -> ev.doc); + hard("For resolve, the field values are:"); + hardEnums(EnumSet.allOf(FormatResolve.class), ev -> ev.doc); + hard(""); + hard("Example:"); + hard(" /set field example resolve ' which cannot be invoked until%%s is declared' defined-update"); + } + + final void printFeedbackHelp() { + hard("Set the feedback mode describing displayed feedback for entered snippets and commands."); + hard(""); + hard("/set feedback "); + hard(""); + hard("Where is the name of a previously defined feedback mode."); + hard("Currently defined feedback modes:"); + modeMap.keySet().stream() + .forEach(m -> hard(" %s", m)); + hard("User-defined modes can be added, see '/help /set newmode'"); + } + + final void printNewModeHelp() { + hard("Create a user-defined feedback mode, optionally copying from an existing mode."); + hard(""); + hard("/set newmode [command|quiet []]"); + hard(""); + hard("Where is the name of a mode you wish to create."); + hard("Where is the name of a previously defined feedback mode."); + hard("If is present, its settings are copied to the new mode."); + hard("'command' vs 'quiet' determines if informative/verifying command feedback is displayed."); + hard(""); + hard("Once the new mode is created, use '/set format', '/set field', and '/set prompt' to configure it."); + hard("Use '/set feedback' to use the new mode."); + } + + final void printPromptHelp() { + hard("Set the prompts. Both the normal prompt and the continuation-prompt must be set."); + hard(""); + hard("/set prompt \"\" \"\""); + hard(""); + hard("Where is the name of a previously defined feedback mode."); + hard("Where and are quoted strings printed as input promptds;"); + hard("Both may optionally contain '%%s' which will be substituted with the next snippet id --"); + hard("note that what is entered may not be assigned that id, for example it may be an error or command."); + hard("The continuation-prompt is used on the second and subsequent lines of a multi-line snippet."); + } + } +} diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java index fd14be2a612..10b121b4062 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java @@ -1,6 +1,5 @@ - /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +34,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.io.Reader; -import java.io.StreamTokenizer; import java.io.StringReader; import java.nio.charset.Charset; import java.nio.file.AccessDeniedException; @@ -66,24 +64,25 @@ import java.util.stream.StreamSupport; import jdk.internal.jshell.debug.InternalDebugControl; import jdk.internal.jshell.tool.IOContext.InputInterruptedException; +import jdk.jshell.DeclarationSnippet; import jdk.jshell.Diag; import jdk.jshell.EvalException; +import jdk.jshell.ExpressionSnippet; +import jdk.jshell.ImportSnippet; import jdk.jshell.JShell; -import jdk.jshell.Snippet; -import jdk.jshell.DeclarationSnippet; -import jdk.jshell.TypeDeclSnippet; +import jdk.jshell.JShell.Subscription; import jdk.jshell.MethodSnippet; import jdk.jshell.PersistentSnippet; -import jdk.jshell.VarSnippet; -import jdk.jshell.ExpressionSnippet; +import jdk.jshell.Snippet; import jdk.jshell.Snippet.Status; +import jdk.jshell.Snippet.SubKind; +import jdk.jshell.SnippetEvent; import jdk.jshell.SourceCodeAnalysis; import jdk.jshell.SourceCodeAnalysis.CompletionInfo; import jdk.jshell.SourceCodeAnalysis.Suggestion; -import jdk.jshell.SnippetEvent; +import jdk.jshell.TypeDeclSnippet; import jdk.jshell.UnresolvedReferenceException; -import jdk.jshell.Snippet.SubKind; -import jdk.jshell.JShell.Subscription; +import jdk.jshell.VarSnippet; import static java.nio.file.StandardOpenOption.CREATE; import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; @@ -94,7 +93,12 @@ import java.util.ResourceBundle; import java.util.Spliterators; import java.util.function.Function; import java.util.function.Supplier; +import jdk.internal.jshell.tool.Feedback.FormatAction; +import jdk.internal.jshell.tool.Feedback.FormatCase; +import jdk.internal.jshell.tool.Feedback.FormatResolve; +import jdk.internal.jshell.tool.Feedback.FormatWhen; import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; import static jdk.jshell.Snippet.SubKind.VAR_VALUE_SUBKIND; /** @@ -103,6 +107,7 @@ import static jdk.jshell.Snippet.SubKind.VAR_VALUE_SUBKIND; */ public class JShellTool { + private static final String LINE_SEP = System.getProperty("line.separator"); private static final Pattern LINEBREAK = Pattern.compile("\\R"); private static final Pattern HISTORY_ALL_START_FILENAME = Pattern.compile( "((?(all|history|start))(\\z|\\p{javaWhitespace}+))?(?.*)"); @@ -116,6 +121,8 @@ public class JShellTool { final PrintStream userout; final PrintStream usererr; + final Feedback feedback = new Feedback(); + /** * The constructor for the tool (used by tool launch via main and by test * harnesses to capture ins and outs. @@ -137,6 +144,70 @@ public class JShellTool { this.userin = userin; this.userout = userout; this.usererr = usererr; + initializeFeedbackModes(); + } + + /** + * Create the default set of feedback modes + */ + final void initializeFeedbackModes() { + // Initialize normal feedback mode + cmdSet("newmode normal command"); + cmdSet("prompt normal '\n-> ' '>> '"); + cmdSet("field normal pre '| '"); + cmdSet("field normal post '%n'"); + cmdSet("field normal errorpre '| '"); + cmdSet("field normal errorpost '%n'"); + cmdSet("field normal action 'Added' added-primary"); + cmdSet("field normal action 'Modified' modified-primary"); + cmdSet("field normal action 'Replaced' replaced-primary"); + cmdSet("field normal action 'Overwrote' overwrote-primary"); + cmdSet("field normal action 'Dropped' dropped-primary"); + cmdSet("field normal action 'Rejected' rejected-primary"); + cmdSet("field normal action ' Update added' added-update"); + cmdSet("field normal action ' Update modified' modified-update"); + cmdSet("field normal action ' Update replaced' replaced-update"); + cmdSet("field normal action ' Update overwrote' overwrote-update"); + cmdSet("field normal action ' Update dropped' dropped-update"); + cmdSet("field normal action ' Update rejected' rejected-update"); + cmdSet("field normal resolve '' ok-*"); + cmdSet("field normal resolve ', however, it cannot be invoked until%s is declared' defined-primary"); + cmdSet("field normal resolve ', however, it cannot be referenced until%s is declared' notdefined-primary"); + cmdSet("field normal resolve ' which cannot be invoked until%s is declared' defined-update"); + cmdSet("field normal resolve ' which cannot be referenced until%s is declared' notdefined-update"); + cmdSet("field normal name '%s'"); + cmdSet("field normal type '%s'"); + cmdSet("field normal result '%s'"); + + cmdSet("format normal '' *-*-*"); + + cmdSet("format normal '{pre}{action} class {name}{resolve}{post}' class"); + cmdSet("format normal '{pre}{action} interface {name}{resolve}{post}' interface"); + cmdSet("format normal '{pre}{action} enum {name}{resolve}{post}' enum"); + cmdSet("format normal '{pre}{action} annotation interface {name}{resolve}{post}' annotation"); + + cmdSet("format normal '{pre}{action} method {name}({type}){resolve}{post}' method"); + + cmdSet("format normal '{pre}{action} variable {name} of type {type}{resolve}{post}' vardecl"); + cmdSet("format normal '{pre}{action} variable {name} of type {type} with initial value {result}{resolve}{post}' varinit"); + cmdSet("format normal '{pre}{action} variable {name}{resolve}{post}' vardeclrecoverable"); + cmdSet("format normal '{pre}{action} variable {name}, reset to null{post}' varreset-*-update"); + + cmdSet("format normal '{pre}Expression value is: {result}{post}" + + "{pre} assigned to temporary variable {name} of type {type}{post}' expression"); + cmdSet("format normal '{pre}Variable {name} of type {type} has value {result}{post}' varvalue"); + cmdSet("format normal '{pre}Variable {name} has been assigned the value {result}{post}' assignment"); + + cmdSet("feedback normal"); + + // Initialize off feedback mode + cmdSet("newmode off quiet"); + cmdSet("prompt off '-> ' '>> '"); + cmdSet("field off pre '| '"); + cmdSet("field off post '%n'"); + cmdSet("field off errorpre '| '"); + cmdSet("field off errorpost '%n'"); + cmdSet("format off '' *-*-*"); } private IOContext input = null; @@ -150,7 +221,6 @@ public class JShellTool { private boolean debug = false; private boolean displayPrompt = true; public boolean testPrompt = false; - private Feedback feedback = Feedback.Default; private String cmdlineClasspath = null; private String cmdlineStartup = null; private String[] editor = null; @@ -185,6 +255,15 @@ public class JShellTool { Map mapSnippet; + /** + * Is the input/output currently interactive + * + * @return true if console + */ + boolean interactive() { + return input != null && input.interactiveOutput(); + } + void debug(String format, Object... args) { if (debug) { cmderr.printf(format + "\n", args); @@ -192,38 +271,98 @@ public class JShellTool { } /** - * For more verbose feedback modes - * @param format printf format - * @param args printf args + * Base output for command output -- no pre- or post-fix + * + * @param printf format + * @param printf args */ - void fluff(String format, Object... args) { - if (feedback() != Feedback.Off && feedback() != Feedback.Concise) { - hard(format, args); - } + void rawout(String format, Object... args) { + cmdout.printf(format, args); } /** - * For concise feedback mode only - * @param format printf format - * @param args printf args - */ - void concise(String format, Object... args) { - if (feedback() == Feedback.Concise) { - hard(format, args); - } - } - - /** - * For all feedback modes -- must show + * Must show command output + * * @param format printf format * @param args printf args */ void hard(String format, Object... args) { - cmdout.printf("| " + format + "\n", args); + rawout(feedback.getPre() + format + feedback.getPost(), args); + } + + /** + * Error command output + * + * @param format printf format + * @param args printf args + */ + void error(String format, Object... args) { + rawout(feedback.getErrorPre() + format + feedback.getErrorPost(), args); + } + + /** + * Optional output + * + * @param format printf format + * @param args printf args + */ + void fluff(String format, Object... args) { + if (feedback.shouldDisplayCommandFluff() && interactive()) { + hard(format, args); + } + } + + /** + * Optional output -- with embedded per- and post-fix + * + * @param format printf format + * @param args printf args + */ + void fluffRaw(String format, Object... args) { + if (feedback.shouldDisplayCommandFluff() && interactive()) { + rawout(format, args); + } + } + + void hardPairs(Stream stream, Function a, Function b) { + Map a2b = stream.collect(toMap(a, b, + (m1, m2) -> m1, + () -> new LinkedHashMap<>())); + int aLen = 0; + for (String av : a2b.keySet()) { + aLen = Math.max(aLen, av.length()); + } + String format = " %-" + aLen + "s -- %s"; + String indentedNewLine = LINE_SEP + feedback.getPre() + + String.format(" %-" + (aLen + 4) + "s", ""); + for (Entry e : a2b.entrySet()) { + hard(format, e.getKey(), e.getValue().replaceAll("\n", indentedNewLine)); + } + } + + /** + * User custom feedback mode only + * + * @param fcase Event to report + * @param update Is this an update (rather than primary) + * @param fa Action + * @param fr Resolution status + * @param name Name string + * @param type Type string or null + * @param result Result value or null + * @param unresolved The unresolved symbols + */ + void custom(FormatCase fcase, boolean update, FormatAction fa, FormatResolve fr, + String name, String type, String unresolved, String result) { + String format = feedback.getFormat(fcase, + (update ? FormatWhen.UPDATE : FormatWhen.PRIMARY), fa, fr, + name != null, type != null, result != null); + fluffRaw(format, unresolved, name, type, result); } /** * Trim whitespace off end of string + * * @param s * @return */ @@ -276,8 +415,8 @@ public class JShellTool { } if (regenerateOnDeath) { - fluff("Welcome to JShell -- Version %s", version()); - fluff("Type /help for help"); + hard("Welcome to JShell -- Version %s", version()); + hard("Type /help for help"); } try { @@ -369,14 +508,14 @@ public class JShellTool { } private void printUsage() { - cmdout.printf("Usage: jshell \n"); - cmdout.printf("where possible options include:\n"); - cmdout.printf(" -classpath Specify where to find user class files\n"); - cmdout.printf(" -cp Specify where to find user class files\n"); - cmdout.printf(" -startup One run replacement for the start-up definitions\n"); - cmdout.printf(" -nostartup Do not run the start-up definitions\n"); - cmdout.printf(" -help Print a synopsis of standard options\n"); - cmdout.printf(" -version Version information\n"); + rawout("Usage: jshell \n"); + rawout("where possible options include:\n"); + rawout(" -classpath Specify where to find user class files\n"); + rawout(" -cp Specify where to find user class files\n"); + rawout(" -startup One run replacement for the start-up definitions\n"); + rawout(" -nostartup Do not run the start-up definitions\n"); + rawout(" -help Print a synopsis of standard options\n"); + rawout(" -version Version information\n"); } private void resetState() { @@ -460,10 +599,8 @@ public class JShellTool { ? "\u0005" //ENQ : "\u0006" //ACK : incomplete.isEmpty() - ? feedback() == Feedback.Concise - ? "-> " - : "\n-> " - : ">> " + ? feedback.getPrompt(currentNameSpace.tidNext()) + : feedback.getContinuationPrompt(currentNameSpace.tidNext()) ; } else { prompt = ""; @@ -541,7 +678,7 @@ public class JShellTool { Command[] candidates = findCommand(cmd, c -> c.kind.isRealCommand); if (candidates.length == 0) { if (!rerunHistoryEntryById(cmd.substring(1))) { - hard("No such command or snippet id: %s", cmd); + error("No such command or snippet id: %s", cmd); fluff("Type /help for help."); } } else if (candidates.length == 1) { @@ -552,7 +689,7 @@ public class JShellTool { addToReplayHistory((command.command + " " + arg).trim()); } } else { - hard("Command: %s is ambiguous: %s", cmd, Arrays.stream(candidates).map(c -> c.command).collect(Collectors.joining(", "))); + error("Command: %s is ambiguous: %s", cmd, Arrays.stream(candidates).map(c -> c.command).collect(Collectors.joining(", "))); fluff("Type /help for help."); } } @@ -635,45 +772,6 @@ public class JShellTool { } } - class ArgTokenizer extends StreamTokenizer { - - ArgTokenizer(String arg) { - super(new StringReader(arg)); - resetSyntax(); - wordChars(0x00, 0xFF); - quoteChar('"'); - quoteChar('\''); - - whitespaceChars(0x09, 0x0D); - whitespaceChars(0x1C, 0x20); - whitespaceChars(0x85, 0x85); - whitespaceChars(0xA0, 0xA0); - whitespaceChars(0x1680, 0x1680); - whitespaceChars(0x180E, 0x180E); - whitespaceChars(0x2000, 0x200A); - whitespaceChars(0x202F, 0x202F); - whitespaceChars(0x205F, 0x205F); - whitespaceChars(0x3000, 0x3000); - } - - String next() { - try { - nextToken(); - } catch (Throwable t) { - return null; - } - return sval; - } - - String val() { - return sval; - } - - boolean isQuoted() { - return ttype == '\'' || ttype == '"'; - } - } - static final class FixedCompletionProvider implements CompletionProvider { private final String[] alternatives; @@ -801,16 +899,9 @@ public class JShellTool { " -- List the snippet with the specified snippet id\n", arg -> cmdList(arg), editKeywordCompletion())); - registerCommand(new Command("/seteditor", "", "set the external editor command to use", - "Specify the command to launch for the /edit command.\n" + - "The command is an operating system dependent string.\n" + - "The command may include space-separated arguments (such as flags).\n" + - "When /edit is used, temporary file to edit will be appended as the last argument.\n", - arg -> cmdSetEditor(arg), - EMPTY_COMPLETION_PROVIDER)); registerCommand(new Command("/edit", "", "edit a source entry referenced by name or id", "Edit a snippet or snippets of source in an external editor.\n" + - "The editor to use is set with /seteditor.\n" + + "The editor to use is set with /set editor.\n" + "If no editor has been set, a simple editor will be launched.\n\n" + "/edit \n" + " -- Edit the snippet or snippets with the specified name (preference for active snippets)\n" + @@ -875,7 +966,7 @@ public class JShellTool { " * Start-up code is re-executed.\n" + " * The execution state is restarted.\n" + " * The classpath is cleared.\n" + - "Tool settings are maintained: /feedback, /prompt, and /seteditor\n" + + "Tool settings are maintained, as set with: /set ...\n" + "Save any work before using this command\n", arg -> cmdReset(), EMPTY_COMPLETION_PROVIDER)); @@ -895,25 +986,6 @@ public class JShellTool { " -- With the 'quiet' argument the replay is not shown. Errors will display.\n", arg -> cmdReload(arg), reloadCompletion())); - registerCommand(new Command("/feedback", "", "feedback information: off, concise, normal, verbose, default, or ?", - "Set the level of feedback describing the effect of commands and snippets.\n\n" + - "/feedback off\n" + - " -- Give no feedback\n" + - "/feedback concise\n" + - " -- Brief and generally symbolic feedback\n" + - "/feedback normal\n" + - " -- Give a natural language description of the actions\n" + - "/feedback verbose\n" + - " -- Like normal but with side-effects described\n" + - "/feedback default\n" + - " -- Same as normal for user input, off for input from a file\n", - arg -> cmdFeedback(arg), - new FixedCompletionProvider("off", "concise", "normal", "verbose", "default", "?"))); - registerCommand(new Command("/prompt", null, "toggle display of a prompt", - "Toggle between displaying an input prompt and not displaying a prompt.\n" + - "Particularly useful when pasting large amounts of text.\n", - arg -> cmdPrompt(), - EMPTY_COMPLETION_PROVIDER)); registerCommand(new Command("/classpath", "", "add a path to the classpath", "Append a additional path to the classpath.\n", arg -> cmdClasspath(arg), @@ -923,10 +995,6 @@ public class JShellTool { "Display the history of snippet and command input since this jshell was launched.\n", arg -> cmdHistory(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/setstart", "", "read file and set as the new start-up definitions", - "The contents of the specified file become the default start-up snippets and commands.\n", - arg -> cmdSetStart(arg), - FILE_COMPLETION_PROVIDER)); registerCommand(new Command("/debug", null, "toggle debugging of the jshell", "Display debugging information for the jshelll implementation.\n" + "0: Debugging off\n" + @@ -951,6 +1019,37 @@ public class JShellTool { " -- Display information about the specified help subject. Example: /help intro\n", arg -> cmdHelp(arg), EMPTY_COMPLETION_PROVIDER)); + registerCommand(new Command("/set", "editor|start|feedback|newmode|prompt|format|field ...", "set jshell configuration information", + "Set jshell configuration information, including:\n" + + "the external editor to use, the start-up definitions to use, a new feedback mode,\n" + + "the command prompt, the feedback mode to use, or the format of output.\n" + + "\n" + + "/set editor ...\n" + + " -- Specify the command to launch for the /edit command.\n" + + " The is an operating system dependent string.\n" + + "\n" + + "/set start \n" + + " -- The contents of the specified become the default start-up snippets and commands.\n" + + "\n" + + "/set feedback \n" + + " -- Set the feedback mode describing displayed feedback for entered snippets and commands.\n" + + "\n" + + "/set newmode [command|quiet []]\n" + + " -- Create a user-defined feedback mode, optionally copying from an existing mode.\n" + + "\n" + + "/set prompt \"\" \"\"\n" + + " -- Set the displayed prompts for a given feedback mode.\n" + + "\n" + + "/set format \"\" ...\n" + + " -- Configure a feedback mode by setting the format to use in a specified set of cases.\n" + + "\n" + + "/set field name|type|result|when|action|resolve|pre|post|errorpre|errorpost \"\" ...\n" + + " -- Set the format of a field within the of a \"/set format\" command\n" + + "\n" + + "To get more information about one of these forms, use /help with the form specified.\n" + + "For example: /help /set format\n", + arg -> cmdSet(arg), + new FixedCompletionProvider("format", "field", "feedback", "prompt", "newmode", "start", "editor"))); registerCommand(new Command("/?", "", "get information about jshell", "Display information about jshell (abbreviation for /help).\n" + "/?\n" + @@ -1051,19 +1150,136 @@ public class JShellTool { // --- Command implementations --- - boolean cmdSetEditor(String arg) { - if (arg.isEmpty()) { - hard("/seteditor requires a path argument"); + private static final String[] setSub = new String[]{ + "format", "field", "feedback", "newmode", "prompt", "editor", "start"}; + + // The /set command. Currently /set format, /set field and /set feedback. + // Other commands will fold here, see: 8148317 + final boolean cmdSet(String arg) { + ArgTokenizer at = new ArgTokenizer(arg.trim()); + String which = setSubCommand(at); + if (which == null) { return false; - } else { - List ed = new ArrayList<>(); - ArgTokenizer at = new ArgTokenizer(arg); - String n; - while ((n = at.next()) != null) ed.add(n); - editor = ed.toArray(new String[ed.size()]); - fluff("Editor set to: %s", arg); - return true; } + switch (which) { + case "format": + return feedback.setFormat(this, at); + case "field": + return feedback.setField(this, at); + case "feedback": + return feedback.setFeedback(this, at); + case "newmode": + return feedback.setNewMode(this, at); + case "prompt": + return feedback.setPrompt(this, at); + case "editor": { + String prog = at.next(); + if (prog == null) { + hard("The '/set editor' command requires a path argument"); + return false; + } else { + List ed = new ArrayList<>(); + ed.add(prog); + String n; + while ((n = at.next()) != null) { + ed.add(n); + } + editor = ed.toArray(new String[ed.size()]); + fluff("Editor set to: %s", arg); + return true; + } + } + case "start": { + String filename = at.next(); + if (filename == null) { + hard("The '/set start' command requires a filename argument."); + } else { + try { + byte[] encoded = Files.readAllBytes(toPathResolvingUserHome(filename)); + String init = new String(encoded); + PREFS.put(STARTUP_KEY, init); + } catch (AccessDeniedException e) { + hard("File '%s' for /set start is not accessible.", filename); + return false; + } catch (NoSuchFileException e) { + hard("File '%s' for /set start is not found.", filename); + return false; + } catch (Exception e) { + hard("Exception while reading start set file: %s", e); + return false; + } + } + return true; + } + default: + hard("Error: Invalid /set argument: %s", which); + return false; + } + } + + boolean printSetHelp(ArgTokenizer at) { + String which = setSubCommand(at); + if (which == null) { + return false; + } + switch (which) { + case "format": + feedback.printFormatHelp(this); + return true; + case "field": + feedback.printFieldHelp(this); + return true; + case "feedback": + feedback.printFeedbackHelp(this); + return true; + case "newmode": + feedback.printNewModeHelp(this); + return true; + case "prompt": + feedback.printPromptHelp(this); + return true; + case "editor": + hard("Specify the command to launch for the /edit command."); + hard(""); + hard("/set editor ..."); + hard(""); + hard("The is an operating system dependent string."); + hard("The may include space-separated arguments (such as flags) -- ...."); + hard("When /edit is used, the temporary file to edit will be appended as the last argument."); + return true; + case "start": + hard("Set the start-up configuration -- a sequence of snippets and commands read at start-up."); + hard(""); + hard("/set start "); + hard(""); + hard("The contents of the specified become the default start-up snippets and commands --"); + hard("which are run when the jshell tool is started or reset."); + return true; + default: + hard("Error: Invalid /set argument: %s", which); + return false; + } + } + + String setSubCommand(ArgTokenizer at) { + String[] matches = at.next(setSub); + if (matches == null) { + error("The /set command requires arguments. See: /help /set"); + return null; + } else if (matches.length == 0) { + error("Not a valid argument to /set: %s", at.val()); + fluff("/set is followed by one of: %s", Arrays.stream(setSub) + .collect(Collectors.joining(", ")) + ); + return null; + } else if (matches.length > 1) { + error("Ambiguous argument to /set: %s", at.val()); + fluff("Use one of: %s", Arrays.stream(matches) + .collect(Collectors.joining(", ")) + ); + return null; + } + return matches[0]; } boolean cmdClasspath(String arg) { @@ -1137,91 +1353,50 @@ public class JShellTool { return true; } - private boolean cmdFeedback(String arg) { - switch (arg) { - case "": - case "d": - case "default": - feedback = Feedback.Default; - break; - case "o": - case "off": - feedback = Feedback.Off; - break; - case "c": - case "concise": - feedback = Feedback.Concise; - break; - case "n": - case "normal": - feedback = Feedback.Normal; - break; - case "v": - case "verbose": - feedback = Feedback.Verbose; - break; - default: - hard("Follow /feedback with of the following:"); - hard(" off (errors and critical output only)"); - hard(" concise"); - hard(" normal"); - hard(" verbose"); - hard(" default"); - hard("You may also use just the first letter, for example: /f c"); - hard("In interactive mode 'default' is the same as 'normal', from a file it is the same as 'off'"); - return false; - } - fluff("Feedback mode: %s", feedback.name().toLowerCase()); - return true; - } - boolean cmdHelp(String arg) { - if (!arg.isEmpty()) { - StringBuilder sb = new StringBuilder(); - commands.values().stream() - .filter(c -> c.command.startsWith(arg)) - .forEach(c -> { - sb.append("\n"); - sb.append(c.command); - sb.append("\n\n"); - sb.append(c.help); - sb.append("\n"); - }); - if (sb.length() > 0) { - cmdout.print(sb); - return true; + ArgTokenizer at = new ArgTokenizer(arg); + String subject = at.next(); + if (subject != null) { + Command[] matches = commands.values().stream() + .filter(c -> c.command.startsWith(subject)) + .toArray(size -> new Command[size]); + at.mark(); + String sub = at.next(); + if (sub != null && matches.length == 1 && matches[0].command.equals("/set")) { + at.rewind(); + return printSetHelp(at); + } + if (matches.length > 0) { + for (Command c : matches) { + hard(""); + hard("%s", c.command); + hard(""); + hard("%s", c.help.replaceAll("\n", LINE_SEP + feedback.getPre())); + } + return true; + } else { + error("No commands or subjects start with the provided argument: %s\n\n", arg); } - cmdout.printf("No commands or subjects start with the provided argument: %s\n\n", arg); } - int synopsisLen = 0; - Map synopsis2Description = new LinkedHashMap<>(); - for (Command cmd : new LinkedHashSet<>(commands.values())) { - if (!cmd.kind.showInHelp) - continue; - StringBuilder synopsis = new StringBuilder(); - synopsis.append(cmd.command); - if (cmd.params != null) - synopsis.append(" ").append(cmd.params); - synopsis2Description.put(synopsis.toString(), cmd.description); - synopsisLen = Math.max(synopsisLen, synopsis.length()); - } - cmdout.println("Type a Java language expression, statement, or declaration."); - cmdout.println("Or type one of the following commands:\n"); - for (Entry e : synopsis2Description.entrySet()) { - cmdout.print(String.format("%-" + synopsisLen + "s", e.getKey())); - cmdout.print(" -- "); - String indentedNewLine = System.getProperty("line.separator") + - String.format("%-" + (synopsisLen + 4) + "s", ""); - cmdout.println(e.getValue().replace("\n", indentedNewLine)); - } - cmdout.println(); - cmdout.println("For more information type '/help' followed by the name of command or a subject."); - cmdout.println("For example '/help /list' or '/help intro'. Subjects:\n"); - commands.values().stream() - .filter(c -> c.kind == CommandKind.HELP_SUBJECT) - .forEach(c -> { - cmdout.printf("%-12s -- %s\n", c.command, c.description); - }); + hard("Type a Java language expression, statement, or declaration."); + hard("Or type one of the following commands:"); + hard(""); + hardPairs(commands.values().stream() + .filter(cmd -> cmd.kind.showInHelp), + cmd -> (cmd.params != null) + ? cmd.command + " " + cmd.params + : cmd.command, + cmd -> cmd.description + ); + hard(""); + hard("For more information type '/help' followed by the name of command or a subject."); + hard("For example '/help /list' or '/help intro'. Subjects:"); + hard(""); + hardPairs(commands.values().stream() + .filter(cmd -> cmd.kind == CommandKind.HELP_SUBJECT), + cmd -> cmd.command, + cmd -> cmd.description + ); return true; } @@ -1482,13 +1657,6 @@ public class JShellTool { return true; } - private boolean cmdPrompt() { - displayPrompt = !displayPrompt; - fluff("Prompt will %sdisplay. Use /prompt to toggle.", displayPrompt ? "" : "NOT "); - concise("Prompt: %s", displayPrompt ? "on" : "off"); - return true; - } - private boolean cmdReset() { live = false; fluff("Resetting state."); @@ -1577,28 +1745,6 @@ public class JShellTool { return true; } - private boolean cmdSetStart(String filename) { - if (filename.isEmpty()) { - hard("The /setstart command requires a filename argument."); - } else { - try { - byte[] encoded = Files.readAllBytes(toPathResolvingUserHome(filename)); - String init = new String(encoded); - PREFS.put(STARTUP_KEY, init); - } catch (AccessDeniedException e) { - hard("File '%s' for /setstart is not accessible.", filename); - return false; - } catch (NoSuchFileException e) { - hard("File '%s' for /setstart is not found.", filename); - return false; - } catch (Exception e) { - hard("Exception while reading start set file: %s", e); - return false; - } - } - return true; - } - private boolean cmdVars() { for (VarSnippet vk : state.variables()) { String val = state.status(vk) == Status.VALID @@ -1831,14 +1977,10 @@ public class JShellTool { printDiagnostics(source, diagnostics, true); } else { // Update - SubKind subkind = sn.subKind(); - if (sn instanceof DeclarationSnippet - && (feedback() == Feedback.Verbose - || ste.status() == Status.OVERWRITTEN - || subkind == SubKind.VAR_DECLARATION_SUBKIND - || subkind == SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND)) { - // Under the conditions, display update information - displayDeclarationAndValue(ste, true, null); + if (sn instanceof DeclarationSnippet) { + // display update information + displayDeclarationAndValue(ste, true, ste.value()); + List other = errorsOnly(diagnostics); if (other.size() > 0) { printDiagnostics(source, other, true); @@ -1851,118 +1993,117 @@ public class JShellTool { @SuppressWarnings("fallthrough") private void displayDeclarationAndValue(SnippetEvent ste, boolean update, String value) { Snippet key = ste.snippet(); - String declared; + FormatAction action; Status status = ste.status(); switch (status) { case VALID: case RECOVERABLE_DEFINED: case RECOVERABLE_NOT_DEFINED: if (ste.previousStatus().isActive) { - declared = ste.isSignatureChange() - ? "Replaced" - : "Modified"; + action = ste.isSignatureChange() + ? FormatAction.REPLACED + : FormatAction.MODIFIED; } else { - declared = "Added"; + action = FormatAction.ADDED; } break; case OVERWRITTEN: - declared = "Overwrote"; + action = FormatAction.OVERWROTE; break; case DROPPED: - declared = "Dropped"; + action = FormatAction.DROPPED; break; case REJECTED: - declared = "Rejected"; + action = FormatAction.REJECTED; break; case NONEXISTENT: default: // Should not occur - declared = ste.previousStatus().toString() + "=>" + status.toString(); + error("Unexpected status: " + ste.previousStatus().toString() + "=>" + status.toString()); + return; } - if (update) { - declared = " Update " + declared.toLowerCase(); - } - String however; + FormatResolve resolution; + String unresolved; if (key instanceof DeclarationSnippet && (status == Status.RECOVERABLE_DEFINED || status == Status.RECOVERABLE_NOT_DEFINED)) { - String cannotUntil = (status == Status.RECOVERABLE_NOT_DEFINED) - ? " cannot be referenced until" - : " cannot be invoked until"; - however = (update? " which" : ", however, it") + cannotUntil + unresolved((DeclarationSnippet) key); + resolution = (status == Status.RECOVERABLE_NOT_DEFINED) + ? FormatResolve.NOTDEFINED + : FormatResolve.DEFINED; + unresolved = unresolved((DeclarationSnippet) key); } else { - however = ""; + resolution = FormatResolve.OK; + unresolved = ""; } switch (key.subKind()) { case CLASS_SUBKIND: - fluff("%s class %s%s", declared, ((TypeDeclSnippet) key).name(), however); + custom(FormatCase.CLASS, update, action, resolution, + ((TypeDeclSnippet) key).name(), null, unresolved, null); break; case INTERFACE_SUBKIND: - fluff("%s interface %s%s", declared, ((TypeDeclSnippet) key).name(), however); + custom(FormatCase.INTERFACE, update, action, resolution, + ((TypeDeclSnippet) key).name(), null, unresolved, null); break; case ENUM_SUBKIND: - fluff("%s enum %s%s", declared, ((TypeDeclSnippet) key).name(), however); + custom(FormatCase.ENUM, update, action, resolution, + ((TypeDeclSnippet) key).name(), null, unresolved, null); break; case ANNOTATION_TYPE_SUBKIND: - fluff("%s annotation interface %s%s", declared, ((TypeDeclSnippet) key).name(), however); + custom(FormatCase.ANNOTATION, update, action, resolution, + ((TypeDeclSnippet) key).name(), null, unresolved, null); break; case METHOD_SUBKIND: - fluff("%s method %s(%s)%s", declared, ((MethodSnippet) key).name(), - ((MethodSnippet) key).parameterTypes(), however); + custom(FormatCase.METHOD, update, action, resolution, + ((MethodSnippet) key).name(), ((MethodSnippet) key).parameterTypes(), unresolved, null); break; case VAR_DECLARATION_SUBKIND: - if (!update) { - VarSnippet vk = (VarSnippet) key; - if (status == Status.RECOVERABLE_NOT_DEFINED) { - fluff("%s variable %s%s", declared, vk.name(), however); - } else { - fluff("%s variable %s of type %s%s", declared, vk.name(), vk.typeName(), however); - } - break; - } - // Fall through case VAR_DECLARATION_WITH_INITIALIZER_SUBKIND: { VarSnippet vk = (VarSnippet) key; if (status == Status.RECOVERABLE_NOT_DEFINED) { - if (!update) { - fluff("%s variable %s%s", declared, vk.name(), however); - break; - } - } else if (update) { - if (ste.isSignatureChange()) { - hard("%s variable %s, reset to null", declared, vk.name()); - } + custom(FormatCase.VARDECLRECOVERABLE, update, action, resolution, + vk.name(), null, unresolved, null); + } else if (update && ste.isSignatureChange()) { + custom(FormatCase.VARRESET, update, action, resolution, + vk.name(), null, unresolved, value); + } else if (key.subKind() == SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND) { + custom(FormatCase.VARINIT, update, action, resolution, + vk.name(), vk.typeName(), unresolved, value); } else { - fluff("%s variable %s of type %s with initial value %s", - declared, vk.name(), vk.typeName(), value); - concise("%s : %s", vk.name(), value); + custom(FormatCase.VARDECL, update, action, resolution, + vk.name(), vk.typeName(), unresolved, value); } break; } case TEMP_VAR_EXPRESSION_SUBKIND: { VarSnippet vk = (VarSnippet) key; - if (update) { - hard("%s temporary variable %s, reset to null", declared, vk.name()); - } else { - fluff("Expression value is: %s", (value)); - fluff(" assigned to temporary variable %s of type %s", vk.name(), vk.typeName()); - concise("%s : %s", vk.name(), value); - } + custom(FormatCase.EXPRESSION, update, action, resolution, + vk.name(), vk.typeName(), null, value); break; } case OTHER_EXPRESSION_SUBKIND: - fluff("Expression value is: %s", (value)); + error("Unexpected expression form -- value is: %s", (value)); break; case VAR_VALUE_SUBKIND: { ExpressionSnippet ek = (ExpressionSnippet) key; - fluff("Variable %s of type %s has value %s", ek.name(), ek.typeName(), (value)); - concise("%s : %s", ek.name(), value); + custom(FormatCase.VARVALUE, update, action, resolution, + ek.name(), ek.typeName(), null, value); break; } case ASSIGNMENT_SUBKIND: { ExpressionSnippet ek = (ExpressionSnippet) key; - fluff("Variable %s has been assigned the value %s", ek.name(), (value)); - concise("%s : %s", ek.name(), value); + custom(FormatCase.ASSIGNMENT, update, action, resolution, + ek.name(), ek.typeName(), null, value); break; } + case SINGLE_TYPE_IMPORT_SUBKIND: + case TYPE_IMPORT_ON_DEMAND_SUBKIND: + case SINGLE_STATIC_IMPORT_SUBKIND: + case STATIC_IMPORT_ON_DEMAND_SUBKIND: + custom(FormatCase.IMPORT, update, action, resolution, + ((ImportSnippet) key).name(), null, null, null); + break; + case STATEMENT_SUBKIND: + custom(FormatCase.STATEMENT, update, action, resolution, + null, null, null, null); + break; } } //where @@ -2048,34 +2189,9 @@ public class JShellTool { sb.append(", "); } } - switch (unr.size()) { - case 0: - break; - case 1: - sb.append(" is declared"); - break; - default: - sb.append(" are declared"); - break; - } return sb.toString(); } - enum Feedback { - Default, - Off, - Concise, - Normal, - Verbose - } - - Feedback feedback() { - if (feedback == Feedback.Default) { - return input == null || input.interactiveOutput() ? Feedback.Normal : Feedback.Off; - } - return feedback; - } - /** The current version number as a string. */ static String version() { diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java index 462d61e87de..2ae696a026f 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -231,7 +231,7 @@ class CompletenessAnalyzer { // Declarations and type parameters (thus expressions) EXTENDS(TokenKind.EXTENDS, XEXPR|XDECL), // extends - COMMA(TokenKind.COMMA, XEXPR|XDECL|XSTART), // , + COMMA(TokenKind.COMMA, XEXPR|XDECL), // , AMP(TokenKind.AMP, XEXPR|XDECL), // & GT(TokenKind.GT, XEXPR|XDECL), // > LT(TokenKind.LT, XEXPR|XDECL1), // < diff --git a/langtools/test/jdk/jshell/CommandCompletionTest.java b/langtools/test/jdk/jshell/CommandCompletionTest.java index 1ca831f0c13..07f7fc3e397 100644 --- a/langtools/test/jdk/jshell/CommandCompletionTest.java +++ b/langtools/test/jdk/jshell/CommandCompletionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,13 +50,9 @@ import org.testng.annotations.Test; public class CommandCompletionTest extends ReplToolTesting { public void testCommand() { - assertCompletion("/f|", false, "/feedback "); assertCompletion("/deb|", false); - assertCompletion("/feedback v|", false, "verbose"); assertCompletion("/c|", false, "/classes ", "/classpath "); assertCompletion("/h|", false, "/help ", "/history "); - assertCompletion("/feedback |", false, - "?", "concise", "default", "normal", "off", "verbose"); } public void testList() { @@ -108,7 +104,7 @@ public class CommandCompletionTest extends ReplToolTesting { public void testSave() throws IOException { Compiler compiler = new Compiler(); - assertCompletion("/s|", false, "/save ", "/seteditor ", "/setstart "); + assertCompletion("/s|", false, "/save ", "/set "); List p1 = listFiles(Paths.get("")); Collections.addAll(p1, "all ", "history ", "start "); FileSystems.getDefault().getRootDirectories().forEach(s -> p1.add(s.toString())); diff --git a/langtools/test/jdk/jshell/CompletenessTest.java b/langtools/test/jdk/jshell/CompletenessTest.java index 893baeee6ed..bbf10d2b28b 100644 --- a/langtools/test/jdk/jshell/CompletenessTest.java +++ b/langtools/test/jdk/jshell/CompletenessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ /* * @test + * @bug 8149524 * @summary Test SourceCodeAnalysis * @build KullaTesting TestingInputStream * @run testng CompletenessTest @@ -60,6 +61,7 @@ public class CompletenessTest extends KullaTesting { "try { } finally { }", "try (java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName)) { }", "foo: while (true) { printf(\"Innn\"); break foo; }", + "class Case, E2 extends Enum, E3 extends Enum> {}", ";", }; diff --git a/langtools/test/jdk/jshell/ExternalEditorTest.java b/langtools/test/jdk/jshell/ExternalEditorTest.java index b337c3d6d27..a794c7e57af 100644 --- a/langtools/test/jdk/jshell/ExternalEditorTest.java +++ b/langtools/test/jdk/jshell/ExternalEditorTest.java @@ -113,7 +113,7 @@ public class ExternalEditorTest extends EditorTestBase { @Override public void testEditor(boolean defaultStartup, String[] args, ReplTest... tests) { ReplTest[] t = new ReplTest[tests.length + 1]; - t[0] = a -> assertCommandCheckOutput(a, "/seteditor " + executionScript, + t[0] = a -> assertCommandCheckOutput(a, "/set editor " + executionScript, assertStartsWith("| Editor set to: " + executionScript)); System.arraycopy(tests, 0, t, 1, tests.length); super.testEditor(defaultStartup, args, t); @@ -193,8 +193,8 @@ public class ExternalEditorTest extends EditorTestBase { @Test public void setUnknownEditor() { test( - a -> assertCommand(a, "/seteditor", "| /seteditor requires a path argument\n"), - a -> assertCommand(a, "/seteditor UNKNOWN", "| Editor set to: UNKNOWN\n"), + a -> assertCommand(a, "/set editor", "| /set editor requires a path argument\n"), + a -> assertCommand(a, "/set editor UNKNOWN", "| Editor set to: UNKNOWN\n"), a -> assertCommand(a, "int a;", null), a -> assertCommand(a, "/e 1", "| Edit Error: process IO failure: Cannot run program \"UNKNOWN\": error=2, No such file or directory\n") @@ -204,7 +204,7 @@ public class ExternalEditorTest extends EditorTestBase { @Test(enabled = false) public void testRemoveTempFile() { test(new String[]{"-nostartup"}, - a -> assertCommandCheckOutput(a, "/seteditor " + executionScript, + a -> assertCommandCheckOutput(a, "/set editor " + executionScript, assertStartsWith("| Editor set to: " + executionScript)), a -> assertVariable(a, "int", "a", "0", "0"), a -> assertEditOutput(a, "/e 1", assertStartsWith("| Edit Error: Failure read edit file:"), () -> { diff --git a/langtools/test/jdk/jshell/ReplToolTesting.java b/langtools/test/jdk/jshell/ReplToolTesting.java index 05dd5389e0b..d4f697d3613 100644 --- a/langtools/test/jdk/jshell/ReplToolTesting.java +++ b/langtools/test/jdk/jshell/ReplToolTesting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -397,6 +397,15 @@ public class ReplToolTesting { assertCommand(after, cmd, out, "", null, "", ""); } + public void assertCommandOutputContains(boolean after, String cmd, String has) { + assertCommandCheckOutput(after, cmd, (s) -> + assertTrue(s.contains(has), "Output: \'" + s + "' does not contain: " + has)); + } + + public void assertCommandOutputStartsWith(boolean after, String cmd, String starts) { + assertCommandCheckOutput(after, cmd, assertStartsWith(starts)); + } + public void assertCommandCheckOutput(boolean after, String cmd, Consumer check) { if (!after) { assertCommand(false, cmd, null); @@ -437,13 +446,13 @@ public class ReplToolTesting { } private List computeCompletions(String code, boolean isSmart) { - JShellTool repl = this.repl != null ? this.repl + JShellTool js = this.repl != null ? this.repl : new JShellTool(null, null, null, null, null, null, null); int cursor = code.indexOf('|'); code = code.replace("|", ""); assertTrue(cursor > -1, "'|' not found: " + code); List completions = - repl.commandCompletionSuggestions(code, cursor, new int[1]); //XXX: ignoring anchor for now + js.commandCompletionSuggestions(code, cursor, new int[1]); //XXX: ignoring anchor for now return completions.stream() .filter(s -> isSmart == s.isSmart) .map(s -> s.continuation) @@ -481,6 +490,15 @@ public class ReplToolTesting { return name.hashCode(); } + @Override + public boolean equals(Object o) { + if (o instanceof MemberInfo) { + MemberInfo mi = (MemberInfo) o; + return name.equals(mi.name); + } + return false; + } + public abstract Consumer checkOutput(); public String getSource() { @@ -536,6 +554,11 @@ public class ReplToolTesting { "Output: " + output + " does not fit pattern: " + finalPattern); } + @Override + public int hashCode() { + return name.hashCode(); + } + @Override public boolean equals(Object o) { if (o instanceof VariableInfo) { @@ -585,6 +608,10 @@ public class ReplToolTesting { return s -> assertTrue(checkOutput.test(s), "Expected: '" + expectedOutput + "', actual: " + s); } + @Override + public int hashCode() { + return (name.hashCode() << 2) ^ type.hashCode() ; + } @Override public boolean equals(Object o) { @@ -615,6 +642,11 @@ public class ReplToolTesting { return s -> assertTrue(checkOutput.test(s), "Expected: '" + expectedOutput + "', actual: " + s); } + @Override + public int hashCode() { + return name.hashCode() ; + } + @Override public boolean equals(Object o) { if (o instanceof ClassInfo) { @@ -640,6 +672,11 @@ public class ReplToolTesting { return s -> assertTrue("".equals(s), "Expected: '', actual: " + s); } + @Override + public int hashCode() { + return (name.hashCode() << 2) ^ type.hashCode() ; + } + @Override public boolean equals(Object o) { if (o instanceof ImportInfo) { diff --git a/langtools/test/jdk/jshell/ToolBasicTest.java b/langtools/test/jdk/jshell/ToolBasicTest.java index f4501c84d32..e38ff644e77 100644 --- a/langtools/test/jdk/jshell/ToolBasicTest.java +++ b/langtools/test/jdk/jshell/ToolBasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 + * @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 * @requires os.family != "solaris" * @summary Tests for Basic tests for REPL tool * @library /tools/lib @@ -90,8 +90,7 @@ public class ToolBasicTest extends ReplToolTesting { public void elideStartUpFromList() { test( - (a) -> assertCommandCheckOutput(a, "123", (s) -> - assertTrue(s.contains("type int"), s)), + (a) -> assertCommandOutputContains(a, "123", "type int"), (a) -> assertCommandCheckOutput(a, "/list", (s) -> { int cnt; try (Scanner scanner = new Scanner(s)) { @@ -112,8 +111,7 @@ public class ToolBasicTest extends ReplToolTesting { Compiler compiler = new Compiler(); Path path = compiler.getPath("myfile"); test( - (a) -> assertCommandCheckOutput(a, "123", - (s) -> assertTrue(s.contains("type int"), s)), + (a) -> assertCommandOutputContains(a, "123", "type int"), (a) -> assertCommand(a, "/save " + path.toString(), "") ); try (Stream lines = Files.lines(path)) { @@ -594,12 +592,12 @@ public class ToolBasicTest extends ReplToolTesting { (a) -> assertMethod(a, "void f() {}", "()V", "f"), (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), (a) -> assertCommand(a, "/save " + startUpFile.toString(), null), - (a) -> assertCommand(a, "/setstart " + startUpFile.toString(), null) + (a) -> assertCommand(a, "/set start " + startUpFile.toString(), null) ); Path unknown = compiler.getPath("UNKNOWN"); test( - (a) -> assertCommand(a, "/setstart " + unknown.toString(), - "| File '" + unknown + "' for /setstart is not found.\n") + (a) -> assertCommand(a, "/set start " + unknown.toString(), + "| File '" + unknown + "' for /set start is not found.\n") ); test(false, new String[0], (a) -> { @@ -619,7 +617,7 @@ public class ToolBasicTest extends ReplToolTesting { } private void removeStartup() { - Preferences preferences = Preferences.userRoot().node("tool/REPL"); + Preferences preferences = Preferences.userRoot().node("tool/JShell"); if (preferences != null) { preferences.remove("STARTUP"); } @@ -636,7 +634,7 @@ public class ToolBasicTest extends ReplToolTesting { } public void testNoArgument() { - String[] commands = {"/save", "/open", "/setstart"}; + String[] commands = {"/save", "/open", "/set start"}; test(Stream.of(commands) .map(cmd -> { String c = cmd; @@ -670,8 +668,7 @@ public class ToolBasicTest extends ReplToolTesting { test( a -> assertVariable(a, "int", "x"), a -> assertCommandCheckOutput(a, "/vars", assertVariables()), - a -> assertCommandCheckOutput(a, "System.exit(5);", s -> - assertTrue(s.contains("terminated"), s)), + a -> assertCommandOutputContains(a, "System.exit(5);", "terminated"), a -> assertCommandCheckOutput(a, "/vars", s -> assertTrue(s.trim().isEmpty(), s)), a -> assertMethod(a, "void f() { }", "()void", "f"), @@ -699,8 +696,7 @@ public class ToolBasicTest extends ReplToolTesting { s -> assertEquals(s, "| No definition or id named " + arg + " found. There are no active definitions.\n")), a -> assertVariable(a, "int", "aardvark"), - a -> assertCommandCheckOutput(a, "/list aardvark", - s -> assertTrue(s.contains("aardvark"))), + a -> assertCommandOutputContains(a, "/list aardvark", "aardvark"), a -> assertCommandCheckOutput(a, "/list start", s -> checkLineToList(s, START_UP)), a -> assertCommandCheckOutput(a, "/list all", @@ -714,14 +710,14 @@ public class ToolBasicTest extends ReplToolTesting { } public void testFeedbackNegative() { - test(a -> assertCommandCheckOutput(a, "/feedback aaaa", - assertStartsWith("| Follow /feedback with of the following"))); + test(a -> assertCommandCheckOutput(a, "/set feedback aaaa", + assertStartsWith("| Does not match any current feedback mode"))); } public void testFeedbackOff() { for (String off : new String[]{"o", "off"}) { test( - a -> assertCommand(a, "/feedback " + off, ""), + a -> assertCommand(a, "/set feedback " + off, ""), a -> assertCommand(a, "int a", ""), a -> assertCommand(a, "void f() {}", ""), a -> assertCommandCheckOutput(a, "aaaa", assertStartsWith("| Error:")), @@ -730,23 +726,6 @@ public class ToolBasicTest extends ReplToolTesting { } } - public void testFeedbackConcise() { - Compiler compiler = new Compiler(); - Path testConciseFile = compiler.getPath("testConciseFeedback"); - String[] sources = new String[] {"int a", "void f() {}", "class A {}", "a = 10"}; - compiler.writeToFile(testConciseFile, sources); - for (String concise : new String[]{"c", "concise"}) { - test( - a -> assertCommand(a, "/feedback " + concise, ""), - a -> assertCommand(a, sources[0], ""), - a -> assertCommand(a, sources[1], ""), - a -> assertCommand(a, sources[2], ""), - a -> assertCommand(a, sources[3], "| a : 10\n"), - a -> assertCommand(a, "/o " + testConciseFile.toString(), "| a : 10\n") - ); - } - } - public void testFeedbackNormal() { Compiler compiler = new Compiler(); Path testNormalFile = compiler.getPath("testConciseNormal"); @@ -759,58 +738,20 @@ public class ToolBasicTest extends ReplToolTesting { "| Variable a has been assigned the value 10\n" }; compiler.writeToFile(testNormalFile, sources2); - for (String feedback : new String[]{"/f", "/feedback"}) { - for (String feedbackState : new String[]{"n", "normal", "v", "verbose"}) { - String f = null; - if (feedbackState.startsWith("n")) { - f = "normal"; - } else if (feedbackState.startsWith("v")) { - f = "verbose"; - } - final String finalF = f; + for (String feedback : new String[]{"/set f", "/set feedback"}) { + for (String feedbackState : new String[]{"n", "normal", "o", "off"}) { test( - a -> assertCommand(a, feedback + " " + feedbackState, "| Feedback mode: " + finalF +"\n"), + a -> assertCommand(a, feedback + " " + feedbackState, "| Feedback mode: normal\n"), a -> assertCommand(a, sources[0], output[0]), a -> assertCommand(a, sources[1], output[1]), a -> assertCommand(a, sources[2], output[2]), a -> assertCommand(a, sources[3], output[3]), - a -> assertCommand(a, "/o " + testNormalFile.toString(), - "| Modified variable a of type int\n" + - "| Modified method f()\n" + - "| Update overwrote method f()\n" + - "| Modified class A\n" + - "| Update overwrote class A\n" + - "| Variable a has been assigned the value 10\n") + a -> assertCommand(a, "/o " + testNormalFile.toString(), "") ); } } } - public void testFeedbackDefault() { - Compiler compiler = new Compiler(); - Path testDefaultFile = compiler.getPath("testDefaultFeedback"); - String[] sources = new String[] {"int a", "void f() {}", "class A {}", "a = 10"}; - String[] output = new String[] { - "| Added variable a of type int\n", - "| Added method f()\n", - "| Added class A\n", - "| Variable a has been assigned the value 10\n" - }; - compiler.writeToFile(testDefaultFile, sources); - for (String defaultFeedback : new String[]{"", "d", "default"}) { - test( - a -> assertCommand(a, "/feedback o", ""), - a -> assertCommand(a, "int x", ""), - a -> assertCommand(a, "/feedback " + defaultFeedback, "| Feedback mode: default\n"), - a -> assertCommand(a, sources[0], output[0]), - a -> assertCommand(a, sources[1], output[1]), - a -> assertCommand(a, sources[2], output[2]), - a -> assertCommand(a, sources[3], output[3]), - a -> assertCommand(a, "/o " + testDefaultFile.toString(), "") - ); - } - } - public void testDrop() { test(false, new String[]{"-nostartup"}, a -> assertVariable(a, "int", "a"), @@ -906,7 +847,7 @@ public class ToolBasicTest extends ReplToolTesting { public void testCommandPrefix() { test(a -> assertCommandCheckOutput(a, "/s", - assertStartsWith("| Command: /s is ambiguous: /seteditor, /save, /setstart")), + assertStartsWith("| Command: /s is ambiguous: /save, /set")), a -> assertCommand(a, "int var", "| Added variable var of type int\n"), a -> assertCommandCheckOutput(a, "/va", assertStartsWith("| int var = 0")), diff --git a/langtools/test/jdk/jshell/ToolFormatTest.java b/langtools/test/jdk/jshell/ToolFormatTest.java new file mode 100644 index 00000000000..cc3aa0273af --- /dev/null +++ b/langtools/test/jdk/jshell/ToolFormatTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8148316 8148317 + * @summary Tests for output customization + * @library /tools/lib + * @build KullaTesting TestingInputStream ToolBox Compiler + * @run testng ToolFormatTest + */ +import org.testng.annotations.Test; + +@Test +public class ToolFormatTest extends ReplToolTesting { + + public void testSetFormat() { + try { + test( + (a) -> assertCommandOutputStartsWith(a, "/set newmode test command", "| Created new feedback mode: test"), + (a) -> assertCommand(a, "/set field test pre '$ '", ""), + (a) -> assertCommand(a, "/set field test post ''", ""), + (a) -> assertCommand(a, "/set field test action 'ADD ' added-primary", ""), + (a) -> assertCommand(a, "/set field test action 'MOD ' modified-primary", ""), + (a) -> assertCommand(a, "/set field test action 'REP ' replaced-primary", ""), + (a) -> assertCommand(a, "/set field test action 'UP-ADD ' added-update", ""), + (a) -> assertCommand(a, "/set field test action 'UP-MOD ' modified-update", ""), + (a) -> assertCommand(a, "/set field test action 'UP-REP ' replaced-update", ""), + (a) -> assertCommand(a, "/set field test resolve 'OK' ok-*", ""), + (a) -> assertCommand(a, "/set field test resolve 'DEF' defined-*", ""), + (a) -> assertCommand(a, "/set field test resolve 'NODEF' notdefined-*", ""), + (a) -> assertCommand(a, "/set field test name ':%s ' ", ""), + (a) -> assertCommand(a, "/set field test type '[%s]' ", ""), + (a) -> assertCommand(a, "/set field test result '=%s ' ", ""), + (a) -> assertCommand(a, "/set format test '{pre}{action}{type}{name}{result}{resolve}' *-*-*", ""), + (a) -> assertCommand(a, "/set format test '{pre}HI this is enum' enum", ""), + (a) -> assertCommand(a, "/set feedback test", "$ Feedback mode: test"), + (a) -> assertCommand(a, "class D {}", "$ ADD :D OK"), + (a) -> assertCommand(a, "void m() {}", "$ ADD []:m OK"), + (a) -> assertCommand(a, "interface EX extends EEX {}", "$ ADD :EX NODEF"), + (a) -> assertCommand(a, "56", "$ ADD [int]:$4 =56 OK"), + (a) -> assertCommand(a, "class D { int hh; }", "$ REP :D OK$ OVERWROTE-UPDATE:D OK"), + (a) -> assertCommandOutputStartsWith(a, "/set feedback normal", "| Feedback mode: normal") + ); + } finally { + assertCommandCheckOutput(false, "/set feedback normal", s -> { + }); + } + } + + public void testNewModeQuiet() { + try { + test( + (a) -> assertCommandOutputStartsWith(a, "/set newmode nmq quiet normal", "| Created new feedback mode: nmq"), + (a) -> assertCommand(a, "/set feedback nmq", ""), + (a) -> assertCommand(a, "/se ne nmq2 q nor", ""), + (a) -> assertCommand(a, "/se fee nmq2", ""), + (a) -> assertCommand(a, "/set newmode nmc command normal", ""), + (a) -> assertCommandOutputStartsWith(a, "/set feedback nmc", "| Feedback mode: nmc"), + (a) -> assertCommandOutputStartsWith(a, "/set newmode nm", "| Created new feedback mode: nm"), + (a) -> assertCommandOutputStartsWith(a, "/set feedback nm", "| Feedback mode: nm") + ); + } finally { + assertCommandCheckOutput(false, "/set feedback normal", s -> { + }); + } + } + + public void testSetError() { + try { + test( + (a) -> assertCommandOutputStartsWith(a, "/set newmode te command normal", "| Created new feedback mode: te"), + (a) -> assertCommand(a, "/set field te errorpre 'ERROR: '", ""), + (a) -> assertCommandOutputStartsWith(a, "/set feedback te", ""), + (a) -> assertCommandCheckOutput(a, "/set ", assertStartsWith("ERROR: The /set command requires arguments")), + (a) -> assertCommandCheckOutput(a, "/set xyz", assertStartsWith("ERROR: Not a valid argument to /set")), + (a) -> assertCommandCheckOutput(a, "/set f", assertStartsWith("ERROR: Ambiguous argument to /set")), + (a) -> assertCommandCheckOutput(a, "/set feedback", assertStartsWith("ERROR: Expected a feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set feedback xyz", assertStartsWith("ERROR: Does not match any current feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set format", assertStartsWith("ERROR: Expected a feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set format xyz", assertStartsWith("ERROR: Does not match any current feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set format te", assertStartsWith("ERROR: Expected format missing")), + (a) -> assertCommandCheckOutput(a, "/set format te aaa", assertStartsWith("ERROR: Format 'aaa' must be quoted")), + (a) -> assertCommandCheckOutput(a, "/set format te 'aaa'", assertStartsWith("ERROR: At least one selector required")), + (a) -> assertCommandCheckOutput(a, "/set format te 'aaa' frog", assertStartsWith("ERROR: Not a valid case")), + (a) -> assertCommandCheckOutput(a, "/set format te 'aaa' import-frog", assertStartsWith("ERROR: Not a valid action")), + (a) -> assertCommandCheckOutput(a, "/set newmode", assertStartsWith("ERROR: Expected new feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set newmode te", assertStartsWith("ERROR: Expected a new feedback mode name")), + (a) -> assertCommandCheckOutput(a, "/set newmode x xyz", assertStartsWith("ERROR: Specify either 'command' or 'quiet'")), + (a) -> assertCommandCheckOutput(a, "/set newmode x quiet y", assertStartsWith("ERROR: Does not match any current feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set prompt", assertStartsWith("ERROR: Expected a feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set prompt te", assertStartsWith("ERROR: Expected format missing")), + (a) -> assertCommandCheckOutput(a, "/set prompt te aaa xyz", assertStartsWith("ERROR: Format 'aaa' must be quoted")), + (a) -> assertCommandCheckOutput(a, "/set prompt te 'aaa' xyz", assertStartsWith("ERROR: Format 'xyz' must be quoted")), + (a) -> assertCommandCheckOutput(a, "/set prompt", assertStartsWith("ERROR: Expected a feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set prompt te", assertStartsWith("ERROR: Expected format missing")), + (a) -> assertCommandCheckOutput(a, "/set prompt te aaa", assertStartsWith("ERROR: Format 'aaa' must be quoted")), + (a) -> assertCommandCheckOutput(a, "/set prompt te 'aaa'", assertStartsWith("ERROR: Expected format missing")), + (a) -> assertCommandCheckOutput(a, "/set field", assertStartsWith("ERROR: Expected a feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set field xyz", assertStartsWith("ERROR: Does not match any current feedback mode: xyz")), + (a) -> assertCommandCheckOutput(a, "/set field te xyz", assertStartsWith("ERROR: Not a valid field: xyz, must be one of: when")), + (a) -> assertCommandCheckOutput(a, "/set field te action", assertStartsWith("ERROR: Expected format missing")), + (a) -> assertCommandCheckOutput(a, "/set field te action 'act'", assertStartsWith("ERROR: At least one selector required")) + ); + } finally { + assertCommandCheckOutput(false, "/set feedback normal", s -> { + }); + } + } + + public void testSetHelp() { + try { + test( + (a) -> assertCommandOutputContains(a, "/help /set", "command to launch"), + (a) -> assertCommandOutputContains(a, "/help /set format", "vardecl"), + (a) -> assertCommandOutputContains(a, "/hel /se for", "vardecl"), + (a) -> assertCommandOutputContains(a, "/help /set editor", "temporary file") + ); + } finally { + assertCommandCheckOutput(false, "/set feedback normal", s -> { + }); + } + } + + public void testSetHelpError() { + try { + test( + (a) -> assertCommandOutputStartsWith(a, "/set newmode te command normal", "| Created new feedback mode: te"), + (a) -> assertCommand(a, "/set field te errorpre 'ERROR: '", ""), + (a) -> assertCommandOutputStartsWith(a, "/set feedback te", "| Feedback mode: te"), + (a) -> assertCommandOutputContains(a, "/help /set xyz", "ERROR: Not a valid argument to /set: xyz"), + (a) -> assertCommandOutputContains(a, "/help /set f", "ERROR: Ambiguous argument to /set: f") + ); + } finally { + assertCommandCheckOutput(false, "/set feedback normal", s -> { + }); + } + } +} From a0224437fcc150c04c75de8ca162d91324e3296d Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 9 Mar 2016 12:52:14 +0300 Subject: [PATCH 049/129] 8151223: String concatenation fails with implicit toString() on package-private class Reviewed-by: mcimadamore, forax --- .../com/sun/tools/javac/jvm/StringConcat.java | 26 ++- .../javac/StringConcat/access/Holder.java | 98 +++++++++ .../StringConcat/access/PublicClass.java | 27 +++ .../StringConcat/access/PublicInterface.java | 27 +++ .../access/Public_PrivateInterface1.java | 30 +++ .../access/Public_PrivateInterface2.java | 30 +++ .../access/Public_PublicClass.java | 30 +++ .../access/Public_PublicInterface.java | 30 +++ .../tools/javac/StringConcat/access/Test.java | 192 ++++++++++++++++++ 9 files changed, 486 insertions(+), 4 deletions(-) create mode 100644 langtools/test/tools/javac/StringConcat/access/Holder.java create mode 100644 langtools/test/tools/javac/StringConcat/access/PublicClass.java create mode 100644 langtools/test/tools/javac/StringConcat/access/PublicInterface.java create mode 100644 langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface1.java create mode 100644 langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface2.java create mode 100644 langtools/test/tools/javac/StringConcat/access/Public_PublicClass.java create mode 100644 langtools/test/tools/javac/StringConcat/access/Public_PublicInterface.java create mode 100644 langtools/test/tools/javac/StringConcat/access/Test.java diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java index bb5436bd96c..80cee302dec 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java @@ -33,8 +33,7 @@ import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.*; import static com.sun.tools.javac.code.Kinds.Kind.MTH; -import static com.sun.tools.javac.code.TypeTag.DOUBLE; -import static com.sun.tools.javac.code.TypeTag.LONG; +import static com.sun.tools.javac.code.TypeTag.*; import static com.sun.tools.javac.jvm.ByteCodes.*; import static com.sun.tools.javac.tree.JCTree.Tag.PLUS; import com.sun.tools.javac.jvm.Items.*; @@ -142,6 +141,25 @@ public abstract class StringConcat { return res.append(tree); } + /** + * If the type is not accessible from current context, try to figure out the + * sharpest accessible supertype. + * + * @param originalType type to sharpen + * @return sharped type + */ + Type sharpestAccessible(Type originalType) { + if (originalType.hasTag(ARRAY)) { + return types.makeArrayType(sharpestAccessible(types.elemtype(originalType))); + } + + Type type = originalType; + while (!rs.isAccessible(gen.getAttrEnv(), type.asElement())) { + type = types.supertype(type); + } + return type; + } + /** * "Legacy" bytecode flavor: emit the StringBuilder.append chains for string * concatenation. @@ -314,7 +332,7 @@ public abstract class StringConcat { if (arg.type == syms.botType) { dynamicArgs.add(types.boxedClass(syms.voidType).type); } else { - dynamicArgs.add(arg.type); + dynamicArgs.add(sharpestAccessible(arg.type)); } gen.genExpr(arg, arg.type).load(); } @@ -415,7 +433,7 @@ public abstract class StringConcat { } else { // Ordinary arguments come through the dynamic arguments. recipe.append(TAG_ARG); - dynamicArgs.add(arg.type); + dynamicArgs.add(sharpestAccessible(arg.type)); gen.genExpr(arg, arg.type).load(); } } diff --git a/langtools/test/tools/javac/StringConcat/access/Holder.java b/langtools/test/tools/javac/StringConcat/access/Holder.java new file mode 100644 index 00000000000..6b4cb37e688 --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/Holder.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1; + +public class Holder { + public Private_PublicClass c1 = new Private_PublicClass(); + public Private_PublicInterface c2 = new Private_PublicInterface(); + public Private_PrivateInterface1 c3 = new Private_PrivateInterface1(); + public Private_PrivateInterface2 c4 = new Private_PrivateInterface2(); + + public Public_PublicClass c5 = new Public_PublicClass(); + public Public_PublicInterface c6 = new Public_PublicInterface(); + public Public_PrivateInterface1 c7 = new Public_PrivateInterface1(); + public Public_PrivateInterface2 c8 = new Public_PrivateInterface2(); + + public Private_PublicClass[] ac1 = new Private_PublicClass[0]; + public Private_PublicInterface[] ac2 = new Private_PublicInterface[0]; + public Private_PrivateInterface1[] ac3 = new Private_PrivateInterface1[0]; + public Private_PrivateInterface2[] ac4 = new Private_PrivateInterface2[0]; + + public Public_PublicClass[] ac5 = new Public_PublicClass[0]; + public Public_PublicInterface[] ac6 = new Public_PublicInterface[0]; + public Public_PrivateInterface1[] ac7 = new Public_PrivateInterface1[0]; + public Public_PrivateInterface2[] ac8 = new Public_PrivateInterface2[0]; + + public Private_PublicClass[][] aac1 = new Private_PublicClass[0][]; + public Private_PublicInterface[][] aac2 = new Private_PublicInterface[0][]; + public Private_PrivateInterface1[][] aac3 = new Private_PrivateInterface1[0][]; + public Private_PrivateInterface2[][] aac4 = new Private_PrivateInterface2[0][]; + + public Public_PublicClass[][] aac5 = new Public_PublicClass[0][]; + public Public_PublicInterface[][] aac6 = new Public_PublicInterface[0][]; + public Public_PrivateInterface1[][] aac7 = new Public_PrivateInterface1[0][]; + public Public_PrivateInterface2[][] aac8 = new Public_PrivateInterface2[0][]; + + public PublicInterface i1 = new Private_PublicInterface(); + public PrivateInterface1 i2 = new Private_PrivateInterface1(); + public PrivateInterface2 i3 = new Private_PrivateInterface2(); + + public PublicInterface[] ai1 = new Private_PublicInterface[0]; + public PrivateInterface1[] ai2 = new Private_PrivateInterface1[0]; + public PrivateInterface2[] ai3 = new Private_PrivateInterface2[0]; + + public PublicInterface[][] aai1 = new Private_PublicInterface[0][]; + public PrivateInterface1[][] aai2 = new Private_PrivateInterface1[0][]; + public PrivateInterface2[][] aai3 = new Private_PrivateInterface2[0][]; +} + +interface PrivateInterface1 { +} + +interface PrivateInterface2 extends PublicInterface { +} + +class Private_PublicClass extends PublicClass { + public String toString() { + return "passed"; + } +} + +class Private_PublicInterface implements PublicInterface { + public String toString() { + return "passed"; + } +} + +class Private_PrivateInterface1 implements PrivateInterface1 { + public String toString() { + return "passed"; + } +} + +class Private_PrivateInterface2 implements PrivateInterface2 { + public String toString() { + return "passed"; + } +} diff --git a/langtools/test/tools/javac/StringConcat/access/PublicClass.java b/langtools/test/tools/javac/StringConcat/access/PublicClass.java new file mode 100644 index 00000000000..d4ae6bfc36e --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/PublicClass.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1; + +public class PublicClass { +} diff --git a/langtools/test/tools/javac/StringConcat/access/PublicInterface.java b/langtools/test/tools/javac/StringConcat/access/PublicInterface.java new file mode 100644 index 00000000000..ba26be94955 --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/PublicInterface.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1; + +public interface PublicInterface { +} diff --git a/langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface1.java b/langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface1.java new file mode 100644 index 00000000000..301f90ec798 --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface1.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1; + +public class Public_PrivateInterface1 implements PrivateInterface1 { + public String toString() { + return "passed"; + } +} diff --git a/langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface2.java b/langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface2.java new file mode 100644 index 00000000000..dcfcea14ad4 --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface2.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1; + +public class Public_PrivateInterface2 implements PrivateInterface2 { + public String toString() { + return "passed"; + } +} diff --git a/langtools/test/tools/javac/StringConcat/access/Public_PublicClass.java b/langtools/test/tools/javac/StringConcat/access/Public_PublicClass.java new file mode 100644 index 00000000000..20d28acf0d3 --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/Public_PublicClass.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1; + +public class Public_PublicClass { + public String toString() { + return "passed"; + } +} diff --git a/langtools/test/tools/javac/StringConcat/access/Public_PublicInterface.java b/langtools/test/tools/javac/StringConcat/access/Public_PublicInterface.java new file mode 100644 index 00000000000..1c8ae4b60bd --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/Public_PublicInterface.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1; + +public class Public_PublicInterface implements PublicInterface { + public String toString() { + return "passed"; + } +} diff --git a/langtools/test/tools/javac/StringConcat/access/Test.java b/langtools/test/tools/javac/StringConcat/access/Test.java new file mode 100644 index 00000000000..fc9e78c0e31 --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/Test.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8151223 + * @summary String concatenation fails with implicit toString() on package-private class + * @modules jdk.jdeps/com.sun.tools.classfile + * @compile -XDstringConcat=indy Holder.java PublicClass.java PublicInterface.java Public_PublicClass.java Public_PublicInterface.java Public_PrivateInterface1.java Public_PrivateInterface2.java Test.java + * @run main Test + * @compile -XDstringConcat=indyWithConstants Holder.java PublicClass.java PublicInterface.java Public_PublicClass.java Public_PublicInterface.java Public_PrivateInterface1.java Public_PrivateInterface2.java Test.java + * @run main Test + */ + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.ConstantPool.*; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class Test { + static List actualTypes; + + public static void main(String[] argv) throws Exception { + readIndyTypes(); + + p1.Holder holder = new p1.Holder(); + + int idx = 0; + + // ---------------------------------------------------------------------------- + + // public Private_PublicClass c1 = new Private_PublicClass(); + test("" + holder.c1, idx++, "(Lp1/PublicClass;)Ljava/lang/String;"); + + // public Private_PublicInterface c2 = new Private_PublicInterface(); + test("" + holder.c2, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + + // public Private_PrivateInterface1 c3 = new Private_PrivateInterface1(); + test("" + holder.c3, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + + // public Private_PrivateInterface2 c4 = new Private_PrivateInterface2(); + test("" + holder.c4, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + + // public Public_PublicClass c5 = new Public_PublicClass(); + test("" + holder.c5, idx++, "(Lp1/Public_PublicClass;)Ljava/lang/String;"); + + // public Public_PublicInterface c6 = new Public_PublicInterface(); + test("" + holder.c6, idx++, "(Lp1/Public_PublicInterface;)Ljava/lang/String;"); + + // public Public_PrivateInterface1 c7 = new Public_PrivateInterface1(); + test("" + holder.c7, idx++, "(Lp1/Public_PrivateInterface1;)Ljava/lang/String;"); + + // public Public_PrivateInterface2 c8 = new Public_PrivateInterface2(); + test("" + holder.c8, idx++, "(Lp1/Public_PrivateInterface2;)Ljava/lang/String;"); + + // ---------------------------------------------------------------------------- + + // public Private_PublicClass[] ac1 = new Private_PublicClass[0]; + test("" + holder.ac1, idx++, "([Lp1/PublicClass;)Ljava/lang/String;"); + + // public Private_PublicInterface[] ac2 = new Private_PublicInterface[0]; + test("" + holder.ac2, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + + // public Private_PrivateInterface1[] ac3 = new Private_PrivateInterface1[0]; + test("" + holder.ac3, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + + // public Private_PrivateInterface2[] ac4 = new Private_PrivateInterface2[0]; + test("" + holder.ac4, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + + // public Public_PublicClass[] ac5 = new Public_PublicClass[0]; + test("" + holder.ac5, idx++, "([Lp1/Public_PublicClass;)Ljava/lang/String;"); + + // public Public_PublicInterface[] ac6 = new Public_PublicInterface[0]; + test("" + holder.ac6, idx++, "([Lp1/Public_PublicInterface;)Ljava/lang/String;"); + + // public Public_PrivateInterface1[] ac7 = new Public_PrivateInterface1[0]; + test("" + holder.ac7, idx++, "([Lp1/Public_PrivateInterface1;)Ljava/lang/String;"); + + // public Public_PrivateInterface2[] ac8 = new Public_PrivateInterface2[0]; + test("" + holder.ac8, idx++, "([Lp1/Public_PrivateInterface2;)Ljava/lang/String;"); + + // ---------------------------------------------------------------------------- + + // public Private_PublicClass[][] aac1 = new Private_PublicClass[0][]; + test("" + holder.aac1, idx++, "([[Lp1/PublicClass;)Ljava/lang/String;"); + + // public Private_PublicInterface[][] aac2 = new Private_PublicInterface[0][]; + test("" + holder.aac2, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + + // public Private_PrivateInterface1[][] aac3 = new Private_PrivateInterface1[0][]; + test("" + holder.aac3, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + + // public Private_PrivateInterface2[][] aac4 = new Private_PrivateInterface2[0][]; + test("" + holder.aac4, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + + // public Public_PublicClass[][] aac5 = new Public_PublicClass[0][]; + test("" + holder.aac5, idx++, "([[Lp1/Public_PublicClass;)Ljava/lang/String;"); + + // public Public_PublicInterface[][] aac6 = new Public_PublicInterface[0][]; + test("" + holder.aac6, idx++, "([[Lp1/Public_PublicInterface;)Ljava/lang/String;"); + + // public Public_PrivateInterface1[][] aac7 = new Public_PrivateInterface1[0][]; + test("" + holder.aac7, idx++, "([[Lp1/Public_PrivateInterface1;)Ljava/lang/String;"); + + // public Public_PrivateInterface2[][] aac8 = new Public_PrivateInterface2[0][]; + test("" + holder.aac8, idx++, "([[Lp1/Public_PrivateInterface2;)Ljava/lang/String;"); + + // ---------------------------------------------------------------------------- + + // public PublicInterface i1 = new Private_PublicInterface(); + test("" + holder.i1, idx++, "(Lp1/PublicInterface;)Ljava/lang/String;"); + + // public PrivateInterface1 i2 = new Private_PrivateInterface1(); + test("" + holder.i2, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + + // public PrivateInterface2 i3 = new Private_PrivateInterface2(); + test("" + holder.i3, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + + // public PublicInterface[] ai1 = new Private_PublicInterface[0]; + test("" + holder.ai1, idx++, "([Lp1/PublicInterface;)Ljava/lang/String;"); + + // public PrivateInterface1[] ai2 = new Private_PrivateInterface1[0]; + test("" + holder.ai2, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + + // public PrivateInterface2[] ai3 = new Private_PrivateInterface2[0]; + test("" + holder.ai3, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + + // public PublicInterface[][] aai1 = new Private_PublicInterface[0][]; + test("" + holder.aai1, idx++, "([[Lp1/PublicInterface;)Ljava/lang/String;"); + + // public PrivateInterface1[][] aai2 = new Private_PrivateInterface1[0][]; + test("" + holder.aai2, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + + // public PrivateInterface2[][] aai3 = new Private_PrivateInterface2[0][]; + test("" + holder.aai3, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + + } + + public static void test(String actual, int index, String expectedType) { + if (!"passed".equals(actual) && !actual.startsWith("[")) { + throw new IllegalStateException("Unexpected result: " + actual); + } + String actualType = actualTypes.get(index); + if (!actualType.equals(expectedType)) { + throw new IllegalStateException("Unexpected type: expected = " + expectedType + ", actual = " + actualType); + } + } + + public static void readIndyTypes() throws Exception { + actualTypes = new ArrayList(); + + ClassFile classFile = ClassFile.read(new File(System.getProperty("test.classes", "."), + Test.class.getName() + ".class")); + ConstantPool constantPool = classFile.constant_pool; + + for (Method method : classFile.methods) { + if (method.getName(constantPool).equals("main")) { + Code_attribute code = (Code_attribute) method.attributes + .get(Attribute.Code); + for (Instruction i : code.getInstructions()) { + if (i.getOpcode() == Opcode.INVOKEDYNAMIC) { + CONSTANT_InvokeDynamic_info indyInfo = (CONSTANT_InvokeDynamic_info) constantPool.get(i.getUnsignedShort(1)); + CONSTANT_NameAndType_info natInfo = indyInfo.getNameAndTypeInfo(); + actualTypes.add(natInfo.getType()); + } + } + } + } + } +} From 0a352526f390f8d204ccdeace3b3fdddcd47b017 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 9 Mar 2016 18:31:49 +0300 Subject: [PATCH 050/129] 8151516: test/tools/javac/TestIndyStringConcat depends on runtime JDK details Reviewed-by: mcimadamore --- .../StringConcat/TestIndyStringConcat.java | 111 ++++++++++++++++++ .../tools/javac/StringConcat/access/Test.java | 26 ++-- .../tools/javac/TestIndyStringConcat.java | 74 ------------ 3 files changed, 126 insertions(+), 85 deletions(-) create mode 100644 langtools/test/tools/javac/StringConcat/TestIndyStringConcat.java delete mode 100644 langtools/test/tools/javac/TestIndyStringConcat.java diff --git a/langtools/test/tools/javac/StringConcat/TestIndyStringConcat.java b/langtools/test/tools/javac/StringConcat/TestIndyStringConcat.java new file mode 100644 index 00000000000..4c8917bbbf9 --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/TestIndyStringConcat.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.BootstrapMethods_attribute.BootstrapMethodSpecifier; +import com.sun.tools.classfile.ConstantPool.CONSTANT_InvokeDynamic_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_MethodHandle_info; + +import java.io.File; + +/* + * @test + * @bug 8148483 8151516 8151223 + * @summary Test that StringConcat is working for JDK >= 9 + * @modules jdk.jdeps/com.sun.tools.classfile + * + * @clean TestIndyStringConcat* + * @compile -source 6 -target 6 TestIndyStringConcat.java + * @run main TestIndyStringConcat false + * + * @clean TestIndyStringConcat* + * @compile -source 7 -target 7 TestIndyStringConcat.java + * @run main TestIndyStringConcat false + * + * @clean TestIndyStringConcat* + * @compile -source 8 -target 8 TestIndyStringConcat.java + * @run main TestIndyStringConcat false + * + * @clean TestIndyStringConcat* + * @compile -XDstringConcat=inline -source 9 -target 9 TestIndyStringConcat.java + * @run main TestIndyStringConcat false + * + * @clean TestIndyStringConcat* + * @compile -XDstringConcat=indy -source 9 -target 9 TestIndyStringConcat.java + * @run main TestIndyStringConcat true + * + * @clean TestIndyStringConcat* + * @compile -XDstringConcat=indyWithConstants -source 9 -target 9 TestIndyStringConcat.java + * @run main TestIndyStringConcat true + */ +public class TestIndyStringConcat { + + static String other; + + public static String test() { + return "Foo" + other; + } + + public static void main(String[] args) throws Exception { + boolean expected = Boolean.valueOf(args[0]); + boolean actual = hasStringConcatFactoryCall("test"); + if (expected != actual) { + throw new AssertionError("expected = " + expected + ", actual = " + actual); + } + } + + public static boolean hasStringConcatFactoryCall(String methodName) throws Exception { + ClassFile classFile = ClassFile.read(new File(System.getProperty("test.classes", "."), + TestIndyStringConcat.class.getName() + ".class")); + ConstantPool constantPool = classFile.constant_pool; + + BootstrapMethods_attribute bsm_attr = + (BootstrapMethods_attribute)classFile + .getAttribute(Attribute.BootstrapMethods); + + for (Method method : classFile.methods) { + if (method.getName(constantPool).equals(methodName)) { + Code_attribute code = (Code_attribute) method.attributes + .get(Attribute.Code); + for (Instruction i : code.getInstructions()) { + if (i.getOpcode() == Opcode.INVOKEDYNAMIC) { + CONSTANT_InvokeDynamic_info indyInfo = + (CONSTANT_InvokeDynamic_info) constantPool.get(i.getUnsignedShort(1)); + + BootstrapMethodSpecifier bsmSpec = + bsm_attr.bootstrap_method_specifiers[indyInfo.bootstrap_method_attr_index]; + + CONSTANT_MethodHandle_info bsmInfo = + (CONSTANT_MethodHandle_info) constantPool.get(bsmSpec.bootstrap_method_ref); + + if (bsmInfo.getCPRefInfo().getClassName().equals("java/lang/invoke/StringConcatFactory")) { + return true; + } + } + } + } + } + return false; + } + +} diff --git a/langtools/test/tools/javac/StringConcat/access/Test.java b/langtools/test/tools/javac/StringConcat/access/Test.java index fc9e78c0e31..72237e8b4ef 100644 --- a/langtools/test/tools/javac/StringConcat/access/Test.java +++ b/langtools/test/tools/javac/StringConcat/access/Test.java @@ -21,17 +21,6 @@ * questions. */ -/* - * @test - * @bug 8151223 - * @summary String concatenation fails with implicit toString() on package-private class - * @modules jdk.jdeps/com.sun.tools.classfile - * @compile -XDstringConcat=indy Holder.java PublicClass.java PublicInterface.java Public_PublicClass.java Public_PublicInterface.java Public_PrivateInterface1.java Public_PrivateInterface2.java Test.java - * @run main Test - * @compile -XDstringConcat=indyWithConstants Holder.java PublicClass.java PublicInterface.java Public_PublicClass.java Public_PublicInterface.java Public_PrivateInterface1.java Public_PrivateInterface2.java Test.java - * @run main Test - */ - import com.sun.tools.classfile.*; import com.sun.tools.classfile.ConstantPool.*; @@ -39,6 +28,21 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +/* + * @test + * @bug 8151223 + * @summary String concatenation fails with implicit toString() on package-private class + * @modules jdk.jdeps/com.sun.tools.classfile + * + * @clean * + * @compile -XDstringConcat=indy Holder.java PublicClass.java PublicInterface.java Public_PublicClass.java Public_PublicInterface.java Public_PrivateInterface1.java Public_PrivateInterface2.java Test.java + * @run main Test + * + * @clean * + * @compile -XDstringConcat=indyWithConstants Holder.java PublicClass.java PublicInterface.java Public_PublicClass.java Public_PublicInterface.java Public_PrivateInterface1.java Public_PrivateInterface2.java Test.java + * @run main Test + */ + public class Test { static List actualTypes; diff --git a/langtools/test/tools/javac/TestIndyStringConcat.java b/langtools/test/tools/javac/TestIndyStringConcat.java deleted file mode 100644 index b799f70015b..00000000000 --- a/langtools/test/tools/javac/TestIndyStringConcat.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @summary Test that StringConcat is working for JDK >= 9 - * @compile -source 6 -target 6 TestIndyStringConcat.java - * @run main TestIndyStringConcat false - * @clean TestIndyStringConcat* - * @compile -source 7 -target 7 TestIndyStringConcat.java - * @run main TestIndyStringConcat false - * @clean TestIndyStringConcat* - * @compile -source 8 -target 8 TestIndyStringConcat.java - * @run main TestIndyStringConcat false - * @clean TestIndyStringConcat* - * @compile -XDstringConcat=inline -source 9 -target 9 TestIndyStringConcat.java - * @run main TestIndyStringConcat false - * @clean TestIndyStringConcat* - * @compile -XDstringConcat=indy -source 9 -target 9 TestIndyStringConcat.java - * @run main TestIndyStringConcat true - * @clean TestIndyStringConcat* - * @compile -XDstringConcat=indyWithConstants -source 9 -target 9 TestIndyStringConcat.java - * @run main TestIndyStringConcat true - */ -public class TestIndyStringConcat { - - private static class MyObject { - public String toString() { - throw new RuntimeException("Boyyaa"); - } - } - - class Inner { } - - public static void main(String[] args) { - boolean useIndyConcat = Boolean.valueOf(args[0]); - try { - String s = "Foo" + new MyObject(); - } catch (RuntimeException ex) { - boolean indifiedStringConcat = false; - ex.printStackTrace(); - for (StackTraceElement e : ex.getStackTrace()) { - if (e.getClassName().contains("$$StringConcat") && - e.getMethodName().equals("concat")) { - indifiedStringConcat = true; - break; - } - } - if (indifiedStringConcat != useIndyConcat) { - throw new AssertionError(); - } - } - } -} From eb9a8ddcc4d2f3bcad1acb33198cfe53ba8aa18c Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Thu, 10 Mar 2016 08:54:29 +0100 Subject: [PATCH 051/129] 8150632: jdk.jshell.TaskFactory should use jdk.Version to check for java.specification.version Reviewed-by: rfield --- .../src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java index 0582fd66cae..f27b0c770be 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java @@ -61,6 +61,7 @@ import javax.lang.model.util.Elements; import javax.tools.FileObject; import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject; import jdk.jshell.ClassTracker.ClassInfo; +import jdk.Version; /** * The primary interface to the compiler API. Parsing, analysis, and @@ -73,6 +74,7 @@ class TaskFactory { private final MemoryFileManager fileManager; private final JShell state; private String classpath = System.getProperty("java.class.path"); + private final static Version INITIAL_SUPPORTED_VER = Version.parse("9"); TaskFactory(JShell state) { this.state = state; @@ -80,7 +82,8 @@ class TaskFactory { if (compiler == null) { throw new UnsupportedOperationException("Compiler not available, must be run with full JDK 9."); } - if (!System.getProperty("java.specification.version").equals("9")) { + Version current = Version.parse(System.getProperty("java.specification.version")); + if (INITIAL_SUPPORTED_VER.compareToIgnoreOpt(current) > 0) { throw new UnsupportedOperationException("Wrong compiler, must be run with full JDK 9."); } this.fileManager = new MemoryFileManager( From c66a688da238dca67f2c8981ad701de8cf4af382 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 10 Mar 2016 09:28:19 -0800 Subject: [PATCH 052/129] Added tag jdk-9+109 for changeset f74f056dc069 --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index 08776ccc375..5fb34d8884a 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -351,3 +351,4 @@ cb73b474703e2de266542b505cffd658bcc052da jdk-9+99 dd05d3761a341143ef4a6b1a245e0960cc125b76 jdk-9+106 7a0c343551497bd0e38ad69a77cc57d9f396615a jdk-9+107 fd18a155ad22f62e06a9b74850ab8609d415c752 jdk-9+108 +f5991c73ed73b9a355a090b65c8d7fb9a1901f89 jdk-9+109 From 19e4c511578a846d781ed5cbaf947165409b138d Mon Sep 17 00:00:00 2001 From: Robert Field Date: Thu, 10 Mar 2016 14:47:14 -0800 Subject: [PATCH 053/129] 8080069: JShell: Support for corralled classes Reviewed-by: jlahoda --- .../jdk/internal/jshell/tool/JShellTool.java | 8 +- .../share/classes/jdk/jshell/Corraller.java | 148 ++++++++++++ .../share/classes/jdk/jshell/Eval.java | 11 +- .../classes/jdk/jshell/ExecutionControl.java | 2 +- .../jshell/UnresolvedReferenceException.java | 24 +- .../share/classes/jdk/jshell/Wrap.java | 92 +++++++- langtools/test/jdk/jshell/ClassesTest.java | 9 +- langtools/test/jdk/jshell/DropTest.java | 36 +-- langtools/test/jdk/jshell/KullaTesting.java | 12 +- langtools/test/jdk/jshell/ReplaceTest.java | 215 +++++++++++++----- 10 files changed, 439 insertions(+), 118 deletions(-) create mode 100644 langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java index 10b121b4062..55eb01bb908 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java @@ -98,6 +98,7 @@ import jdk.internal.jshell.tool.Feedback.FormatCase; import jdk.internal.jshell.tool.Feedback.FormatResolve; import jdk.internal.jshell.tool.Feedback.FormatWhen; import static java.util.stream.Collectors.toList; +import static jdk.jshell.Snippet.Kind.METHOD; import static java.util.stream.Collectors.toMap; import static jdk.jshell.Snippet.SubKind.VAR_VALUE_SUBKIND; @@ -2139,7 +2140,7 @@ public class JShellTool { } //where void printUnresolved(UnresolvedReferenceException ex) { - MethodSnippet corralled = ex.getMethodSnippet(); + DeclarationSnippet corralled = ex.getSnippet(); List otherErrors = errorsOnly(state.diagnostics(corralled)); StringBuilder sb = new StringBuilder(); if (otherErrors.size() > 0) { @@ -2155,7 +2156,10 @@ public class JShellTool { sb.append("."); } - hard("Attempted to call %s which cannot be invoked until%s", corralled.name(), + String format = corralled.kind() == METHOD + ? "Attempted to call %s which cannot be invoked until%s" + : "Attempted to use %s which cannot be accessed until%s"; + hard(format, corralled.name(), unresolved(corralled), sb.toString()); if (otherErrors.size() > 0) { printDiagnostics(corralled.source(), otherErrors, true); diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java new file mode 100644 index 00000000000..349e393caa0 --- /dev/null +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jshell; + +import java.util.List; +import com.sun.source.tree.ArrayTypeTree; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MethodTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.VariableTree; +import jdk.jshell.Wrap.Range; +import static java.util.stream.Collectors.toList; + +/** + * Produce a corralled version of the Wrap for a snippet. + * + * @author Robert Field + */ +class Corraller { + + private final int index; + private final String compileSource; + private final TreeDissector dis; + + Corraller(int index, String compileSource, TreeDissector dis) { + this.index = index; + this.compileSource = compileSource; + this.dis = dis; + } + + Wrap corralTree(Tree tree, String enclosingType, int indent) { + switch (tree.getKind()) { + case VARIABLE: + return corralVariable((VariableTree) tree, indent); + case CLASS: + case ENUM: + case ANNOTATION_TYPE: + case INTERFACE: + return corralType((ClassTree) tree, indent); + case METHOD: + return corralMethod((MethodTree) tree, enclosingType, indent); + default: + return null; + } + } + + Wrap corralMethod(MethodTree mt) { + return corralMethod(mt, null, 1); + } + + Wrap corralMethod(MethodTree mt, String enclosingType, int indent) { + Range modRange = dis.treeToRange(mt.getModifiers()); + Range tpRange = dis.treeListToRange(mt.getTypeParameters()); + Range typeRange = dis.treeToRange(mt.getReturnType()); + String name = mt.getName().toString(); + if ("".equals(name)) { + name = enclosingType; + } + Range paramRange = dis.treeListToRange(mt.getParameters()); + Range throwsRange = dis.treeListToRange(mt.getThrows()); + return Wrap.corralledMethod(compileSource, + modRange, tpRange, typeRange, name, paramRange, throwsRange, index, indent); + } + + Wrap corralVariable(VariableTree vt, int indent) { + String name = vt.getName().toString(); + Range modRange = dis.treeToRange(vt.getModifiers()); + Tree baseType = vt.getType(); + StringBuilder sbBrackets = new StringBuilder(); + while (baseType instanceof ArrayTypeTree) { + //TODO handle annotations too + baseType = ((ArrayTypeTree) baseType).getType(); + sbBrackets.append("[]"); + } + Range rtype = dis.treeToRange(baseType); + Range runit = dis.treeToRange(vt); + runit = new Range(runit.begin, runit.end - 1); + ExpressionTree it = vt.getInitializer(); + int nameMax; + if (it != null) { + Range rinit = dis.treeToRange(it); + nameMax = rinit.begin - 1; + } else { + nameMax = runit.end - 1; + } + int nameStart = compileSource.lastIndexOf(name, nameMax); + if (nameStart < 0) { + throw new AssertionError("Name '" + name + "' not found"); + } + int nameEnd = nameStart + name.length(); + Range rname = new Range(nameStart, nameEnd); + return Wrap.corralledVar(compileSource, modRange, rtype, sbBrackets.toString(), rname, indent); + } + + Wrap corralType(ClassTree ct, int indent) { + boolean isClass; + switch (ct.getKind()) { + case CLASS: + isClass = true; + break; + case INTERFACE: + isClass = false; + break; + default: + return null; + } + Range modRange = dis.treeToRange(ct.getModifiers()); + String name = ct.getSimpleName().toString(); + Range tpRange = dis.treeListToRange(ct.getTypeParameters()); + Range extendsRange = dis.treeToRange(ct.getExtendsClause()); + List implementsRanges = ct.getImplementsClause().stream() + .map(ic -> dis.treeToRange(ic)) + .collect(toList()); + List members = ct.getMembers().stream() + .map(t -> corralTree(t, name, indent + 1)) + .filter(w -> w != null) + .collect(toList()); + boolean hasConstructor = ct.getMembers().stream() + .anyMatch(t -> t.getKind() == Tree.Kind.METHOD && ((MethodTree) t).getName().toString().equals("")); + Wrap wrap = Wrap.corralledType(compileSource, modRange, ct.getKind(), name, tpRange, + extendsRange, implementsRanges, members, isClass && !hasConstructor, index, indent); + return wrap; + } +} diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java index 3f01908b782..610840353ec 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java @@ -53,6 +53,7 @@ import java.util.Set; import jdk.jshell.ClassTracker.ClassInfo; import jdk.jshell.Key.ErroneousKey; import jdk.jshell.Key.MethodKey; +import jdk.jshell.Key.TypeDeclKey; import jdk.jshell.Snippet.SubKind; import jdk.jshell.TaskFactory.AnalyzeTask; import jdk.jshell.TaskFactory.BaseTask; @@ -300,7 +301,8 @@ class Eval { ClassTree klassTree = (ClassTree) unitTree; String name = klassTree.getSimpleName().toString(); Wrap guts = Wrap.classMemberWrap(compileSource); - Wrap corralled = null; //TODO + TypeDeclKey key = state.keyMap.keyForClass(name); + Wrap corralled = new Corraller(key.index(), compileSource, dis).corralType(klassTree, 1); Snippet snip = new TypeDeclSnippet(state.keyMap.keyForClass(name), userSource, guts, name, snippetKind, corralled, tds.declareReferences(), tds.bodyReferences()); @@ -362,12 +364,8 @@ class Eval { String unitName = mt.getName().toString(); Wrap guts = Wrap.classMemberWrap(compileSource); - Range modRange = dis.treeToRange(mt.getModifiers()); - Range tpRange = dis.treeListToRange(mt.getTypeParameters()); Range typeRange = dis.treeToRange(mt.getReturnType()); String name = mt.getName().toString(); - Range paramRange = dis.treeListToRange(mt.getParameters()); - Range throwsRange = dis.treeListToRange(mt.getThrows()); String parameterTypes = mt.getParameters() @@ -378,8 +376,7 @@ class Eval { MethodKey key = state.keyMap.keyForMethod(name, parameterTypes); // rewrap with correct Key index - Wrap corralled = Wrap.corralledMethod(compileSource, - modRange, tpRange, typeRange, name, paramRange, throwsRange, key.index()); + Wrap corralled = new Corraller(key.index(), compileSource, dis).corralMethod(mt); Snippet snip = new MethodSnippet(key, userSource, guts, unitName, signature, corralled, tds.declareReferences(), tds.bodyReferences()); diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java index ad115656661..8f629fd75c8 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java @@ -225,7 +225,7 @@ class ExecutionControl { int id = in.readInt(); StackTraceElement[] elems = readStackTrace(); Snippet si = maps.getSnippet(id); - throw new UnresolvedReferenceException((MethodSnippet) si, elems); + throw new UnresolvedReferenceException((DeclarationSnippet) si, elems); } case RESULT_KILLED: { proc.out.println("Killed."); diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java index eaf240d47b2..3e3de8fd943 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,33 +28,33 @@ package jdk.jshell; /** * Exception reported on attempting to execute a * {@link jdk.jshell.Snippet.Status#RECOVERABLE_DEFINED RECOVERABLE_DEFINED} - * method. + * snippet. *

* The stack can be queried by methods on Exception. * Note that in stack trace frames representing JShell Snippets, * StackTraceElement.getFileName() will return "#" followed by * the Snippet id and for snippets without a method name (for example an - * expression) StackTraceElement.getMethodName() will be the + * expression) StackTraceElement.getName() will be the * empty string. */ @SuppressWarnings("serial") // serialVersionUID intentionally omitted public class UnresolvedReferenceException extends Exception { - final MethodSnippet methodSnippet; + final DeclarationSnippet snippet; - UnresolvedReferenceException(MethodSnippet methodSnippet, StackTraceElement[] stackElements) { - super("Attempt to invoke method with unresolved references"); - this.methodSnippet = methodSnippet; + UnresolvedReferenceException(DeclarationSnippet snippet, StackTraceElement[] stackElements) { + super("Attempt to use definition snippet with unresolved references"); + this.snippet = snippet; this.setStackTrace(stackElements); } /** - * Return the method Snippet which has the unresolved reference(s). - * @return the MethodSnippet of the + * Return the Snippet which has the unresolved reference(s). + * @return the Snippet of the * {@link jdk.jshell.Snippet.Status#RECOVERABLE_DEFINED RECOVERABLE_DEFINED} - * method. + * definition snippet. */ - public MethodSnippet getMethodSnippet() { - return methodSnippet; + public DeclarationSnippet getSnippet() { + return snippet; } } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java index 1b380444936..62759319a9b 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ package jdk.jshell; import java.util.ArrayList; import java.util.List; +import com.sun.source.tree.Tree; import static jdk.internal.jshell.remote.RemoteCodes.DOIT_METHOD_NAME; /** @@ -58,9 +59,18 @@ abstract class Wrap implements GeneralWrap { return methodWrap("", source, ""); } - public static Wrap corralledMethod(String source, Range modRange, Range tpRange, Range typeRange, String name, Range paramRange, Range throwsRange, int id) { + private static String indent(int n) { + return " ".substring(0, n * 4); + } + + private static String nlindent(int n) { + return "\n" + indent(n); + } + + public static Wrap corralledMethod(String source, Range modRange, Range tpRange, + Range typeRange, String name, Range paramRange, Range throwsRange, int id, int indent) { List l = new ArrayList<>(); - l.add(" public static\n "); + l.add(indent(indent) + ((indent == 1) ? "public static" + nlindent(indent) : "")); if (!modRange.isEmpty()) { l.add(new RangeWrap(source, modRange)); l.add(" "); @@ -70,17 +80,81 @@ abstract class Wrap implements GeneralWrap { l.add(new RangeWrap(source, tpRange)); l.add("> "); } - l.add(new RangeWrap(source, typeRange)); - l.add(" " + name + "(\n "); - if (paramRange != null) { + if (!typeRange.isEmpty()) { + l.add(new RangeWrap(source, typeRange)); + l.add(" "); + } + l.add(name + "("); + if (paramRange != null && !paramRange.isEmpty()) { + l.add(nlindent(indent + 1)); l.add(new RangeWrap(source, paramRange)); } - l.add(") "); + l.add(")"); if (throwsRange != null) { - l.add("throws "); + l.add(" throws "); l.add(new RangeWrap(source, throwsRange)); } - l.add(" {\n throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");\n}\n"); + l.add(" {" + + nlindent(indent+1) + + "throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");" + + nlindent(indent) + + "}\n"); + return new CompoundWrap(l.toArray()); + } + + public static Wrap corralledType(String source, Range modRange, Tree.Kind kind, String name, Range tpRange, + Range extendsRange, List implementsRanges, List members, + boolean defaultConstructor, int id, int indent) { + boolean isInterface = kind == Tree.Kind.INTERFACE; + List l = new ArrayList<>(); + l.add(indent(indent) + ((indent == 1) ? "public static" + nlindent(indent) : "")); + if (!modRange.isEmpty()) { + l.add(new RangeWrap(source, modRange)); + l.add(" "); + } + l.add((isInterface ? "interface " : "class ") + name); + if (tpRange != null) { + l.add("<"); + l.add(new RangeWrap(source, tpRange)); + l.add("> "); + } + if (extendsRange != null && !extendsRange.isEmpty()) { + l.add(" extends "); + l.add(new RangeWrap(source, extendsRange)); + } + for (int i = 0; i < implementsRanges.size(); ++i) { + Range ir = implementsRanges.get(i); + l.add(i == 0 ? " implements " : ", "); + l.add(new RangeWrap(source, ir)); + } + if (defaultConstructor) { + l.add(" {" + + nlindent(indent+1) + + ((indent == 1)? "public " : "") + name + "() {" + + nlindent(indent+2) + + "throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");" + + nlindent(indent+1) + + "}\n"); + } else { + l.add(" {\n"); + } + l.addAll(members); + l.add(indent(indent) + "}\n"); + return new CompoundWrap(l.toArray()); + } + + public static Wrap corralledVar(String source, Range modRange, Range typeRange, String brackets, Range nameRange, int indent) { + RangeWrap wname = new RangeWrap(source, nameRange); + List l = new ArrayList<>(); + l.add(indent(indent) + ((indent == 1) ? "public static" + nlindent(indent) : "")); + if (!modRange.isEmpty()) { + l.add(new RangeWrap(source, modRange)); + l.add(" "); + } + l.add(new RangeWrap(source, typeRange)); + l.add(" "); + l.add(wname); + l.add(semi(wname)); return new CompoundWrap(l.toArray()); } diff --git a/langtools/test/jdk/jshell/ClassesTest.java b/langtools/test/jdk/jshell/ClassesTest.java index 394d88b3c0e..058714fe438 100644 --- a/langtools/test/jdk/jshell/ClassesTest.java +++ b/langtools/test/jdk/jshell/ClassesTest.java @@ -43,12 +43,13 @@ import org.testng.annotations.Test; import jdk.jshell.Diag; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED; +import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED; import static jdk.jshell.Snippet.Status.DROPPED; import static jdk.jshell.Snippet.Status.REJECTED; +import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.SubKind.*; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; -import static jdk.jshell.Snippet.Status.OVERWRITTEN; @Test public class ClassesTest extends KullaTesting { @@ -82,10 +83,10 @@ public class ClassesTest extends KullaTesting { TypeDeclSnippet c1 = (TypeDeclSnippet) assertDeclareFail("class A { void f() { return g(); } }", "compiler.err.prob.found.req"); assertTypeDeclSnippet(c1, "A", REJECTED, CLASS_SUBKIND, 0, 2); TypeDeclSnippet c2 = classKey(assertEval("class A { int f() { return g(); } }", - ste(c1, REJECTED, RECOVERABLE_NOT_DEFINED, false, null))); - assertTypeDeclSnippet(c2, "A", RECOVERABLE_NOT_DEFINED, CLASS_SUBKIND, 1, 0); + ste(c1, REJECTED, RECOVERABLE_DEFINED, true, null))); + assertTypeDeclSnippet(c2, "A", RECOVERABLE_DEFINED, CLASS_SUBKIND, 1, 0); assertDrop(c2, - ste(c2, RECOVERABLE_NOT_DEFINED, DROPPED, false, null)); + ste(c2, RECOVERABLE_DEFINED, DROPPED, true, null)); } public void classDeclaration() { diff --git a/langtools/test/jdk/jshell/DropTest.java b/langtools/test/jdk/jshell/DropTest.java index 0e61ebad700..04e9fb2a4e5 100644 --- a/langtools/test/jdk/jshell/DropTest.java +++ b/langtools/test/jdk/jshell/DropTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8081431 + * @bug 8081431 8080069 * @summary Test of JShell#drop(). * @build KullaTesting TestingInputStream * @run testng DropTest @@ -31,6 +31,7 @@ import jdk.jshell.DeclarationSnippet; import jdk.jshell.PersistentSnippet; +import jdk.jshell.VarSnippet; import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.*; @@ -45,21 +46,27 @@ public class DropTest extends KullaTesting { assertDrop(var, ste(var, VALID, DROPPED, true, null), ste(method, VALID, RECOVERABLE_DEFINED, false, var)); - //assertDrop(method, - // ste(method, RECOVERABLE_DEFINED, DROPPED, false, null), - // ste(clazz, RECOVERABLE_NOT_DEFINED, RECOVERABLE_NOT_DEFINED, false, method)); - //assertDeclareFail("new C();", "compiler.err.cant.resolve.location"); + assertDrop(method, + ste(method, RECOVERABLE_DEFINED, DROPPED, true, null), + ste(clazz, VALID, RECOVERABLE_DEFINED, false, method)); + VarSnippet cc = varKey(assertEval("C c;")); + assertEvalUnresolvedException("new C();", "C", 1, 0); assertVariables(); assertMethods(); assertClasses(); assertActiveKeys(); + method = methodKey(assertEval("int mu() { return x * 4; }", + ste(MAIN_SNIPPET, DROPPED, RECOVERABLE_DEFINED, true, null), + ste(clazz, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET))); assertEval("int x = 10;", "10", - ste(var, DROPPED, VALID, true, null), + ste(MAIN_SNIPPET, DROPPED, VALID, true, null), ste(method, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET)); PersistentSnippet c0 = varKey(assertEval("C c0 = new C();")); assertEval("c0.v();", "\"#40\""); - assertEval("C c = new C();"); + assertEval("C c = new C();", + ste(MAIN_SNIPPET, VALID, VALID, false, null), + ste(cc, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); assertEval("c.v();", "\"#40\""); assertEval("int mu() { return x * 3; }", ste(MAIN_SNIPPET, VALID, VALID, false, null), @@ -144,9 +151,10 @@ public class DropTest extends KullaTesting { DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, ste(x, VALID, DROPPED, true, null), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, x)); - assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "variable x"); - assertDeclareFail("new A().a;", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, x)); + assertEval("A foo() { return null; }"); + assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable x"); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertVariables(); assertActiveKeys(); } @@ -158,9 +166,9 @@ public class DropTest extends KullaTesting { DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, ste(x, VALID, DROPPED, true, null), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, x)); - assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "method x()"); - assertDeclareFail("new A().a;", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, x)); + assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "method x()"); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertMethods(); assertActiveKeys(); } diff --git a/langtools/test/jdk/jshell/KullaTesting.java b/langtools/test/jdk/jshell/KullaTesting.java index c2ceeea1e06..0ea4a622499 100644 --- a/langtools/test/jdk/jshell/KullaTesting.java +++ b/langtools/test/jdk/jshell/KullaTesting.java @@ -191,14 +191,14 @@ public class KullaTesting { return key; } - public MethodSnippet assertEvalUnresolvedException(String input, String name, int unresolvedSize, int diagnosticsSize) { + public DeclarationSnippet assertEvalUnresolvedException(String input, String name, int unresolvedSize, int diagnosticsSize) { List events = assertEval(input, null, UnresolvedReferenceException.class, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, null); SnippetEvent ste = events.get(0); - MethodSnippet methodKey = ((UnresolvedReferenceException) ste.exception()).getMethodSnippet(); - assertEquals(methodKey.name(), name, "Given input: " + input + ", checking name"); - assertEquals(getState().unresolvedDependencies(methodKey).size(), unresolvedSize, "Given input: " + input + ", checking unresolved"); - assertEquals(getState().diagnostics(methodKey).size(), diagnosticsSize, "Given input: " + input + ", checking diagnostics"); - return methodKey; + DeclarationSnippet sn = ((UnresolvedReferenceException) ste.exception()).getSnippet(); + assertEquals(sn.name(), name, "Given input: " + input + ", checking name"); + assertEquals(getState().unresolvedDependencies(sn).size(), unresolvedSize, "Given input: " + input + ", checking unresolved"); + assertEquals(getState().diagnostics(sn).size(), diagnosticsSize, "Given input: " + input + ", checking diagnostics"); + return sn; } public Snippet assertKeyMatch(String input, boolean isExecutable, SubKind expectedSubKind, STEInfo mainInfo, STEInfo... updates) { diff --git a/langtools/test/jdk/jshell/ReplaceTest.java b/langtools/test/jdk/jshell/ReplaceTest.java index a26545da577..36b1c505cd4 100644 --- a/langtools/test/jdk/jshell/ReplaceTest.java +++ b/langtools/test/jdk/jshell/ReplaceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* - * @test + * @test 8080069 * @summary Test of Snippet redefinition and replacement. * @build KullaTesting TestingInputStream * @run testng ReplaceTest @@ -30,6 +30,7 @@ import java.util.Collection; +import java.util.List; import jdk.jshell.Snippet; import jdk.jshell.MethodSnippet; import jdk.jshell.PersistentSnippet; @@ -38,9 +39,11 @@ import jdk.jshell.VarSnippet; import jdk.jshell.DeclarationSnippet; import org.testng.annotations.Test; +import jdk.jshell.SnippetEvent; +import jdk.jshell.UnresolvedReferenceException; +import static org.testng.Assert.assertEquals; import static jdk.jshell.Snippet.Status.*; import static jdk.jshell.Snippet.SubKind.*; -import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @Test @@ -259,7 +262,7 @@ public class ReplaceTest extends KullaTesting { ste(MAIN_SNIPPET, VALID, VALID, true, null), ste(g, VALID, OVERWRITTEN, false, MAIN_SNIPPET), ste(f, VALID, RECOVERABLE_DEFINED, false, MAIN_SNIPPET)); - MethodSnippet exsn = assertEvalUnresolvedException("t();", "f", 0, 1); + DeclarationSnippet exsn = assertEvalUnresolvedException("t();", "f", 0, 1); assertTrue(exsn == f, "Identity must not change"); assertActiveKeys(); } @@ -289,13 +292,95 @@ public class ReplaceTest extends KullaTesting { } public void testForwardVarToClass() { - DeclarationSnippet a = classKey(assertEval("class A { int f() { return g; } }", added(RECOVERABLE_NOT_DEFINED))); - assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "variable g"); + DeclarationSnippet a = classKey(assertEval("class A { int f() { return g; } }", added(RECOVERABLE_DEFINED))); + assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable g"); Snippet g = varKey(assertEval("int g = 10;", "10", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null))); + ste(a, RECOVERABLE_DEFINED, VALID, false, null))); assertEval("new A().f();", "10"); assertEval("double g = 10;", "10.0", null, + DiagCheck.DIAG_OK, + DiagCheck.DIAG_ERROR, + ste(MAIN_SNIPPET, VALID, VALID, true, null), + ste(g, VALID, OVERWRITTEN, false, MAIN_SNIPPET), + ste(a, VALID, RECOVERABLE_DEFINED, false, MAIN_SNIPPET)); + assertUnresolvedDependencies(a, 0); + assertActiveKeys(); + } + + public void testForwardVarToClassGeneric() { + DeclarationSnippet a = classKey(assertEval("class A { final T x; A(T v) { this.x = v; } ; T get() { return x; } int core() { return g; } }", added(RECOVERABLE_DEFINED))); + assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable g"); + + List events = assertEval("A as = new A<>(\"hi\");", null, + UnresolvedReferenceException.class, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, null); + SnippetEvent ste = events.get(0); + Snippet assn = ste.snippet(); + DeclarationSnippet unsn = ((UnresolvedReferenceException) ste.exception()).getSnippet(); + assertEquals(unsn.name(), "A", "Wrong with unresolved"); + assertEquals(getState().unresolvedDependencies(unsn).size(), 1, "Wrong size unresolved"); + assertEquals(getState().diagnostics(unsn).size(), 0, "Expected no diagnostics"); + + Snippet g = varKey(assertEval("int g = 10;", "10", + added(VALID), + ste(a, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET))); + assertEval("A as = new A<>(\"low\");", + ste(MAIN_SNIPPET, VALID, VALID, false, null), + ste(assn, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); + assertEval("as.get();", "\"low\""); + assertUnresolvedDependencies(a, 0); + assertActiveKeys(); + } + + public void testForwardVarToClassExtendsImplements() { + DeclarationSnippet ik = classKey(assertEval("interface I { default int ii() { return 1; } }", added(VALID))); + DeclarationSnippet jk = classKey(assertEval("interface J { default int jj() { return 2; } }", added(VALID))); + DeclarationSnippet ck = classKey(assertEval("class C { int cc() { return 3; } }", added(VALID))); + DeclarationSnippet dk = classKey(assertEval("class D extends C implements I,J { int dd() { return g; } }", added(RECOVERABLE_DEFINED))); + DeclarationSnippet ek = classKey(assertEval("class E extends D { int ee() { return 5; } }", added(VALID))); + assertUnresolvedDependencies1(dk, RECOVERABLE_DEFINED, "variable g"); + assertEvalUnresolvedException("new D();", "D", 1, 0); + assertEvalUnresolvedException("new E();", "D", 1, 0); + VarSnippet g = varKey(assertEval("int g = 10;", "10", + added(VALID), + ste(dk, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET))); + assertEval("E e = new E();"); + assertDrop(g, + ste(g, VALID, DROPPED, true, null), + ste(dk, VALID, RECOVERABLE_DEFINED, false, g)); + assertEvalUnresolvedException("new D();", "D", 1, 0); + assertEvalUnresolvedException("new E();", "D", 1, 0); + assertEval("e.ee();", "5"); + assertEvalUnresolvedException("e.dd();", "D", 1, 0); + assertEval("e.cc();", "3"); + assertEval("e.jj();", "2"); + assertEval("e.ii();", "1"); + assertActiveKeys(); + } + + public void testForwardVarToInterface() { + DeclarationSnippet i = classKey(assertEval("interface I { default int f() { return x; } }", added(RECOVERABLE_DEFINED))); + assertUnresolvedDependencies1(i, RECOVERABLE_DEFINED, "variable x"); + DeclarationSnippet c = classKey(assertEval("class C implements I { int z() { return 2; } }", added(VALID))); + assertEval("C c = new C();"); + assertEval("c.z();", "2"); + assertEvalUnresolvedException("c.f()", "I", 1, 0); + Snippet g = varKey(assertEval("int x = 55;", "55", + added(VALID), + ste(i, RECOVERABLE_DEFINED, VALID, false, null))); + assertEval("c.f();", "55"); + assertUnresolvedDependencies(i, 0); + assertActiveKeys(); + } + + public void testForwardVarToEnum() { + DeclarationSnippet a = classKey(assertEval("enum E { Q, W, E; float ff() { return fff; } }", added(RECOVERABLE_NOT_DEFINED))); + assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "variable fff"); + Snippet g = varKey(assertEval("float fff = 4.5f;", "4.5", + added(VALID), + ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null))); + assertEval("E.Q.ff();", "4.5"); + assertEval("double fff = 3.3;", "3.3", null, DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, ste(MAIN_SNIPPET, VALID, VALID, true, null), @@ -305,20 +390,21 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } - public void testForwardMethodToClass() { - DeclarationSnippet a = classKey(assertEval("class A { int f() { return g(); } }", added(RECOVERABLE_NOT_DEFINED))); - assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "method g()"); + DeclarationSnippet a = classKey(assertEval("class A { int f() { return g(); } }", added(RECOVERABLE_DEFINED))); + assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "method g()"); + assertEval("A foo() { return null; }"); + assertEvalUnresolvedException("new A();", "A", 1, 0); Snippet g = methodKey(assertEval("int g() { return 10; }", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null))); + ste(a, RECOVERABLE_DEFINED, VALID, false, null))); assertEval("new A().f();", "10"); assertEval("double g() { return 10; }", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, ste(MAIN_SNIPPET, VALID, VALID, true, null), ste(g, VALID, OVERWRITTEN, false, MAIN_SNIPPET), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET)); + ste(a, VALID, RECOVERABLE_DEFINED, false, MAIN_SNIPPET)); assertUnresolvedDependencies(a, 0); assertActiveKeys(); } @@ -336,8 +422,8 @@ public class ReplaceTest extends KullaTesting { DiagCheck.DIAG_ERROR, ste(MAIN_SNIPPET, VALID, VALID, true, null), ste(b, VALID, OVERWRITTEN, false, MAIN_SNIPPET), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET)); - assertDeclareFail("new A().b;", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, true, MAIN_SNIPPET)); + assertEvalUnresolvedException("new A().b;", "A", 0, 1); assertActiveKeys(); } @@ -503,42 +589,42 @@ public class ReplaceTest extends KullaTesting { public void testForwardSingleImportMethodToClass1() { PersistentSnippet a = classKey(assertEval("class A { String s = format(\"%d\", 10); }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.String.format;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); + ste(a, RECOVERABLE_DEFINED, VALID, false, null)); assertEval("new A().s;", "\"10\""); PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET))); - assertDeclareFail("new A().s;", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, MAIN_SNIPPET))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(format, ste(format, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, format)); + ste(a, RECOVERABLE_DEFINED, VALID, false, format)); } public void testForwardSingleImportMethodToClass2() { PersistentSnippet a = classKey(assertEval("class A { String s() { return format(\"%d\", 10); } }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.String.format;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); + ste(a, RECOVERABLE_DEFINED, VALID, false, null)); assertEval("new A().s();", "\"10\""); PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null))); - assertDeclareFail("new A().s();", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, null))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(format, ste(format, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, format)); + ste(a, RECOVERABLE_DEFINED, VALID, false, format)); } public void testForwardSingleImportClassToClass1() { @@ -589,42 +675,44 @@ public class ReplaceTest extends KullaTesting { public void testForwardImportOnDemandMethodToClass1() { PersistentSnippet a = classKey(assertEval("class A { String s = format(\"%d\", 10); }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.String.*;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); - assertEval("new A().s;", "\"10\""); + ste(a, RECOVERABLE_DEFINED, VALID, false, null)); + assertEval("A x = new A();"); + assertEval("x.s;", "\"10\""); PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null))); - assertDeclareFail("new A().s;", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, null))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(format, ste(format, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, format)); + ste(a, RECOVERABLE_DEFINED, VALID, false, format)); + assertEval("x.s;", "\"10\""); } public void testForwardImportOnDemandMethodToClass2() { PersistentSnippet a = classKey(assertEval("class A { String s() { return format(\"%d\", 10); } }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.String.*;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); + ste(a, RECOVERABLE_DEFINED, VALID, false, null)); assertEval("new A().s();", "\"10\""); PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null))); - assertDeclareFail("new A().s();", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, null))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(format, ste(format, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, format)); + ste(a, RECOVERABLE_DEFINED, VALID, false, format)); } public void testForwardImportOnDemandClassToClass1() { @@ -673,86 +761,87 @@ public class ReplaceTest extends KullaTesting { public void testForwardSingleImportFieldToClass1() { PersistentSnippet a = classKey(assertEval("class A { static double pi() { return PI; } }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.Math.PI;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); + ste(a, RECOVERABLE_DEFINED, VALID, false, null)); assertEval("Math.abs(A.pi() - 3.1415) < 0.001;", "true"); PersistentSnippet list = varKey(assertEval("String PI;", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, null))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(list, ste(list, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list)); + ste(a, RECOVERABLE_DEFINED, VALID, false, list)); } public void testForwardSingleImportFieldToClass2() { PersistentSnippet a = classKey(assertEval("class A { static double pi = PI; }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.Math.PI;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); + ste(a, RECOVERABLE_DEFINED, VALID, true, null)); assertEval("Math.abs(A.pi - 3.1415) < 0.001;", "true"); PersistentSnippet list = varKey(assertEval("String PI;", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, true, null))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(list, ste(list, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list)); + ste(a, RECOVERABLE_DEFINED, VALID, true, list)); } public void testForwardImportOnDemandFieldToClass1() { PersistentSnippet a = classKey(assertEval("class A { static double pi() { return PI; } }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.Math.*;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); + ste(a, RECOVERABLE_DEFINED, VALID, false, null)); assertEval("Math.abs(A.pi() - 3.1415) < 0.001;", "true"); PersistentSnippet list = varKey(assertEval("String PI;", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, null))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(list, ste(list, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list)); + ste(a, RECOVERABLE_DEFINED, VALID, false, list)); } public void testForwardImportOnDemandFieldToClass2() { PersistentSnippet a = classKey(assertEval("class A { static double pi = PI; }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.Math.*;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); + ste(a, RECOVERABLE_DEFINED, VALID, true, null)); assertEval("Math.abs(A.pi - 3.1415) < 0.001;", "true"); PersistentSnippet list = varKey(assertEval("String PI;", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, true, null))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(list, ste(list, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list)); + ste(a, RECOVERABLE_DEFINED, VALID, true, list)); + assertEval("Math.abs(A.pi - 3.1415) < 0.001;", "true"); } public void testReplaceCausesMethodReferenceError() { From 0bca52a90883fa850b5e0018471ef317d3df387b Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Wed, 24 Feb 2016 15:31:36 -0800 Subject: [PATCH 054/129] 8149139: [javadoc] Modify Content to accept CharSequence Reviewed-by: jjg --- .../html/AbstractExecutableMemberWriter.java | 10 ++-- .../formats/html/AbstractMemberWriter.java | 24 +------- .../doclets/formats/html/ClassWriterImpl.java | 7 +-- .../html/ConstantsSummaryWriterImpl.java | 4 +- .../formats/html/HtmlDocletWriter.java | 60 +++++++++---------- .../doclets/formats/html/LinkInfoImpl.java | 2 +- .../formats/html/MethodWriterImpl.java | 5 +- .../formats/html/PackageIndexFrameWriter.java | 2 +- .../formats/html/PropertyWriterImpl.java | 2 +- .../formats/html/TagletWriterImpl.java | 3 +- .../doclets/formats/html/markup/Comment.java | 5 +- .../formats/html/markup/ContentBuilder.java | 6 +- .../doclets/formats/html/markup/DocType.java | 5 +- .../formats/html/markup/HtmlDocument.java | 5 +- .../doclets/formats/html/markup/HtmlTree.java | 3 +- .../formats/html/markup/HtmlWriter.java | 2 +- .../doclets/formats/html/markup/RawHtml.java | 11 ++-- .../formats/html/markup/StringContent.java | 8 +-- .../internal/doclets/toolkit/Content.java | 4 +- .../internal/doclets/toolkit/util/Utils.java | 6 +- 20 files changed, 79 insertions(+), 95 deletions(-) diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java index d82da4653cd..44977bfb71a 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java @@ -104,11 +104,11 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite sb.append(utils.getFullyQualifiedName(member)); if (!utils.isConstructor(member)) { sb.append("."); - sb.append(member.getSimpleName().toString()); + sb.append(member.getSimpleName()); } sb.append(utils.flatSignature((ExecutableElement) member)); - return writer.getDocLink(MEMBER, member, sb.toString()); + return writer.getDocLink(MEMBER, member, sb); } /** @@ -204,7 +204,7 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite htmltree.addContent("("); String sep = ""; List parameters = member.getParameters(); - String indent = makeSpace(indentSize + 1); + CharSequence indent = makeSpace(indentSize + 1); TypeMirror rcvrType = member.getReceiverType(); if (includeAnnotations && rcvrType != null && utils.isAnnotated(rcvrType)) { List annotationMirrors = rcvrType.getAnnotationMirrors(); @@ -260,7 +260,7 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite protected void addExceptions(ExecutableElement member, Content htmltree, int indentSize) { List exceptions = member.getThrownTypes(); if (!exceptions.isEmpty()) { - String indent = makeSpace(indentSize + 1 - 7); + CharSequence indent = makeSpace(indentSize + 1 - 7); htmltree.addContent(DocletConstants.NL); htmltree.addContent(indent); htmltree.addContent("throws "); @@ -336,7 +336,7 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite @Override @DefinedBy(Api.LANGUAGE_MODEL) protected Boolean defaultAction(TypeMirror e, Void p) { - buf.append(e.toString()); + buf.append(e); return foundTypeVariable; } }; diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java index aa04f515ea1..50f4c099807 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java @@ -223,26 +223,6 @@ public abstract class AbstractMemberWriter { htmltree.addContent(name); } - protected String typeString(Element member) { - return new SimpleElementVisitor9() { - - @Override @DefinedBy(Api.LANGUAGE_MODEL) - public String visitExecutable(ExecutableElement e, Void p) { - return utils.isMethod(e) ? e.getReturnType().toString() : ""; - } - - @Override @DefinedBy(Api.LANGUAGE_MODEL) - public String visitVariable(VariableElement e, Void p) { - return e.toString(); - } - - @Override @DefinedBy(Api.LANGUAGE_MODEL) - protected String defaultAction(Element e, Void p) { - return ""; - } - }.visit(member); - } - /** * Add the modifier for the member. The modifiers are ordered as specified * by The Java Language Specification. @@ -282,7 +262,7 @@ public abstract class AbstractMemberWriter { } } - protected String makeSpace(int len) { + protected CharSequence makeSpace(int len) { if (len <= 0) { return ""; } @@ -290,7 +270,7 @@ public abstract class AbstractMemberWriter { for (int i = 0; i < len; i++) { sb.append(' '); } - return sb.toString(); + return sb; } /** diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java index 9356fb7f3c2..17efe9c9c52 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java @@ -199,8 +199,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite Content classPackageLabel = HtmlTree.SPAN(HtmlStyle.packageLabelInClass, packageLabel); Content pkgNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, classPackageLabel); pkgNameDiv.addContent(getSpace()); - Content pkgNameContent = getPackageLink(pkg, - new StringContent(pkg.getQualifiedName().toString())); + Content pkgNameContent = getPackageLink(pkg, new StringContent(pkg.getQualifiedName())); pkgNameDiv.addContent(pkgNameContent); div.addContent(pkgNameDiv); } @@ -395,10 +394,10 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite new LinkInfoImpl(configuration, LinkInfoImpl.Kind.TREE, typeElement)); if (configuration.shouldExcludeQualifier(utils.containingPackage(typeElement).toString())) { - li.addContent(utils.asTypeElement(type).getSimpleName().toString()); + li.addContent(utils.asTypeElement(type).getSimpleName()); li.addContent(typeParameters); } else { - li.addContent(utils.asTypeElement(type).getQualifiedName().toString()); + li.addContent(utils.asTypeElement(type).getQualifiedName()); li.addContent(typeParameters); } } else { diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java index 2b993595998..70f4a0fdd5a 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java @@ -244,7 +244,7 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter implements Cons PackageElement enclosingPackage = utils.containingPackage(typeElement); if (!enclosingPackage.isUnnamed()) { Content cb = new ContentBuilder(); - cb.addContent(enclosingPackage.getQualifiedName().toString()); + cb.addContent(enclosingPackage.getQualifiedName()); cb.addContent("."); cb.addContent(classlink); return getClassName(cb); @@ -332,7 +332,7 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter implements Cons */ private Content getNameColumn(VariableElement member) { Content nameContent = getDocLink(LinkInfoImpl.Kind.CONSTANT_SUMMARY, - member, member.getSimpleName().toString(), false); + member, member.getSimpleName(), false); Content code = HtmlTree.CODE(nameContent); return HtmlTree.TD(code); } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index c5daf0fa50b..294bc605891 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -166,6 +166,8 @@ public class HtmlDocletWriter extends HtmlDocWriter { HtmlTree fixedNavDiv = new HtmlTree(HtmlTag.DIV); + final static Pattern IMPROPER_HTML_CHARS = Pattern.compile(".*[&<>].*"); + /** * Constructor to construct the HtmlStandardWriter object. * @@ -945,7 +947,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { public Content getPackageName(PackageElement packageElement) { return packageElement == null || packageElement.isUnnamed() ? defaultPackageLabel - : getPackageLabel(packageElement.getQualifiedName().toString()); + : getPackageLabel(packageElement.getQualifiedName()); } /** @@ -954,7 +956,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { * @param packageName the package name * @return the package name content */ - public Content getPackageLabel(String packageName) { + public Content getPackageLabel(CharSequence packageName) { return new StringContent(packageName); } @@ -1038,7 +1040,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { * @param label the label for the link. * @return a content tree for the package link. */ - public Content getPackageLink(PackageElement packageElement, String label) { + public Content getPackageLink(PackageElement packageElement, CharSequence label) { return getPackageLink(packageElement, new StringContent(label)); } @@ -1081,7 +1083,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { public Content interfaceName(TypeElement typeElement, boolean qual) { Content name = new StringContent((qual) - ? typeElement.getQualifiedName().toString() + ? typeElement.getQualifiedName() : utils.getSimpleName(typeElement)); return (utils.isInterface(typeElement)) ? HtmlTree.SPAN(HtmlStyle.interfaceName, name) : name; } @@ -1279,7 +1281,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { * @param label the label for the link * @return a content tree for the element link */ - public Content getDocLink(LinkInfoImpl.Kind context, Element element, String label) { + public Content getDocLink(LinkInfoImpl.Kind context, Element element, CharSequence label) { return getDocLink(context, utils.getEnclosingTypeElement(element), element, new StringContent(label)); } @@ -1293,7 +1295,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { * @param strong true if the link should be strong. * @return the link for the given member. */ - public Content getDocLink(LinkInfoImpl.Kind context, Element element, String label, + public Content getDocLink(LinkInfoImpl.Kind context, Element element, CharSequence label, boolean strong) { return getDocLink(context, utils.getEnclosingTypeElement(element), element, label, strong); } @@ -1311,7 +1313,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { * @return the link for the given member. */ public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, - String label, boolean strong) { + CharSequence label, boolean strong) { return getDocLink(context, typeElement, element, label, strong, false); } @@ -1334,13 +1336,14 @@ public class HtmlDocletWriter extends HtmlDocWriter { * @return the link for the given member. */ public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, - String label, boolean strong, boolean isProperty) { + CharSequence label, boolean strong, boolean isProperty) { return getDocLink(context, typeElement, element, new StringContent(check(label)), strong, isProperty); } - String check(String s) { - if (s.matches(".*[&<>].*")) { - throw new IllegalArgumentException(s); + CharSequence check(CharSequence s) { + Matcher m = IMPROPER_HTML_CHARS.matcher(s); + if (m.matches()) { + throw new IllegalArgumentException(s.toString()); } return s; } @@ -1426,7 +1429,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { CommentHelper ch = utils.getCommentHelper(element); String tagName = ch.getTagName(see); - String seetext = replaceDocRootDir(utils.normalizeNewlines(ch.getText(see))); + String seetext = replaceDocRootDir(utils.normalizeNewlines(ch.getText(see)).toString()); // Check if @see is an href or "string" if (seetext.startsWith("<") || seetext.startsWith("\"")) { return new RawHtml(seetext); @@ -1452,7 +1455,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { //@see is referencing an included package if (label.isEmpty()) label = plainOrCode(isLinkPlain, - new StringContent(refPackage.getQualifiedName().toString())); + new StringContent(refPackage.getQualifiedName())); return getPackageLink(refPackage, label); } else { // @see is not referencing an included class or package. Check for cross links. @@ -1695,7 +1698,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { final Content result = new ContentBuilder() { @Override - public void addContent(String text) { + public void addContent(CharSequence text) { super.addContent(utils.normalizeNewlines(text)); } }; @@ -1741,7 +1744,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { public Boolean visitAttribute(AttributeTree node, Content c) { StringBuilder sb = new StringBuilder(SPACER).append(node.getName()); if (node.getValueKind() == ValueKind.EMPTY) { - result.addContent(sb.toString()); + result.addContent(sb); return false; } sb.append("="); @@ -1758,7 +1761,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { break; } sb.append(quote); - result.addContent(sb.toString()); + result.addContent(sb); Content docRootContent = new ContentBuilder(); for (DocTree dt : node.getValue()) { @@ -1767,16 +1770,15 @@ public class HtmlDocletWriter extends HtmlDocWriter { if (text.startsWith("/..") && !configuration.docrootparent.isEmpty()) { result.addContent(configuration.docrootparent); docRootContent = new ContentBuilder(); - text = textCleanup(text.substring(3), isLast(node)); + result.addContent(textCleanup(text.substring(3), isLast(node))); } else { if (!docRootContent.isEmpty()) { docRootContent = copyDocRootContent(docRootContent); } else { text = redirectRelativeLinks(element, (TextTree) dt); } - text = textCleanup(text, isLast(node)); + result.addContent(textCleanup(text, isLast(node))); } - result.addContent(text); } else { docRootContent = copyDocRootContent(docRootContent); dt.accept(this, docRootContent); @@ -1889,8 +1891,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { @Override @DefinedBy(Api.COMPILER_TREE) public Boolean visitStartElement(StartElementTree node, Content c) { String text = "<" + node.getName(); - text = utils.normalizeNewlines(text); - RawHtml rawHtml = new RawHtml(text); + RawHtml rawHtml = new RawHtml(utils.normalizeNewlines(text)); result.addContent(rawHtml); for (DocTree dt : node.getAttributes()) { @@ -1900,11 +1901,11 @@ public class HtmlDocletWriter extends HtmlDocWriter { return false; } - private String textCleanup(String text, boolean isLast) { + private CharSequence textCleanup(String text, boolean isLast) { return textCleanup(text, isLast, false); } - private String textCleanup(String text, boolean isLast, boolean trimLeader) { + private CharSequence textCleanup(String text, boolean isLast, boolean trimLeader) { if (trimLeader) { text = removeLeadingWhitespace(text); } @@ -1912,16 +1913,14 @@ public class HtmlDocletWriter extends HtmlDocWriter { text = removeTrailingWhitespace(text); } text = utils.replaceTabs(text); - text = utils.normalizeNewlines(text); - return text; + return utils.normalizeNewlines(text); } @Override @DefinedBy(Api.COMPILER_TREE) public Boolean visitText(TextTree node, Content c) { String text = node.getBody(); - text = textCleanup(text, isLast(node), commentRemoved); + result.addContent(new RawHtml(textCleanup(text, isLast(node), commentRemoved))); commentRemoved = false; - result.addContent(new RawHtml(text)); return false; } @@ -2358,7 +2357,8 @@ public class HtmlDocletWriter extends HtmlDocWriter { private void addAnnotations(TypeElement annotationDoc, LinkInfoImpl linkInfo, ContentBuilder annotation, Mapmap, int indent, boolean linkBreak) { - linkInfo.label = new StringContent("@" + annotationDoc.getSimpleName().toString()); + linkInfo.label = new StringContent("@"); + linkInfo.label.addContent(annotationDoc.getSimpleName()); annotation.addContent(getLink(linkInfo)); if (!map.isEmpty()) { annotation.addContent("("); @@ -2372,7 +2372,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { annotation.addContent(","); if (linkBreak) { annotation.addContent(DocletConstants.NL); - int spaces = annotationDoc.getSimpleName().toString().length() + 2; + int spaces = annotationDoc.getSimpleName().length() + 2; for (int k = 0; k < (spaces + indent); k++) { annotation.addContent(" "); } @@ -2496,7 +2496,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { @Override @DefinedBy(Api.LANGUAGE_MODEL) public Content visitEnumConstant(VariableElement c, Void p) { return getDocLink(LinkInfoImpl.Kind.ANNOTATION, - c, c.getSimpleName().toString(), false); + c, c.getSimpleName(), false); } @Override @DefinedBy(Api.LANGUAGE_MODEL) public Content visitArray(List vals, Void p) { diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkInfoImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkInfoImpl.java index 01cd9508a1a..30801a6bbc9 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkInfoImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkInfoImpl.java @@ -294,7 +294,7 @@ public class LinkInfoImpl extends LinkInfo { * Set the label for the link. * @param label plain-text label for the link */ - public LinkInfoImpl label(String label) { + public LinkInfoImpl label(CharSequence label) { this.label = new StringContent(label); return this; } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java index 40b00cdd1fd..68648d4aaaa 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java @@ -356,11 +356,10 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter Content overriddenTypeLink = writer.getLink(new LinkInfoImpl(writer.configuration, context, overriddenType)); Content codeOverridenTypeLink = HtmlTree.CODE(overriddenTypeLink); - String name = method.getSimpleName().toString(); Content methlink = writer.getLink( new LinkInfoImpl(writer.configuration, LinkInfoImpl.Kind.MEMBER, holder) - .where(writer.getName(writer.getAnchor(method))).label(name)); + .where(writer.getName(writer.getAnchor(method))).label(method.getSimpleName())); Content codeMethLink = HtmlTree.CODE(methlink); Content dd = HtmlTree.DD(codeMethLink); dd.addContent(writer.getSpace()); @@ -395,7 +394,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter dl.addContent(dt); Content methlink = writer.getDocLink( LinkInfoImpl.Kind.MEMBER, implementedMeth, - implementedMeth.getSimpleName().toString(), false); + implementedMeth.getSimpleName(), false); Content codeMethLink = HtmlTree.CODE(methlink); Content dd = HtmlTree.DD(codeMethLink); dd.addContent(writer.getSpace()); diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexFrameWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexFrameWriter.java index 064a93ce9d2..94170a334fb 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexFrameWriter.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexFrameWriter.java @@ -123,7 +123,7 @@ public class PackageIndexFrameWriter extends AbstractPackageIndexWriter { packageLinkContent = getHyperLink(DocPaths.PACKAGE_FRAME, packageLabel, "", "packageFrame"); } else { - packageLabel = getPackageLabel(pe.getQualifiedName().toString()); + packageLabel = getPackageLabel(pe.getQualifiedName()); packageLinkContent = getHyperLink(pathString(pe, DocPaths.PACKAGE_FRAME), packageLabel, "", "packageFrame"); diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java index 3a1eebc23cf..9b7ca5da8ed 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java @@ -158,7 +158,7 @@ public class PropertyWriterImpl extends AbstractMemberWriter writer.getDocLink(LinkInfoImpl.Kind.PROPERTY_COPY, holder, property, utils.isIncluded(holder) - ? holder.toString() : utils.getFullyQualifiedName(holder), + ? holder.getSimpleName() : holder.getQualifiedName(), false); Content codeLink = HtmlTree.CODE(link); Content descfrmLabel = HtmlTree.SPAN(HtmlStyle.descfrmTypeLabel, diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java index 1ae644233b2..80a4cccf532 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java @@ -91,8 +91,7 @@ public class TagletWriterImpl extends TagletWriter { */ protected Content codeTagOutput(Element element, DocTree tag) { CommentHelper ch = utils.getCommentHelper(element); - String str = utils.normalizeNewlines(ch.getText(tag)); - StringContent content = new StringContent(str); + StringContent content = new StringContent(utils.normalizeNewlines(ch.getText(tag))); Content result = HtmlTree.CODE(content); return result; } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java index 0adfc088106..32c5cc6c5b3 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,8 @@ public class Comment extends Content { * DocletAbortException because it * is not supported. */ - public void addContent(String stringContent) { + @Override + public void addContent(CharSequence stringContent) { throw new DocletAbortException("not supported"); } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java index 64ceef82473..e4a9265cbbd 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,8 +50,8 @@ public class ContentBuilder extends Content { } @Override - public void addContent(String text) { - if (text.isEmpty()) + public void addContent(CharSequence text) { + if (text.length() == 0) return; ensureMutableContents(); Content c = contents.isEmpty() ? null : contents.get(contents.size() - 1); diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/DocType.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/DocType.java index 469ee40743f..cd6739d3f1f 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/DocType.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/DocType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,7 +89,8 @@ public class DocType extends Content { * DocletAbortException because it * is not supported. */ - public void addContent(String stringContent) { + @Override + public void addContent(CharSequence stringContent) { throw new DocletAbortException("not supported"); } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java index 8f995c7c772..73da0086ab1 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,7 +90,8 @@ public class HtmlDocument extends Content { * DocletAbortException because it * is not supported. */ - public void addContent(String stringContent) { + @Override + public void addContent(CharSequence stringContent) { throw new DocletAbortException("not supported"); } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java index 93b9071dcf7..a3a40f4391e 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java @@ -132,7 +132,8 @@ public class HtmlTree extends Content { * * @param stringContent string content that needs to be added */ - public void addContent(String stringContent) { + @Override + public void addContent(CharSequence stringContent) { if (!content.isEmpty()) { Content lastContent = content.get(content.size() - 1); if (lastContent instanceof StringContent) diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlWriter.java index 88c93108672..dce9fd720a7 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlWriter.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlWriter.java @@ -475,7 +475,7 @@ public class HtmlWriter { addStyles(HtmlStyle.rowColor, vars); addStyles(HtmlStyle.tableTab, vars); addStyles(HtmlStyle.activeTableTab, vars); - script.addContent(new RawHtml(vars.toString())); + script.addContent(new RawHtml(vars)); } /** diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java index fe425dd743a..ca621a4c75a 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,8 +53,8 @@ public class RawHtml extends Content { * * @param rawHtml raw HTML text to be added */ - public RawHtml(String rawHtml) { - rawHtmlContent = nullCheck(rawHtml); + public RawHtml(CharSequence rawHtml) { + rawHtmlContent = rawHtml.toString(); } /** @@ -77,7 +77,8 @@ public class RawHtml extends Content { * DocletAbortException because it * is not supported. */ - public void addContent(String stringContent) { + @Override + public void addContent(CharSequence stringContent) { throw new DocletAbortException("not supported"); } @@ -103,7 +104,7 @@ public class RawHtml extends Content { return charCount(rawHtmlContent); } - static int charCount(String htmlText) { + static int charCount(CharSequence htmlText) { State state = State.TEXT; int count = 0; for (int i = 0; i < htmlText.length(); i++) { diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/StringContent.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/StringContent.java index 6b7c7dde2ed..cececf6b991 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/StringContent.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/StringContent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ public class StringContent extends Content { * * @param initialContent initial content for the object */ - public StringContent(String initialContent) { + public StringContent(CharSequence initialContent) { stringContent = new StringBuilder(); appendChars(initialContent); } @@ -83,7 +83,7 @@ public class StringContent extends Content { * @param strContent string content to be added */ @Override - public void addContent(String strContent) { + public void addContent(CharSequence strContent) { appendChars(strContent); } @@ -118,7 +118,7 @@ public class StringContent extends Content { return s.endsWith(DocletConstants.NL); } - private void appendChars(String s) { + private void appendChars(CharSequence s) { for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); switch (ch) { diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java index 3d2e664a3e0..7efd4250504 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ public abstract class Content { * * @param stringContent the string content to be added */ - public abstract void addContent(String stringContent); + public abstract void addContent(CharSequence stringContent); /** * Writes content to a writer. diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java index 5914a2e6013..fa2c90f1efe 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java @@ -1356,7 +1356,7 @@ public class Utils { return result.toString(); } - public String normalizeNewlines(String text) { + public CharSequence normalizeNewlines(CharSequence text) { StringBuilder sb = new StringBuilder(); final int textLength = text.length(); final String NL = DocletConstants.NL; @@ -1379,7 +1379,7 @@ public class Utils { } } sb.append(text, pos, textLength); - return sb.toString(); + return sb; } /** @@ -1746,6 +1746,8 @@ public class Utils { * A generic utility which returns the fully qualified names of an entity, * if the entity is not qualifiable then its enclosing entity, it is upto * the caller to add the elements name as required. + * @param e the element to get FQN for. + * @return the name */ public String getFullyQualifiedName(Element e) { return getFullyQualifiedName(e, true); From a9a432a1a1774056ff85e01d34fd1e4c398a5ce2 Mon Sep 17 00:00:00 2001 From: Shafi Ahmad Date: Thu, 25 Feb 2016 11:27:13 +0530 Subject: [PATCH 055/129] 8150002: Check for the validity of oop before printing it in verify_remembered_set Adding missing check for valid oop. Reviewed-by: dcubed --- hotspot/src/share/vm/gc/g1/heapRegion.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/gc/g1/heapRegion.cpp b/hotspot/src/share/vm/gc/g1/heapRegion.cpp index 1c332adcdf1..42cb7d5928a 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp @@ -781,7 +781,9 @@ public: ResourceMark rm; _containing_obj->print_on(log.error_stream()); log.error("points to obj " PTR_FORMAT " in region " HR_FORMAT, p2i(obj), HR_FORMAT_PARAMS(to)); - obj->print_on(log.error_stream()); + if (obj->is_oop()) { + obj->print_on(log.error_stream()); + } log.error("Obj head CTE = %d, field CTE = %d.", cv_obj, cv_field); log.error("----------"); _failures = true; From be1f49a6fdc3252f91763eb701b64d4c4b457ca5 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Thu, 25 Feb 2016 10:43:04 +0100 Subject: [PATCH 056/129] 8148159: [TESTBUG] TestCompilerDirectivesCompatibility tests fails on non-tiered server VMs Add whitebox for checking available compilers Reviewed-by: kvn --- test/lib/sun/hotspot/WhiteBox.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/sun/hotspot/WhiteBox.java b/test/lib/sun/hotspot/WhiteBox.java index 9964831c3c9..668d2f00c1a 100644 --- a/test/lib/sun/hotspot/WhiteBox.java +++ b/test/lib/sun/hotspot/WhiteBox.java @@ -207,7 +207,7 @@ public class WhiteBox { // Compiler public native int matchesMethod(Executable method, String pattern); public native int matchesInline(Executable method, String pattern); - public native boolean shouldPrintAssembly(Executable method); + public native boolean shouldPrintAssembly(Executable method, int comp_level); public native int deoptimizeFrames(boolean makeNotEntrant); public native void deoptimizeAll(); From 167ce92545929e1afd69eb29306cbbf40d04ecb5 Mon Sep 17 00:00:00 2001 From: Mikael Gerdin Date: Thu, 25 Feb 2016 11:20:03 +0100 Subject: [PATCH 057/129] 8150390: Move rs length sampling data to the sampling thread Reviewed-by: drwhite, jwilhelm --- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 7 +-- .../src/share/vm/gc/g1/g1CollectedHeap.hpp | 3 +- .../src/share/vm/gc/g1/g1CollectorPolicy.cpp | 3 +- .../src/share/vm/gc/g1/g1CollectorPolicy.hpp | 2 +- .../vm/gc/g1/g1YoungRemSetSamplingThread.cpp | 29 +++++++++--- hotspot/src/share/vm/gc/g1/youngList.cpp | 46 ++----------------- hotspot/src/share/vm/gc/g1/youngList.hpp | 16 +------ 7 files changed, 32 insertions(+), 74 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index f241d749045..be30e88c541 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -1400,7 +1400,6 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, JavaThread::dirty_card_queue_set().abandon_logs(); assert(dirty_card_queue_set().completed_buffers_num() == 0, "DCQS should be empty"); - _young_list->reset_sampled_info(); // At this point there should be no regions in the // entire heap tagged as young. assert(check_young_list_empty(true /* check_heap */), @@ -3390,8 +3389,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { clear_cset_fast_test(); - _young_list->reset_sampled_info(); - // Don't check the whole heap at this point as the // GC alloc regions from this pause have been tagged // as survivors and moved on to the survivor list. @@ -5188,8 +5185,8 @@ public: bool success() { return _success; } }; -bool G1CollectedHeap::check_young_list_empty(bool check_heap, bool check_sample) { - bool ret = _young_list->check_list_empty(check_sample); +bool G1CollectedHeap::check_young_list_empty(bool check_heap) { + bool ret = _young_list->check_list_empty(); if (check_heap) { NoYoungRegionsClosure closure; diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index 3d8badc27bb..a62d1c6a8ed 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -1333,8 +1333,7 @@ public: return _young_list->check_list_well_formed(); } - bool check_young_list_empty(bool check_heap, - bool check_sample = true); + bool check_young_list_empty(bool check_heap); // *** Stuff related to concurrent marking. It's not clear to me that so // many of these need to be public. diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index 93b2cce3dd1..f14e360ce44 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -787,10 +787,9 @@ double G1CollectorPolicy::predict_survivor_regions_evac_time() const { return survivor_regions_evac_time; } -void G1CollectorPolicy::revise_young_list_target_length_if_necessary() { +void G1CollectorPolicy::revise_young_list_target_length_if_necessary(size_t rs_lengths) { guarantee( adaptive_young_list_length(), "should not call this otherwise" ); - size_t rs_lengths = _g1->young_list()->sampled_rs_lengths(); if (rs_lengths > _rs_lengths_prediction) { // add 10% to avoid having to recalculate often size_t rs_lengths_prediction = rs_lengths * 1100 / 1000; diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp index fbdc47742cf..6db53e64119 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp @@ -471,7 +471,7 @@ public: // Check the current value of the young list RSet lengths and // compare it against the last prediction. If the current value is // higher, recalculate the young list target length prediction. - void revise_young_list_target_length_if_necessary(); + void revise_young_list_target_length_if_necessary(size_t rs_lengths); // This should be called after the heap is resized. void record_new_heap_size(uint new_number_of_regions); diff --git a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp index b511b04617f..8c8d216478c 100644 --- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp +++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp @@ -26,6 +26,8 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1YoungRemSetSamplingThread.hpp" +#include "gc/g1/heapRegion.inline.hpp" +#include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/suspendibleThreadSet.hpp" #include "runtime/mutexLocker.hpp" @@ -100,22 +102,35 @@ void G1YoungRemSetSamplingThread::sample_young_list_rs_lengths() { G1CollectorPolicy* g1p = g1h->g1_policy(); if (g1p->adaptive_young_list_length()) { int regions_visited = 0; - g1h->young_list()->rs_length_sampling_init(); - while (g1h->young_list()->rs_length_sampling_more()) { - g1h->young_list()->rs_length_sampling_next(); + HeapRegion* hr = g1h->young_list()->first_region(); + size_t sampled_rs_lengths = 0; + + while (hr != NULL) { + size_t rs_length = hr->rem_set()->occupied(); + sampled_rs_lengths += rs_length; + + // The current region may not yet have been added to the + // incremental collection set (it gets added when it is + // retired as the current allocation region). + if (hr->in_collection_set()) { + // Update the collection set policy information for this region + g1p->update_incremental_cset_info(hr, rs_length); + } + ++regions_visited; // we try to yield every time we visit 10 regions if (regions_visited == 10) { if (sts.should_yield()) { sts.yield(); - // we just abandon the iteration - break; + // A gc may have occurred and our sampling data is stale and further + // traversal of the young list is unsafe + return; } regions_visited = 0; } + hr = hr->get_next_young_region(); } - - g1p->revise_young_list_target_length_if_necessary(); + g1p->revise_young_list_target_length_if_necessary(sampled_rs_lengths); } } diff --git a/hotspot/src/share/vm/gc/g1/youngList.cpp b/hotspot/src/share/vm/gc/g1/youngList.cpp index 3d95e8ff93a..25b9d21d4fa 100644 --- a/hotspot/src/share/vm/gc/g1/youngList.cpp +++ b/hotspot/src/share/vm/gc/g1/youngList.cpp @@ -33,9 +33,9 @@ #include "utilities/ostream.hpp" YoungList::YoungList(G1CollectedHeap* g1h) : - _g1h(g1h), _head(NULL), _length(0), _last_sampled_rs_lengths(0), + _g1h(g1h), _head(NULL), _length(0), _survivor_head(NULL), _survivor_tail(NULL), _survivor_length(0) { - guarantee(check_list_empty(false), "just making sure..."); + guarantee(check_list_empty(), "just making sure..."); } void YoungList::push_region(HeapRegion *hr) { @@ -86,9 +86,7 @@ void YoungList::empty_list() { _survivor_tail = NULL; _survivor_length = 0; - _last_sampled_rs_lengths = 0; - - assert(check_list_empty(false), "just making sure..."); + assert(check_list_empty(), "just making sure..."); } bool YoungList::check_list_well_formed() { @@ -119,17 +117,13 @@ bool YoungList::check_list_well_formed() { return ret; } -bool YoungList::check_list_empty(bool check_sample) { +bool YoungList::check_list_empty() { bool ret = true; if (_length != 0) { log_error(gc, verify)("### YOUNG LIST should have 0 length, not %u", _length); ret = false; } - if (check_sample && _last_sampled_rs_lengths != 0) { - log_error(gc, verify)("### YOUNG LIST has non-zero last sampled RS lengths"); - ret = false; - } if (_head != NULL) { log_error(gc, verify)("### YOUNG LIST does not have a NULL head"); ret = false; @@ -141,38 +135,6 @@ bool YoungList::check_list_empty(bool check_sample) { return ret; } -void -YoungList::rs_length_sampling_init() { - _sampled_rs_lengths = 0; - _curr = _head; -} - -bool -YoungList::rs_length_sampling_more() { - return _curr != NULL; -} - -void -YoungList::rs_length_sampling_next() { - assert( _curr != NULL, "invariant" ); - size_t rs_length = _curr->rem_set()->occupied(); - - _sampled_rs_lengths += rs_length; - - // The current region may not yet have been added to the - // incremental collection set (it gets added when it is - // retired as the current allocation region). - if (_curr->in_collection_set()) { - // Update the collection set policy information for this region - _g1h->g1_policy()->update_incremental_cset_info(_curr, rs_length); - } - - _curr = _curr->get_next_young_region(); - if (_curr == NULL) { - _last_sampled_rs_lengths = _sampled_rs_lengths; - } -} - void YoungList::reset_auxilary_lists() { guarantee( is_empty(), "young list should be empty" ); diff --git a/hotspot/src/share/vm/gc/g1/youngList.hpp b/hotspot/src/share/vm/gc/g1/youngList.hpp index 36108b807db..1030b3f9c1c 100644 --- a/hotspot/src/share/vm/gc/g1/youngList.hpp +++ b/hotspot/src/share/vm/gc/g1/youngList.hpp @@ -37,14 +37,9 @@ private: HeapRegion* _survivor_head; HeapRegion* _survivor_tail; - HeapRegion* _curr; - uint _length; uint _survivor_length; - size_t _last_sampled_rs_lengths; - size_t _sampled_rs_lengths; - void empty_list(HeapRegion* list); public: @@ -72,15 +67,6 @@ public: return (size_t) survivor_length() * HeapRegion::GrainBytes; } - void rs_length_sampling_init(); - bool rs_length_sampling_more(); - void rs_length_sampling_next(); - - void reset_sampled_info() { - _last_sampled_rs_lengths = 0; - } - size_t sampled_rs_lengths() { return _last_sampled_rs_lengths; } - // for development purposes void reset_auxilary_lists(); void clear() { _head = NULL; _length = 0; } @@ -97,7 +83,7 @@ public: // debugging bool check_list_well_formed(); - bool check_list_empty(bool check_sample = true); + bool check_list_empty(); void print(); }; From 4f6dba156809d016802eee6c3f128a173665a4b7 Mon Sep 17 00:00:00 2001 From: Max Ockner Date: Thu, 25 Feb 2016 13:09:17 -0500 Subject: [PATCH 058/129] 8150103: Convert TraceClassPaths to Unified Logging TraceClassPaths has been reimplemented with Unified Logging Reviewed-by: coleenp, dholmes, iklam --- .../src/share/vm/classfile/classLoader.cpp | 49 +++++++++---------- .../src/share/vm/classfile/classLoader.hpp | 4 +- .../vm/classfile/sharedPathsMiscInfo.cpp | 39 ++++++++++----- .../vm/classfile/sharedPathsMiscInfo.hpp | 19 +------ hotspot/src/share/vm/logging/logTag.hpp | 1 + hotspot/src/share/vm/memory/filemap.cpp | 20 +++----- hotspot/src/share/vm/runtime/arguments.cpp | 13 ++--- hotspot/src/share/vm/runtime/globals.hpp | 3 -- 8 files changed, 64 insertions(+), 84 deletions(-) diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index 14feb9876cf..0a1e20df3f0 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -37,6 +37,7 @@ #include "gc/shared/generation.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/oopMapCache.hpp" +#include "logging/logTag.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "memory/oopFactory.hpp" @@ -417,34 +418,30 @@ bool ClassPathImageEntry::is_jrt() { #if INCLUDE_CDS void ClassLoader::exit_with_path_failure(const char* error, const char* message) { assert(DumpSharedSpaces, "only called at dump time"); - tty->print_cr("Hint: enable -XX:+TraceClassPaths to diagnose the failure"); + tty->print_cr("Hint: enable -Xlog:classpath=info to diagnose the failure"); vm_exit_during_initialization(error, message); } #endif -void ClassLoader::trace_class_path(outputStream* out, const char* msg, const char* name) { - if (!TraceClassPaths) { - return; - } - - if (msg) { - out->print("%s", msg); - } - if (name) { - if (strlen(name) < 256) { - 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') { - out->print("%c", name[0]); - name++; +void ClassLoader::trace_class_path(const char* msg, const char* name) { + if (log_is_enabled(Info, classpath)) { + ResourceMark rm; + outputStream* out = LogHandle(classpath)::info_stream(); + if (msg) { + out->print("%s", msg); + } + if (name) { + if (strlen(name) < 256) { + 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') { + out->print("%c", name[0]); + name++; + } } } - } - if (msg && msg[0] == '[') { - out->print_cr("]"); - } else { out->cr(); } } @@ -470,11 +467,13 @@ void ClassLoader::check_shared_classpath(const char *path) { void ClassLoader::setup_bootstrap_search_path() { assert(_first_entry == NULL, "should not setup bootstrap class search path twice"); const char* sys_class_path = Arguments::get_sysclasspath(); + const char* java_class_path = Arguments::get_appclasspath(); if (PrintSharedArchiveAndExit) { // 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(tty, "[Bootstrap loader class path=", sys_class_path); + trace_class_path("bootstrap loader class path=", sys_class_path); + trace_class_path("classpath: ", java_class_path); } #if INCLUDE_CDS if (DumpSharedSpaces) { @@ -578,9 +577,7 @@ ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const str } } } - if (TraceClassPaths) { - tty->print_cr("[Opened %s]", path); - } + log_info(classpath)("opened: %s", path); log_info(classload)("opened: %s", path); } else { // Directory diff --git a/hotspot/src/share/vm/classfile/classLoader.hpp b/hotspot/src/share/vm/classfile/classLoader.hpp index 92ee90f2675..c2a68c04b09 100644 --- a/hotspot/src/share/vm/classfile/classLoader.hpp +++ b/hotspot/src/share/vm/classfile/classLoader.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -331,7 +331,7 @@ class ClassLoader: AllStatic { static void exit_with_path_failure(const char* error, const char* message); #endif - static void trace_class_path(outputStream* out, const char* msg, const char* name = NULL); + static void trace_class_path(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 9233e3243ad..40843700bd6 100644 --- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,15 +26,15 @@ #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/sharedPathsMiscInfo.hpp" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/metaspaceShared.hpp" #include "runtime/arguments.hpp" +#include "utilities/ostream.hpp" void SharedPathsMiscInfo::add_path(const char* path, int type) { - if (TraceClassPaths) { - tty->print("[type=%s] ", type_name(type)); - trace_class_path("[Add misc shared path ", path); - } + log_info(classpath)("type=%s ", type_name(type)); + ClassLoader::trace_class_path("add misc shared path ", path); write(path, strlen(path) + 1); write_jint(jint(type)); } @@ -67,11 +67,29 @@ bool SharedPathsMiscInfo::read(void* ptr, size_t size) { } bool SharedPathsMiscInfo::fail(const char* msg, const char* name) { - ClassLoader::trace_class_path(tty, msg, name); + ClassLoader::trace_class_path(msg, name); MetaspaceShared::set_archive_loading_failed(); return false; } +void SharedPathsMiscInfo::print_path(int type, const char* path) { + ResourceMark rm; + outputStream* out = LogHandle(classpath)::info_stream(); + switch (type) { + case BOOT: + out->print("Expecting -Dsun.boot.class.path=%s", path); + break; + case NON_EXIST: + out->print("Expecting that %s does not exist", path); + break; + case REQUIRED: + out->print("Expecting that file %s must exist and is not altered", path); + break; + default: + ShouldNotReachHere(); + } +} + bool SharedPathsMiscInfo::check() { // The whole buffer must be 0 terminated so that we can use strlen and strcmp // without fear. @@ -90,17 +108,14 @@ bool SharedPathsMiscInfo::check() { if (!read_jint(&type)) { return fail("Corrupted archive file header"); } - if (TraceClassPaths) { - tty->print("[type=%s ", type_name(type)); - print_path(tty, type, path); - tty->print_cr("]"); - } + log_info(classpath)("type=%s ", type_name(type)); + print_path(type, path); if (!check(type, path)) { if (!PrintSharedArchiveAndExit) { return false; } } else { - trace_class_path("[ok"); + ClassLoader::trace_class_path("ok"); } } diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp index 652d20c883a..435630febac 100644 --- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp @@ -64,9 +64,6 @@ protected: void write(const void* ptr, size_t size); bool read(void* ptr, size_t size); - static void trace_class_path(const char* msg, const char* name = NULL) { - ClassLoader::trace_class_path(tty, msg, name); - } protected: static bool fail(const char* msg, const char* name = NULL); virtual bool check(jint type, const char* path); @@ -144,21 +141,7 @@ public: } } - virtual void print_path(outputStream* out, int type, const char* path) { - switch (type) { - case BOOT: - out->print("Expecting -Dsun.boot.class.path=%s", path); - break; - case NON_EXIST: - out->print("Expecting that %s does not exist", path); - break; - case REQUIRED: - out->print("Expecting that file %s must exist and is not altered", path); - break; - default: - ShouldNotReachHere(); - } - } + virtual void print_path(int type, const char* path); bool check(); bool read_jint(jint *ptr) { diff --git a/hotspot/src/share/vm/logging/logTag.hpp b/hotspot/src/share/vm/logging/logTag.hpp index 16a91cfbddf..08a78c6b2ba 100644 --- a/hotspot/src/share/vm/logging/logTag.hpp +++ b/hotspot/src/share/vm/logging/logTag.hpp @@ -43,6 +43,7 @@ LOG_TAG(classload) /* Trace all classes loaded */ \ LOG_TAG(classloaderdata) /* class loader loader_data lifetime */ \ LOG_TAG(classunload) /* Trace unloading of classes */ \ + LOG_TAG(classpath) \ LOG_TAG(compaction) \ LOG_TAG(cpu) \ LOG_TAG(cset) \ diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp index 2a82e60c063..1b21736315c 100644 --- a/hotspot/src/share/vm/memory/filemap.cpp +++ b/hotspot/src/share/vm/memory/filemap.cpp @@ -208,9 +208,7 @@ void FileMapInfo::allocate_classpath_entry_table() { count ++; bytes += (int)entry_size; bytes += name_bytes; - if (TraceClassPaths) { - tty->print_cr("[Add main shared path (%s) %s]", (cpe->is_jar_file() ? "jar" : "dir"), name); - } + log_info(classpath)("add main shared path (%s) %s", (cpe->is_jar_file() ? "jar" : "dir"), name); } else { SharedClassPathEntry* ent = shared_classpath(cur_entry); if (cpe->is_jar_file()) { @@ -275,9 +273,7 @@ bool FileMapInfo::validate_classpath_entry_table() { struct stat st; const char* name = ent->_name; bool ok = true; - if (TraceClassPaths) { - tty->print_cr("[Checking shared classpath entry: %s]", name); - } + log_info(classpath)("checking shared classpath entry: %s", name); if (os::stat(name, &st) != 0) { fail_continue("Required classpath entry does not exist: %s", name); ok = false; @@ -301,9 +297,7 @@ bool FileMapInfo::validate_classpath_entry_table() { } } if (ok) { - if (TraceClassPaths) { - tty->print_cr("[ok]"); - } + log_info(classpath)("ok"); } else if (!PrintSharedArchiveAndExit) { _validating_classpath_entry_table = false; return false; @@ -888,10 +882,8 @@ bool FileMapInfo::FileMapHeader::validate() { char header_version[JVM_IDENT_MAX]; get_header_version(header_version); if (strncmp(_jvm_ident, header_version, JVM_IDENT_MAX-1) != 0) { - if (TraceClassPaths) { - tty->print_cr("Expected: %s", header_version); - tty->print_cr("Actual: %s", _jvm_ident); - } + log_info(classpath)("expected: %s", header_version); + log_info(classpath)("actual: %s", _jvm_ident); FileMapInfo::fail_continue("The shared archive file was created by a different" " version or build of HotSpot"); return false; @@ -919,7 +911,7 @@ bool FileMapInfo::validate_header() { if (status) { if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size)) { if (!PrintSharedArchiveAndExit) { - fail_continue("shared class paths mismatch (hint: enable -XX:+TraceClassPaths to diagnose the failure)"); + fail_continue("shared class paths mismatch (hint: enable -Xlog:classpath=info to diagnose the failure)"); status = false; } } diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index f43a7a1372f..512c29fc94d 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -405,8 +405,9 @@ static AliasedFlag const aliased_jvm_flags[] = { static AliasedLoggingFlag const aliased_logging_flags[] = { { "TraceClassLoading", LogLevel::Info, true, LogTag::_classload }, - { "TraceClassUnloading", LogLevel::Info, true, LogTag::_classunload }, + { "TraceClassPaths", LogLevel::Info, true, LogTag::_classpath }, { "TraceClassResolution", LogLevel::Info, true, LogTag::_classresolve }, + { "TraceClassUnloading", LogLevel::Info, true, LogTag::_classunload }, { "TraceExceptions", LogLevel::Info, true, LogTag::_exceptions }, { "TraceMonitorInflation", LogLevel::Debug, true, LogTag::_monitorinflation }, { "TraceBiasedLocking", LogLevel::Info, true, LogTag::_biasedlocking }, @@ -3255,7 +3256,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, // PrintSharedArchiveAndExit will turn on // -Xshare:on - // -XX:+TraceClassPaths + // -Xlog:classpath=info if (PrintSharedArchiveAndExit) { if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) { return JNI_EINVAL; @@ -3263,9 +3264,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, TraceClassPaths, true) != Flag::SUCCESS) { - return JNI_EINVAL; - } + LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(classpath)); } // Change the default value for flags which have different default values @@ -3318,10 +3317,6 @@ void Arguments::fix_appclasspath() { _java_class_path->set_value(copy); FreeHeap(copy); // a copy was made by set_value, so don't need this anymore } - - if (!PrintSharedArchiveAndExit) { - ClassLoader::trace_class_path(tty, "[classpath: ", _java_class_path->value()); - } } static bool has_jar_files(const char* directory) { diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index ce36ff1db49..3c6219a4402 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -2403,9 +2403,6 @@ public: product(bool, IgnoreEmptyClassPaths, false, \ "Ignore empty path elements in -classpath") \ \ - product(bool, TraceClassPaths, false, \ - "Trace processing of class paths") \ - \ product(bool, TraceClassLoadingPreorder, false, \ "Trace all classes loaded in order referenced (not loaded)") \ \ From 917dc3b87c2d3fa0608727085a42189479a24c7e Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 26 Feb 2016 13:02:30 +0100 Subject: [PATCH 059/129] 8140777: Make Adaptive IHOP logging information the same as JFR logging Reviewed-by: tbenson, jmasa --- hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp b/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp index 0cf5dab9448..5759ed0c68f 100644 --- a/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp +++ b/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,14 +47,16 @@ void G1IHOPControl::update_allocation_info(double allocation_time_s, size_t allo void G1IHOPControl::print() { size_t cur_conc_mark_start_threshold = get_conc_mark_start_threshold(); - log_debug(gc, ihop)("Basic information (value update), threshold: " SIZE_FORMAT "B (%1.2f), target occupancy: " SIZE_FORMAT "B, current occupancy: " SIZE_FORMAT "B," - " recent old gen allocation rate: %1.2f, recent marking phase length: %1.2f", + log_debug(gc, ihop)("Basic information (value update), threshold: " SIZE_FORMAT "B (%1.2f), target occupancy: " SIZE_FORMAT "B, current occupancy: " SIZE_FORMAT "B, " + "recent allocation size: " SIZE_FORMAT "B, recent allocation duration: %1.2fms, recent old gen allocation rate: %1.2fB/s, recent marking phase length: %1.2fms", cur_conc_mark_start_threshold, cur_conc_mark_start_threshold * 100.0 / _target_occupancy, _target_occupancy, G1CollectedHeap::heap()->used(), + _last_allocated_bytes, + _last_allocation_time_s * 1000.0, _last_allocation_time_s > 0.0 ? _last_allocated_bytes / _last_allocation_time_s : 0.0, - last_marking_length_s()); + last_marking_length_s() * 1000.0); } void G1IHOPControl::send_trace_event(G1NewTracer* tracer) { @@ -191,13 +193,16 @@ void G1AdaptiveIHOPControl::update_marking_length(double marking_length_s) { void G1AdaptiveIHOPControl::print() { G1IHOPControl::print(); size_t actual_target = actual_target_threshold(); - log_debug(gc, ihop)("Adaptive IHOP information (value update), threshold: " SIZE_FORMAT "B (%1.2f), internal target occupancy: " SIZE_FORMAT "B," - " predicted old gen allocation rate: %1.2f, predicted marking phase length: %1.2f, prediction active: %s", + log_debug(gc, ihop)("Adaptive IHOP information (value update), threshold: " SIZE_FORMAT "B (%1.2f), internal target occupancy: " SIZE_FORMAT "B, " + "occupancy: " SIZE_FORMAT "B, additional buffer size: " SIZE_FORMAT "B, predicted old gen allocation rate: %1.2fB/s, " + "predicted marking phase length: %1.2fms, prediction active: %s", get_conc_mark_start_threshold(), percent_of(get_conc_mark_start_threshold(), actual_target), actual_target, + G1CollectedHeap::heap()->used(), + _last_unrestrained_young_size, _predictor->get_new_prediction(&_allocation_rate_s), - _predictor->get_new_prediction(&_marking_times_s), + _predictor->get_new_prediction(&_marking_times_s) * 1000.0, have_enough_data_for_prediction() ? "true" : "false"); } From d00c7378d6fd9b41ae66fece438c1975bf1d835b Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 26 Feb 2016 13:02:30 +0100 Subject: [PATCH 060/129] 8076463: Add logging for the preserve CM referents task Add logging and do minor refactoring to CM referents handling task. Reviewed-by: jmasa --- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 25 +++++++++++++------ .../src/share/vm/gc/g1/g1CollectedHeap.hpp | 3 +++ hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp | 6 ++++- hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp | 9 ++++++- hotspot/test/gc/g1/TestGCLogMessages.java | 6 +++-- 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index f241d749045..860df5306a5 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -4398,6 +4398,8 @@ public: { } void work(uint worker_id) { + G1GCParPhaseTimesTracker x(_g1h->g1_policy()->phase_times(), G1GCPhaseTimes::PreserveCMReferents, worker_id); + ResourceMark rm; HandleMark hm; @@ -4461,13 +4463,8 @@ void G1CollectedHeap::process_weak_jni_handles() { 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(); - - ReferenceProcessor* rp = _ref_processor_stw; - assert(rp->discovery_enabled(), "should have been enabled"); - +void G1CollectedHeap::preserve_cm_referents(G1ParScanThreadStateSet* per_thread_states) { + double preserve_cm_referents_start = os::elapsedTime(); // Any reference objects, in the collection set, that were 'discovered' // by the CM ref processor should have already been copied (either by // applying the external root copy closure to the discovered lists, or @@ -4495,9 +4492,18 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per per_thread_states, no_of_gc_workers, _task_queues); - workers()->run_task(&keep_cm_referents); + g1_policy()->phase_times()->record_preserve_cm_referents_time_ms((os::elapsedTime() - preserve_cm_referents_start) * 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(); + + ReferenceProcessor* rp = _ref_processor_stw; + assert(rp->discovery_enabled(), "should have been enabled"); + // Closure to test whether a referent is alive. G1STWIsAliveClosure is_alive(this); @@ -4529,6 +4535,8 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per NULL, _gc_timer_stw); } else { + uint no_of_gc_workers = workers()->active_workers(); + // Parallel reference processing assert(rp->num_q() == no_of_gc_workers, "sanity"); assert(no_of_gc_workers <= rp->max_num_q(), "sanity"); @@ -4644,6 +4652,7 @@ void G1CollectedHeap::post_evacuate_collection_set(EvacuationInfo& evacuation_in // objects (and their reachable sub-graphs) that were // not copied during the pause. if (g1_policy()->should_process_references()) { + preserve_cm_referents(per_thread_states); process_discovered_references(per_thread_states); } else { ref_processor_stw()->verify_no_references_recorded(); diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index 3d8badc27bb..f381ee5b7db 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -511,6 +511,9 @@ protected: // allocated block, or else "NULL". HeapWord* expand_and_allocate(size_t word_size, AllocationContext_t context); + // Preserve any referents discovered by concurrent marking that have not yet been + // copied by the STW pause. + void preserve_cm_referents(G1ParScanThreadStateSet* per_thread_states); // Process any reference objects discovered during // an incremental evacuation pause. void process_discovered_references(G1ParScanThreadStateSet* per_thread_states); diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp index 706495fdbc7..8fefab03f65 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,6 +129,8 @@ G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) : _gc_par_phases[RedirtyCards] = new WorkerDataArray(max_gc_threads, "Parallel Redirty:", true, 3); _redirtied_cards = new WorkerDataArray(max_gc_threads, "Redirtied Cards:", true, 3); _gc_par_phases[RedirtyCards]->link_thread_work_items(_redirtied_cards); + + _gc_par_phases[PreserveCMReferents] = new WorkerDataArray(max_gc_threads, "Parallel Preserve CM Refs:", true, 3); } void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) { @@ -392,10 +394,12 @@ void G1GCPhaseTimes::print() { print_stats(Indents[2], "Choose CSet", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms)); + print_stats(Indents[2], "Preserve CM Refs", _recorded_preserve_cm_referents_time_ms); print_stats(Indents[2], "Ref Proc", _cur_ref_proc_time_ms); print_stats(Indents[2], "Ref Enq", _cur_ref_enq_time_ms); print_stats(Indents[2], "Redirty Cards", _recorded_redirty_logged_cards_time_ms); par_phase_printer.print(RedirtyCards); + par_phase_printer.print(PreserveCMReferents); if (G1EagerReclaimHumongousObjects) { print_stats(Indents[2], "Humongous Register", _cur_fast_reclaim_humongous_register_time_ms); diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp index 5607c3f4ea0..a4e6ff1dec5 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,6 +69,7 @@ class G1GCPhaseTimes : public CHeapObj { StringDedupQueueFixup, StringDedupTableFixup, RedirtyCards, + PreserveCMReferents, GCParPhasesSentinel }; @@ -108,6 +109,8 @@ class G1GCPhaseTimes : public CHeapObj { double _recorded_redirty_logged_cards_time_ms; + double _recorded_preserve_cm_referents_time_ms; + double _recorded_young_free_cset_time_ms; double _recorded_non_young_free_cset_time_ms; @@ -234,6 +237,10 @@ class G1GCPhaseTimes : public CHeapObj { _recorded_redirty_logged_cards_time_ms = time_ms; } + void record_preserve_cm_referents_time_ms(double time_ms) { + _recorded_preserve_cm_referents_time_ms = time_ms; + } + void record_cur_collection_start_sec(double time_ms) { _cur_collection_start_sec = time_ms; } diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java index 8ab921b0186..c0f83fc1fe0 100644 --- a/hotspot/test/gc/g1/TestGCLogMessages.java +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test TestGCLogMessages - * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 8069330 + * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 8069330 8076463 * @summary Ensure the output for a minor GC with G1 * includes the expected necessary messages. * @key gc @@ -86,6 +86,8 @@ public class TestGCLogMessages { // Humongous Eager Reclaim new LogMessageWithLevel("Humongous Reclaim", Level.DEBUG), new LogMessageWithLevel("Humongous Register", Level.DEBUG), + // Preserve CM Referents + new LogMessageWithLevel("Preserve CM Refs", Level.DEBUG), }; void checkMessagesAtLevel(OutputAnalyzer output, LogMessageWithLevel messages[], Level level) throws Exception { From 6fe8d6e7de9f68558d8350c12935eb28095bbec9 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 26 Feb 2016 13:02:30 +0100 Subject: [PATCH 061/129] 8150630: Add logging for ParScanThreadState merge phase Improve visibility of the per-thread scan state merge phase by adding appropriate logging. Reviewed-by: jmasa, tbenson --- hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp | 8 +++++++- hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp | 3 +++ hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp | 1 + hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp | 6 ++++++ hotspot/test/gc/g1/TestGCLogMessages.java | 4 +++- 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index 860df5306a5..6b1f7f0d389 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -4594,6 +4594,12 @@ void G1CollectedHeap::enqueue_discovered_references(G1ParScanThreadStateSet* per g1_policy()->phase_times()->record_ref_enq_time(ref_enq_time * 1000.0); } +void G1CollectedHeap::merge_per_thread_state_info(G1ParScanThreadStateSet* per_thread_states) { + double merge_pss_time_start = os::elapsedTime(); + per_thread_states->flush(); + g1_policy()->phase_times()->record_merge_pss_time_ms((os::elapsedTime() - merge_pss_time_start) * 1000.0); +} + void G1CollectedHeap::pre_evacuate_collection_set() { _expand_heap_after_alloc_failure = true; _evacuation_failed = false; @@ -4696,7 +4702,7 @@ void G1CollectedHeap::post_evacuate_collection_set(EvacuationInfo& evacuation_in _allocator->release_gc_alloc_regions(evacuation_info); - per_thread_states->flush(); + merge_per_thread_state_info(per_thread_states); record_obj_copy_mem_stats(); diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index f381ee5b7db..bce50eb7a5b 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -522,6 +522,9 @@ protected: // after processing. void enqueue_discovered_references(G1ParScanThreadStateSet* per_thread_states); + // Merges the information gathered on a per-thread basis for all worker threads + // during GC into global variables. + void merge_per_thread_state_info(G1ParScanThreadStateSet* per_thread_states); public: WorkGang* workers() const { return _workers; } diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp index 8fefab03f65..e8c852b051f 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp @@ -413,6 +413,7 @@ void G1GCPhaseTimes::print() { _recorded_non_young_free_cset_time_ms)); log_trace(gc, phases)("%sYoung Free CSet: %.1lf ms", Indents[3], _recorded_young_free_cset_time_ms); log_trace(gc, phases)("%sNon-Young Free CSet: %.1lf ms", Indents[3], _recorded_non_young_free_cset_time_ms); + print_stats(Indents[2], "Merge Per-Thread State", _recorded_merge_pss_time_ms); if (_cur_verify_after_time_ms > 0.0) { print_stats(Indents[2], "Verify After", _cur_verify_after_time_ms); } diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp index a4e6ff1dec5..c474659a849 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp @@ -111,6 +111,8 @@ class G1GCPhaseTimes : public CHeapObj { double _recorded_preserve_cm_referents_time_ms; + double _recorded_merge_pss_time_ms; + double _recorded_young_free_cset_time_ms; double _recorded_non_young_free_cset_time_ms; @@ -241,6 +243,10 @@ class G1GCPhaseTimes : public CHeapObj { _recorded_preserve_cm_referents_time_ms = time_ms; } + void record_merge_pss_time_ms(double time_ms) { + _recorded_merge_pss_time_ms = time_ms; + } + void record_cur_collection_start_sec(double time_ms) { _cur_collection_start_sec = time_ms; } diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java index c0f83fc1fe0..0659c98f1c9 100644 --- a/hotspot/test/gc/g1/TestGCLogMessages.java +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -23,7 +23,7 @@ /* * @test TestGCLogMessages - * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 8069330 8076463 + * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 8069330 8076463 8150630 * @summary Ensure the output for a minor GC with G1 * includes the expected necessary messages. * @key gc @@ -88,6 +88,8 @@ public class TestGCLogMessages { new LogMessageWithLevel("Humongous Register", Level.DEBUG), // Preserve CM Referents new LogMessageWithLevel("Preserve CM Refs", Level.DEBUG), + // Merge PSS + new LogMessageWithLevel("Merge Per-Thread State", Level.DEBUG), }; void checkMessagesAtLevel(OutputAnalyzer output, LogMessageWithLevel messages[], Level level) throws Exception { From d090b747441eaec656cc785e165e61bda27bf037 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 26 Feb 2016 13:02:30 +0100 Subject: [PATCH 062/129] 8150629: Initializing all ParScanThreadStates causes significant unaccounted "Other" times Lazily allocate ParScanThreadStates within the worker threads instead of doing this work upfront serially. Reviewed-by: mgerdin, jmasa --- hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp | 9 ++++++++- hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp | 6 ++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp index f22c6e2195c..b59fc203c6c 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -327,6 +327,9 @@ oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state, G1ParScanThreadState* G1ParScanThreadStateSet::state_for_worker(uint worker_id) { assert(worker_id < _n_workers, "out of bounds access"); + if (_states[worker_id] == NULL) { + _states[worker_id] = new_par_scan_state(worker_id, _young_cset_length); + } return _states[worker_id]; } @@ -352,6 +355,10 @@ void G1ParScanThreadStateSet::flush() { for (uint worker_index = 0; worker_index < _n_workers; ++worker_index) { G1ParScanThreadState* pss = _states[worker_index]; + if (pss == NULL) { + continue; + } + _total_cards_scanned += _cards_scanned[worker_index]; pss->flush(_surviving_young_words_total); diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp index 47c5328d2b9..6accb48c1de 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -200,6 +200,7 @@ class G1ParScanThreadStateSet : public StackObj { size_t* _surviving_young_words_total; size_t* _cards_scanned; size_t _total_cards_scanned; + size_t _young_cset_length; uint _n_workers; bool _flushed; @@ -210,10 +211,11 @@ class G1ParScanThreadStateSet : public StackObj { _surviving_young_words_total(NEW_C_HEAP_ARRAY(size_t, young_cset_length, mtGC)), _cards_scanned(NEW_C_HEAP_ARRAY(size_t, n_workers, mtGC)), _total_cards_scanned(0), + _young_cset_length(young_cset_length), _n_workers(n_workers), _flushed(false) { for (uint i = 0; i < n_workers; ++i) { - _states[i] = new_par_scan_state(i, young_cset_length); + _states[i] = NULL; } memset(_surviving_young_words_total, 0, young_cset_length * sizeof(size_t)); memset(_cards_scanned, 0, n_workers * sizeof(size_t)); From 8cc9a5146bd92919ef836da698a5c75aa0c99efe Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Fri, 26 Feb 2016 13:21:28 +0100 Subject: [PATCH 063/129] 8150727: [JVMCI] add LoadLoad to the implicit memory barriers on AMD64 Reviewed-by: rschatz, twisti --- .../classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java index 37393ff08bc..972aea94231 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java @@ -22,6 +22,7 @@ */ package jdk.vm.ci.amd64; +import static jdk.vm.ci.code.MemoryBarriers.LOAD_LOAD; import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE; import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE; import static jdk.vm.ci.code.Register.SPECIAL; @@ -220,7 +221,7 @@ public class AMD64 extends Architecture { private final AMD64Kind largestKind; public AMD64(EnumSet features, EnumSet flags) { - super("AMD64", AMD64Kind.QWORD, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_STORE | STORE_STORE, 1, 8); + super("AMD64", AMD64Kind.QWORD, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_LOAD | LOAD_STORE | STORE_STORE, 1, 8); this.features = features; this.flags = flags; assert features.contains(CPUFeature.SSE2) : "minimum config for x64"; From 62c5bdbe9de1c89cc28184badcc50cfe888c1185 Mon Sep 17 00:00:00 2001 From: Andreas Eriksson Date: Fri, 26 Feb 2016 16:28:42 +0100 Subject: [PATCH 064/129] 8144732: VM_HeapDumper hits assert with bad dump_len Reviewed-by: dsamersoff --- hotspot/src/share/vm/runtime/arguments.cpp | 1 + hotspot/src/share/vm/runtime/globals.hpp | 4 - hotspot/src/share/vm/services/heapDumper.cpp | 256 +++++++++++-------- 3 files changed, 149 insertions(+), 112 deletions(-) diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 512c29fc94d..322516b9ef4 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -372,6 +372,7 @@ static SpecialFlag const special_jvm_flags[] = { { "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) }, + { "SegmentedHeapDumpThreshold", 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() }, diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 3c6219a4402..848bb5d2607 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1055,10 +1055,6 @@ public: "directory) of the dump file (defaults to java_pid.hprof " \ "in the working directory)") \ \ - develop(size_t, SegmentedHeapDumpThreshold, 2*G, \ - "Generate a segmented heap dump (JAVA PROFILE 1.0.2 format) " \ - "when the heap usage is larger than this") \ - \ develop(size_t, HeapDumpSegmentSize, 1*G, \ "Approximate segment size when generating a segmented heap dump") \ \ diff --git a/hotspot/src/share/vm/services/heapDumper.cpp b/hotspot/src/share/vm/services/heapDumper.cpp index 2f01fab4cc9..986855894d2 100644 --- a/hotspot/src/share/vm/services/heapDumper.cpp +++ b/hotspot/src/share/vm/services/heapDumper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,8 +53,7 @@ * src/share/demo/jvmti/hprof/hprof_io.c * * - * header "JAVA PROFILE 1.0.1" or "JAVA PROFILE 1.0.2" - * (0-terminated) + * header "JAVA PROFILE 1.0.2" (0-terminated) * * u4 size of identifiers. Identifiers are used to represent * UTF8 strings, objects, stack traces, etc. They usually @@ -385,6 +384,8 @@ class DumpWriter : public StackObj { size_t _size; size_t _pos; + jlong _dump_start; + char* _error; // error message when I/O fails void set_file_descriptor(int fd) { _fd = fd; } @@ -408,6 +409,10 @@ class DumpWriter : public StackObj { bool is_open() const { return file_descriptor() >= 0; } void flush(); + jlong dump_start() const { return _dump_start; } + void set_dump_start(jlong pos); + julong current_record_length(); + // total number of bytes written to the disk julong bytes_written() const { return _bytes_written; } @@ -449,6 +454,7 @@ DumpWriter::DumpWriter(const char* path) { _pos = 0; _error = NULL; _bytes_written = 0L; + _dump_start = (jlong)-1; _fd = os::create_binary_file(path, false); // don't replace existing file // if the open failed we record the error @@ -476,6 +482,22 @@ void DumpWriter::close() { } } +// sets the dump starting position +void DumpWriter::set_dump_start(jlong pos) { + _dump_start = pos; +} + +julong DumpWriter::current_record_length() { + if (is_open()) { + // calculate the size of the dump record + julong dump_end = bytes_written() + bytes_unwritten(); + assert(dump_end == (size_t)current_offset(), "checking"); + julong dump_len = dump_end - dump_start() - 4; + return dump_len; + } + return 0; +} + // write directly to the file void DumpWriter::write_internal(void* s, size_t len) { if (is_open()) { @@ -645,6 +667,18 @@ class DumperSupport : AllStatic { static void dump_prim_array(DumpWriter* writer, typeArrayOop array); // create HPROF_FRAME record for the given method and bci static void dump_stack_frame(DumpWriter* writer, int frame_serial_num, int class_serial_num, Method* m, int bci); + + // check if we need to truncate an array + static int calculate_array_max_length(DumpWriter* writer, arrayOop array, short header_size); + + // writes a HPROF_HEAP_DUMP_SEGMENT record + static void write_dump_header(DumpWriter* writer); + + // fixes up the length of the current dump record + static void write_current_dump_record_length(DumpWriter* writer); + + // fixes up the current dump record and writes HPROF_HEAP_DUMP_END record + static void end_of_dump(DumpWriter* writer); }; // write a header of the given type @@ -1005,50 +1039,102 @@ void DumperSupport::dump_basic_type_array_class(DumpWriter* writer, Klass* k) { } } +// Hprof uses an u4 as record length field, +// which means we need to truncate arrays that are too long. +int DumperSupport::calculate_array_max_length(DumpWriter* writer, arrayOop array, short header_size) { + BasicType type = ArrayKlass::cast(array->klass())->element_type(); + assert(type >= T_BOOLEAN && type <= T_OBJECT, "invalid array element type"); + + int length = array->length(); + + int type_size; + if (type == T_OBJECT) { + type_size = sizeof(address); + } else { + type_size = type2aelembytes(type); + } + + size_t length_in_bytes = (size_t)length * type_size; + + // Create a new record if the current record is non-empty and the array can't fit. + julong current_record_length = writer->current_record_length(); + if (current_record_length > 0 && + (current_record_length + header_size + length_in_bytes) > max_juint) { + write_current_dump_record_length(writer); + write_dump_header(writer); + + // We now have an empty record. + current_record_length = 0; + } + + // Calculate max bytes we can use. + uint max_bytes = max_juint - (header_size + current_record_length); + + // Array too long for the record? + // Calculate max length and return it. + if (length_in_bytes > max_bytes) { + length = max_bytes / type_size; + length_in_bytes = (size_t)length * type_size; + + warning("cannot dump array of type %s[] with length %d; truncating to length %d", + type2name_tab[type], array->length(), length); + } + return length; +} + // creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array void DumperSupport::dump_object_array(DumpWriter* writer, objArrayOop array) { + // sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID) + sizeof(classID) + short header_size = 1 + 2 * 4 + 2 * sizeof(address); + + int length = calculate_array_max_length(writer, array, header_size); writer->write_u1(HPROF_GC_OBJ_ARRAY_DUMP); writer->write_objectID(array); writer->write_u4(STACK_TRACE_ID); - writer->write_u4((u4)array->length()); + writer->write_u4(length); // array class ID writer->write_classID(array->klass()); // [id]* elements - for (int index=0; indexlength(); index++) { + for (int index = 0; index < length; index++) { oop o = array->obj_at(index); writer->write_objectID(o); } } -#define WRITE_ARRAY(Array, Type, Size) \ - for (int i=0; ilength(); i++) { writer->write_##Size((Size)array->Type##_at(i)); } - +#define WRITE_ARRAY(Array, Type, Size, Length) \ + for (int i = 0; i < Length; i++) { writer->write_##Size((Size)Array->Type##_at(i)); } // creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { BasicType type = TypeArrayKlass::cast(array->klass())->element_type(); + // 2 * sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID) + short header_size = 2 * 1 + 2 * 4 + sizeof(address); + + int length = calculate_array_max_length(writer, array, header_size); + int type_size = type2aelembytes(type); + u4 length_in_bytes = (u4)length * type_size; + writer->write_u1(HPROF_GC_PRIM_ARRAY_DUMP); writer->write_objectID(array); writer->write_u4(STACK_TRACE_ID); - writer->write_u4((u4)array->length()); + writer->write_u4(length); writer->write_u1(type2tag(type)); // nothing to copy - if (array->length() == 0) { + if (length == 0) { return; } // If the byte ordering is big endian then we can copy most types directly - u4 length_in_bytes = (u4)array->length() * type2aelembytes(type); switch (type) { case T_INT : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, int, u4); + WRITE_ARRAY(array, int, u4, length); } else { writer->write_raw((void*)(array->int_at_addr(0)), length_in_bytes); } @@ -1060,7 +1146,7 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { } case T_CHAR : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, char, u2); + WRITE_ARRAY(array, char, u2, length); } else { writer->write_raw((void*)(array->char_at_addr(0)), length_in_bytes); } @@ -1068,7 +1154,7 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { } case T_SHORT : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, short, u2); + WRITE_ARRAY(array, short, u2, length); } else { writer->write_raw((void*)(array->short_at_addr(0)), length_in_bytes); } @@ -1076,7 +1162,7 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { } case T_BOOLEAN : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, bool, u1); + WRITE_ARRAY(array, bool, u1, length); } else { writer->write_raw((void*)(array->bool_at_addr(0)), length_in_bytes); } @@ -1084,7 +1170,7 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { } case T_LONG : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, long, u8); + WRITE_ARRAY(array, long, u8, length); } else { writer->write_raw((void*)(array->long_at_addr(0)), length_in_bytes); } @@ -1096,14 +1182,14 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { // use IEEE 754. case T_FLOAT : { - for (int i=0; ilength(); i++) { - dump_float( writer, array->float_at(i) ); + for (int i = 0; i < length; i++) { + dump_float(writer, array->float_at(i)); } break; } case T_DOUBLE : { - for (int i=0; ilength(); i++) { - dump_double( writer, array->double_at(i) ); + for (int i = 0; i < length; i++) { + dump_double(writer, array->double_at(i)); } break; } @@ -1320,8 +1406,6 @@ class VM_HeapDumper : public VM_GC_Operation { JavaThread* _oome_thread; Method* _oome_constructor; bool _gc_before_heap_dump; - bool _is_segmented_dump; - jlong _dump_start; GrowableArray* _klass_map; ThreadStackTrace** _stack_traces; int _num_threads; @@ -1340,11 +1424,6 @@ class VM_HeapDumper : public VM_GC_Operation { void clear_global_dumper() { _global_dumper = NULL; } void clear_global_writer() { _global_writer = NULL; } - bool is_segmented_dump() const { return _is_segmented_dump; } - void set_segmented_dump() { _is_segmented_dump = true; } - jlong dump_start() const { return _dump_start; } - void set_dump_start(jlong pos); - bool skip_operation() const; // writes a HPROF_LOAD_CLASS record @@ -1369,16 +1448,6 @@ class VM_HeapDumper : public VM_GC_Operation { // HPROF_TRACE and HPROF_FRAME records void dump_stack_traces(); - // writes a HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT record - void write_dump_header(); - - // fixes up the length of the current dump record - void write_current_dump_record_length(); - - // fixes up the current dump record )and writes HPROF_HEAP_DUMP_END - // record in the case of a segmented heap dump) - void end_of_dump(); - public: VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump, bool oome) : VM_GC_Operation(0 /* total collections, dummy, ignored */, @@ -1387,8 +1456,6 @@ class VM_HeapDumper : public VM_GC_Operation { gc_before_heap_dump) { _local_writer = writer; _gc_before_heap_dump = gc_before_heap_dump; - _is_segmented_dump = false; - _dump_start = (jlong)-1; _klass_map = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(INITIAL_CLASS_COUNT, true); _stack_traces = NULL; _num_threads = 0; @@ -1428,35 +1495,23 @@ bool VM_HeapDumper::skip_operation() const { return false; } -// sets the dump starting position -void VM_HeapDumper::set_dump_start(jlong pos) { - _dump_start = pos; -} - - // writes a HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT record -void VM_HeapDumper::write_dump_header() { - if (writer()->is_open()) { - if (is_segmented_dump()) { - writer()->write_u1(HPROF_HEAP_DUMP_SEGMENT); - } else { - writer()->write_u1(HPROF_HEAP_DUMP); - } - writer()->write_u4(0); // current ticks + // writes a HPROF_HEAP_DUMP_SEGMENT record +void DumperSupport::write_dump_header(DumpWriter* writer) { + if (writer->is_open()) { + writer->write_u1(HPROF_HEAP_DUMP_SEGMENT); + writer->write_u4(0); // current ticks // record the starting position for the dump (its length will be fixed up later) - set_dump_start(writer()->current_offset()); - writer()->write_u4(0); + writer->set_dump_start(writer->current_offset()); + writer->write_u4(0); } } // fixes up the length of the current dump record -void VM_HeapDumper::write_current_dump_record_length() { - if (writer()->is_open()) { - assert(dump_start() >= 0, "no dump start recorded"); - - // calculate the size of the dump record - julong dump_end = writer()->current_offset(); - julong dump_len = (dump_end - dump_start() - 4); +void DumperSupport::write_current_dump_record_length(DumpWriter* writer) { + if (writer->is_open()) { + julong dump_end = writer->bytes_written() + writer->bytes_unwritten(); + julong dump_len = writer->current_record_length(); // record length must fit in a u4 if (dump_len > max_juint) { @@ -1464,17 +1519,18 @@ void VM_HeapDumper::write_current_dump_record_length() { } // seek to the dump start and fix-up the length - writer()->seek_to_offset(dump_start()); - writer()->write_u4((u4)dump_len); + assert(writer->dump_start() >= 0, "no dump start recorded"); + writer->seek_to_offset(writer->dump_start()); + writer->write_u4((u4)dump_len); // adjust the total size written to keep the bytes written correct. - writer()->adjust_bytes_written(-((jlong) sizeof(u4))); + writer->adjust_bytes_written(-((jlong) sizeof(u4))); // seek to dump end so we can continue - writer()->seek_to_offset(dump_end); + writer->seek_to_offset(dump_end); // no current dump record - set_dump_start((jlong)-1); + writer->set_dump_start((jlong)-1); } } @@ -1482,33 +1538,23 @@ void VM_HeapDumper::write_current_dump_record_length() { // new segment. void VM_HeapDumper::check_segment_length() { if (writer()->is_open()) { - if (is_segmented_dump()) { - // don't use current_offset that would be too expensive on a per record basis - julong dump_end = writer()->bytes_written() + writer()->bytes_unwritten(); - assert(dump_end == (julong)writer()->current_offset(), "checking"); - julong dump_len = (dump_end - dump_start() - 4); - assert(dump_len <= max_juint, "bad dump length"); + julong dump_len = writer()->current_record_length(); - if (dump_len > HeapDumpSegmentSize) { - write_current_dump_record_length(); - write_dump_header(); - } + if (dump_len > 2UL*G) { + DumperSupport::write_current_dump_record_length(writer()); + DumperSupport::write_dump_header(writer()); } } } -// fixes up the current dump record )and writes HPROF_HEAP_DUMP_END -// record in the case of a segmented heap dump) -void VM_HeapDumper::end_of_dump() { - if (writer()->is_open()) { - write_current_dump_record_length(); +// fixes up the current dump record and writes HPROF_HEAP_DUMP_END record +void DumperSupport::end_of_dump(DumpWriter* writer) { + if (writer->is_open()) { + write_current_dump_record_length(writer); - // for segmented dump we write the end record - if (is_segmented_dump()) { - writer()->write_u1(HPROF_HEAP_DUMP_END); - writer()->write_u4(0); - writer()->write_u4(0); - } + writer->write_u1(HPROF_HEAP_DUMP_END); + writer->write_u4(0); + writer->write_u4(0); } } @@ -1686,16 +1732,17 @@ void VM_HeapDumper::do_threads() { // [HPROF_LOAD_CLASS]* // [[HPROF_FRAME]*|HPROF_TRACE]* // [HPROF_GC_CLASS_DUMP]* -// HPROF_HEAP_DUMP +// [HPROF_HEAP_DUMP_SEGMENT]* +// HPROF_HEAP_DUMP_END // // The HPROF_TRACE records represent the stack traces where the heap dump // is generated and a "dummy trace" record which does not include // any frames. The dummy trace record is used to be referenced as the // unknown object alloc site. // -// The HPROF_HEAP_DUMP record has a length following by sub-records. To allow -// the heap dump be generated in a single pass we remember the position of -// the dump length and fix it up after all sub-records have been written. +// Each HPROF_HEAP_DUMP_SEGMENT record has a length followed by sub-records. +// To allow the heap dump be generated in a single pass we remember the position +// of the dump length and fix it up after all sub-records have been written. // To generate the sub-records we iterate over the heap, writing // HPROF_GC_INSTANCE_DUMP, HPROF_GC_OBJ_ARRAY_DUMP, and HPROF_GC_PRIM_ARRAY_DUMP // records as we go. Once that is done we write records for some of the GC @@ -1722,15 +1769,9 @@ void VM_HeapDumper::doit() { set_global_dumper(); set_global_writer(); - // Write the file header - use 1.0.2 for large heaps, otherwise 1.0.1 + // Write the file header - we always use 1.0.2 size_t used = ch->used(); - const char* header; - if (used > SegmentedHeapDumpThreshold) { - set_segmented_dump(); - header = "JAVA PROFILE 1.0.2"; - } else { - header = "JAVA PROFILE 1.0.1"; - } + const char* header = "JAVA PROFILE 1.0.2"; // header is few bytes long - no chance to overflow int writer()->write_raw((void*)header, (int)strlen(header)); @@ -1750,8 +1791,8 @@ void VM_HeapDumper::doit() { // this must be called after _klass_map is built when iterating the classes above. dump_stack_traces(); - // write HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT - write_dump_header(); + // write HPROF_HEAP_DUMP_SEGMENT + DumperSupport::write_dump_header(writer()); // Writes HPROF_GC_CLASS_DUMP records ClassLoaderDataGraph::classes_do(&do_class_dump); @@ -1759,9 +1800,9 @@ void VM_HeapDumper::doit() { check_segment_length(); // writes HPROF_GC_INSTANCE_DUMP records. - // After each sub-record is written check_segment_length will be invoked. When - // generated a segmented heap dump this allows us to check if the current - // segment exceeds a threshold and if so, then a new segment is started. + // After each sub-record is written check_segment_length will be invoked + // to check if the current segment exceeds a threshold. If so, a new + // segment is started. // The HPROF_GC_CLASS_DUMP and HPROF_GC_INSTANCE_DUMP are the vast bulk // of the heap dump. HeapObjectDumper obj_dumper(this, writer()); @@ -1785,9 +1826,8 @@ void VM_HeapDumper::doit() { StickyClassDumper class_dumper(writer()); SystemDictionary::always_strong_classes_do(&class_dumper); - // fixes up the length of the dump record. In the case of a segmented - // heap then the HPROF_HEAP_DUMP_END record is also written. - end_of_dump(); + // fixes up the length of the dump record and writes the HPROF_HEAP_DUMP_END record. + DumperSupport::end_of_dump(writer()); // Now we clear the global variables, so that a future dumper might run. clear_global_dumper(); From 6d7d3228e7b3fd1e3b4c2b51b8a7de6f04acdb0b Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Fri, 26 Feb 2016 09:13:22 -0800 Subject: [PATCH 065/129] 8147978: Remove Method::_method_data for C1 Method::_method_data field removed when not using C2 or JVMCI Reviewed-by: dholmes, kvn --- hotspot/src/share/vm/c1/c1_Runtime1.cpp | 26 ++++++++++++---------- hotspot/src/share/vm/oops/method.cpp | 5 +++-- hotspot/src/share/vm/oops/method.hpp | 18 +++++++++++++++ hotspot/src/share/vm/runtime/arguments.cpp | 6 +++++ hotspot/src/share/vm/runtime/vmStructs.cpp | 2 +- hotspot/src/share/vm/utilities/macros.hpp | 11 ++++++++- 6 files changed, 52 insertions(+), 16 deletions(-) diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index 92c721575d0..01e639258c8 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -1502,21 +1502,23 @@ JRT_ENTRY(void, Runtime1::predicate_failed_trap(JavaThread* thread)) nm->make_not_entrant(); methodHandle m(nm->method()); - MethodData* mdo = m->method_data(); + if (ProfileInterpreter) { + MethodData* mdo = m->method_data(); - if (mdo == NULL && !HAS_PENDING_EXCEPTION) { - // Build an MDO. Ignore errors like OutOfMemory; - // that simply means we won't have an MDO to update. - Method::build_interpreter_method_data(m, THREAD); - if (HAS_PENDING_EXCEPTION) { - assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here"); - CLEAR_PENDING_EXCEPTION; + if (mdo == NULL && !HAS_PENDING_EXCEPTION) { + // Build an MDO. Ignore errors like OutOfMemory; + // that simply means we won't have an MDO to update. + Method::build_interpreter_method_data(m, THREAD); + if (HAS_PENDING_EXCEPTION) { + assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here"); + CLEAR_PENDING_EXCEPTION; + } + mdo = m->method_data(); } - mdo = m->method_data(); - } - if (mdo != NULL) { - mdo->inc_trap_count(Deoptimization::Reason_none); + if (mdo != NULL) { + mdo->inc_trap_count(Deoptimization::Reason_none); + } } if (TracePredicateFailedTraps) { diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 7620ea9f985..1f3eb751413 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -383,14 +383,15 @@ void Method::build_interpreter_method_data(const methodHandle& method, TRAPS) { MutexLocker ml(MethodData_lock, THREAD); if (method->method_data() == NULL) { ClassLoaderData* loader_data = method->method_holder()->class_loader_data(); +#if defined(COMPILER2) || INCLUDE_JVMCI MethodData* method_data = MethodData::allocate(loader_data, method, THREAD); if (HAS_PENDING_EXCEPTION) { CompileBroker::log_metaspace_failure(); ClassLoaderDataGraph::set_metaspace_oom(true); return; // return the exception (which is cleared) } - method->set_method_data(method_data); +#endif if (PrintMethodData && (Verbose || WizardMode)) { ResourceMark rm(THREAD); tty->print("build_interpreter_method_data for "); @@ -920,7 +921,7 @@ void Method::unlink_method() { // shared class that failed to load, this->link_method() may // have already been called (before an exception happened), so // this->_method_data may not be NULL. - assert(!DumpSharedSpaces || _method_data == NULL, "unexpected method data?"); + assert(!DumpSharedSpaces || method_data() == NULL, "unexpected method data?"); set_method_data(NULL); clear_method_counters(); diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 8fc7b133a16..fdf7d1f9fb0 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -64,7 +64,9 @@ class Method : public Metadata { friend class JVMCIVMStructs; private: ConstMethod* _constMethod; // Method read-only data. +#if defined(COMPILER2) || INCLUDE_JVMCI MethodData* _method_data; +#endif MethodCounters* _method_counters; AccessFlags _access_flags; // Access flags int _vtable_index; // vtable index of this method (see VtableIndexFlag) @@ -319,6 +321,7 @@ class Method : public Metadata { // InterpreterRuntime::exception_handler_for_exception. static int fast_exception_handler_bci_for(methodHandle mh, KlassHandle ex_klass, int throw_bci, TRAPS); +#if defined(COMPILER2) || INCLUDE_JVMCI // method data access MethodData* method_data() const { return _method_data; @@ -330,6 +333,10 @@ class Method : public Metadata { // the initialization of data otherwise. OrderAccess::release_store_ptr((volatile void *)&_method_data, data); } +#else + MethodData* method_data() const { return NULL; } + void set_method_data(MethodData* data) { } +#endif MethodCounters* method_counters() const { return _method_counters; @@ -639,9 +646,16 @@ class Method : public Metadata { #endif /* CC_INTERP */ static ByteSize from_compiled_offset() { return byte_offset_of(Method, _from_compiled_entry); } static ByteSize code_offset() { return byte_offset_of(Method, _code); } +#if defined(COMPILER2) || INCLUDE_JVMCI static ByteSize method_data_offset() { return byte_offset_of(Method, _method_data); } +#else + static ByteSize method_data_offset() { + ShouldNotReachHere(); + return in_ByteSize(0); + } +#endif static ByteSize method_counters_offset() { return byte_offset_of(Method, _method_counters); } @@ -654,7 +668,11 @@ class Method : public Metadata { static ByteSize signature_handler_offset() { return in_ByteSize(sizeof(Method) + wordSize); } // for code generation +#if defined(COMPILER2) || INCLUDE_JVMCI static int method_data_offset_in_bytes() { return offset_of(Method, _method_data); } +#else + static int method_data_offset_in_bytes() { ShouldNotReachHere(); return 0; } +#endif static int intrinsic_id_offset_in_bytes() { return offset_of(Method, _intrinsic_id); } static int intrinsic_id_size_in_bytes() { return sizeof(u2); } diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 006e3c94739..ca25748543e 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -3464,6 +3464,12 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req } #endif +#if !defined(COMPILER2) && !INCLUDE_JVMCI + UNSUPPORTED_OPTION(ProfileInterpreter, "ProfileInterpreter"); + NOT_PRODUCT(UNSUPPORTED_OPTION(TraceProfileInterpreter, "TraceProfileInterpreter")); + UNSUPPORTED_OPTION(PrintMethodData, "PrintMethodData"); +#endif + #ifndef TIERED // Tiered compilation is undefined. UNSUPPORTED_OPTION(TieredCompilation, "TieredCompilation"); diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 84d2c6ebd3b..6630da1633c 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -390,7 +390,7 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(MethodCounters, _invocation_counter, InvocationCounter) \ nonstatic_field(MethodCounters, _backedge_counter, InvocationCounter) \ nonstatic_field(Method, _constMethod, ConstMethod*) \ - nonstatic_field(Method, _method_data, MethodData*) \ + COMPILER2_OR_JVMCI_PRESENT(nonstatic_field(Method, _method_data, MethodData*)) \ nonstatic_field(Method, _method_counters, MethodCounters*) \ nonstatic_field(Method, _access_flags, AccessFlags) \ nonstatic_field(Method, _vtable_index, int) \ diff --git a/hotspot/src/share/vm/utilities/macros.hpp b/hotspot/src/share/vm/utilities/macros.hpp index ccdb90813b7..11b4fe4f3aa 100644 --- a/hotspot/src/share/vm/utilities/macros.hpp +++ b/hotspot/src/share/vm/utilities/macros.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,6 +206,15 @@ #define NOT_COMPILER2(code) code #endif // COMPILER2 +// COMPILER2 or JVMCI +#if defined(COMPILER2) || INCLUDE_JVMCI +#define COMPILER2_OR_JVMCI_PRESENT(code) code +#define NOT_COMPILER2_OR_JVMCI(code) +#else +#define COMPILER2_OR_JVMCI_PRESENT(code) +#define NOT_COMPILER2_OR_JVMCI(code) code +#endif + #ifdef TIERED #define TIERED_ONLY(code) code #define NOT_TIERED(code) From 41c0116f6ef2f0e1e12de4909b5e56a4662d51fd Mon Sep 17 00:00:00 2001 From: Joseph Provino Date: Fri, 26 Feb 2016 14:02:39 -0500 Subject: [PATCH 066/129] 8139651: ConcurrentG1Refine uses ints for many of its members that should be unsigned types Ints need to be changed to size_t Reviewed-by: kbarrett, tbenson --- .../src/share/vm/gc/g1/concurrentG1Refine.cpp | 8 +++---- .../src/share/vm/gc/g1/concurrentG1Refine.hpp | 24 +++++++++---------- .../vm/gc/g1/concurrentG1RefineThread.cpp | 12 ++++++---- .../vm/gc/g1/concurrentG1RefineThread.hpp | 8 +++---- hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp | 14 ++++++----- hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp | 4 ++-- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 4 ++-- .../src/share/vm/gc/g1/g1CollectorPolicy.cpp | 16 ++++++------- .../src/share/vm/gc/g1/g1ConcurrentMark.cpp | 4 ++-- hotspot/src/share/vm/gc/g1/g1RemSet.cpp | 1 - hotspot/src/share/vm/gc/g1/g1_globals.hpp | 22 ++++++++--------- hotspot/src/share/vm/gc/g1/ptrQueue.cpp | 12 ++++++---- hotspot/src/share/vm/gc/g1/ptrQueue.hpp | 12 +++++----- 13 files changed, 73 insertions(+), 68 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp index 0e2f4dd4bb3..5edec2775ed 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,19 +36,19 @@ ConcurrentG1Refine::ConcurrentG1Refine(G1CollectedHeap* g1h) : { // Ergonomically select initial concurrent refinement parameters if (FLAG_IS_DEFAULT(G1ConcRefinementGreenZone)) { - FLAG_SET_DEFAULT(G1ConcRefinementGreenZone, (intx)ParallelGCThreads); + FLAG_SET_DEFAULT(G1ConcRefinementGreenZone, ParallelGCThreads); } set_green_zone(G1ConcRefinementGreenZone); if (FLAG_IS_DEFAULT(G1ConcRefinementYellowZone)) { FLAG_SET_DEFAULT(G1ConcRefinementYellowZone, green_zone() * 3); } - set_yellow_zone(MAX2(G1ConcRefinementYellowZone, green_zone())); + set_yellow_zone(MAX2(G1ConcRefinementYellowZone, green_zone())); if (FLAG_IS_DEFAULT(G1ConcRefinementRedZone)) { FLAG_SET_DEFAULT(G1ConcRefinementRedZone, yellow_zone() * 2); } - set_red_zone(MAX2(G1ConcRefinementRedZone, yellow_zone())); + set_red_zone(MAX2(G1ConcRefinementRedZone, yellow_zone())); } ConcurrentG1Refine* ConcurrentG1Refine::create(G1CollectedHeap* g1h, CardTableEntryClosure* refine_closure, jint* ecode) { diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp index 0e5525f73c2..2333fea311f 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,11 +61,11 @@ class ConcurrentG1Refine: public CHeapObj { * 2) green = 0. Means no caching. Can be a good way to minimize the * amount of time spent updating rsets during a collection. */ - int _green_zone; - int _yellow_zone; - int _red_zone; + size_t _green_zone; + size_t _yellow_zone; + size_t _red_zone; - int _thread_threshold_step; + size_t _thread_threshold_step; // We delay the refinement of 'hot' cards using the hot card cache. G1HotCardCache _hot_card_cache; @@ -100,17 +100,17 @@ class ConcurrentG1Refine: public CHeapObj { void print_worker_threads_on(outputStream* st) const; - void set_green_zone(int x) { _green_zone = x; } - void set_yellow_zone(int x) { _yellow_zone = x; } - void set_red_zone(int x) { _red_zone = x; } + void set_green_zone(size_t x) { _green_zone = x; } + void set_yellow_zone(size_t x) { _yellow_zone = x; } + void set_red_zone(size_t x) { _red_zone = x; } - int green_zone() const { return _green_zone; } - int yellow_zone() const { return _yellow_zone; } - int red_zone() const { return _red_zone; } + size_t green_zone() const { return _green_zone; } + size_t yellow_zone() const { return _yellow_zone; } + size_t red_zone() const { return _red_zone; } uint worker_thread_num() const { return _n_worker_threads; } - int thread_threshold_step() const { return _thread_threshold_step; } + size_t thread_threshold_step() const { return _thread_threshold_step; } G1HotCardCache* hot_card_cache() { return &_hot_card_cache; } diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp index cefcab3065b..1e8081e53e0 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp @@ -67,10 +67,12 @@ ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *nex void ConcurrentG1RefineThread::initialize() { // Current thread activation threshold - _threshold = MIN2(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(), + _threshold = MIN2(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(), cg1r()->yellow_zone()); // A thread deactivates once the number of buffer reached a deactivation threshold - _deactivation_threshold = MAX2(_threshold - cg1r()->thread_threshold_step(), cg1r()->green_zone()); + _deactivation_threshold = + MAX2(_threshold - MIN2(_threshold, cg1r()->thread_threshold_step()), + cg1r()->green_zone()); } void ConcurrentG1RefineThread::wait_for_completed_buffers() { @@ -127,14 +129,14 @@ void ConcurrentG1RefineThread::run_service() { } DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); - log_debug(gc, refine)("Activated %d, on threshold: %d, current: %d", + log_debug(gc, refine)("Activated %d, on threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT, _worker_id, _threshold, dcqs.completed_buffers_num()); { SuspendibleThreadSetJoiner sts_join; do { - int curr_buffer_num = (int)dcqs.completed_buffers_num(); + size_t curr_buffer_num = dcqs.completed_buffers_num(); // If the number of the buffers falls down into the yellow zone, // that means that the transition period after the evacuation pause has ended. if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) { @@ -151,7 +153,7 @@ void ConcurrentG1RefineThread::run_service() { false /* during_pause */)); deactivate(); - log_debug(gc, refine)("Deactivated %d, off threshold: %d, current: %d", + log_debug(gc, refine)("Deactivated %d, off threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT, _worker_id, _deactivation_threshold, dcqs.completed_buffers_num()); } diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp index 5b6d3ed79d5..40071766d6f 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,11 +53,11 @@ class ConcurrentG1RefineThread: public ConcurrentGCThread { // The closure applied to completed log buffers. CardTableEntryClosure* _refine_closure; - int _thread_threshold_step; + size_t _thread_threshold_step; // This thread activation threshold - int _threshold; + size_t _threshold; // This thread deactivation threshold - int _deactivation_threshold; + size_t _deactivation_threshold; void wait_for_completed_buffers(); diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp index 4c33fb9b211..d79ac8066b9 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp @@ -207,22 +207,24 @@ bool DirtyCardQueueSet::mut_process_buffer(void** buf) { } -BufferNode* DirtyCardQueueSet::get_completed_buffer(int stop_at) { +BufferNode* DirtyCardQueueSet::get_completed_buffer(size_t stop_at) { BufferNode* nd = NULL; MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); - if ((int)_n_completed_buffers <= stop_at) { + if (_n_completed_buffers <= stop_at) { _process_completed = false; return NULL; } if (_completed_buffers_head != NULL) { nd = _completed_buffers_head; + assert(_n_completed_buffers > 0, "Invariant"); _completed_buffers_head = nd->next(); - if (_completed_buffers_head == NULL) - _completed_buffers_tail = NULL; _n_completed_buffers--; - assert(_n_completed_buffers >= 0, "Invariant"); + if (_completed_buffers_head == NULL) { + assert(_n_completed_buffers == 0, "Invariant"); + _completed_buffers_tail = NULL; + } } DEBUG_ONLY(assert_completed_buffer_list_len_correct_locked()); return nd; @@ -230,7 +232,7 @@ BufferNode* DirtyCardQueueSet::get_completed_buffer(int stop_at) { bool DirtyCardQueueSet::apply_closure_to_completed_buffer(CardTableEntryClosure* cl, uint worker_i, - int stop_at, + size_t stop_at, bool during_pause) { assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause"); BufferNode* nd = get_completed_buffer(stop_at); diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp index 17c92bb8ecf..96865a5784b 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp @@ -134,10 +134,10 @@ public: // is returned to the completed buffer set, and this call returns false. bool apply_closure_to_completed_buffer(CardTableEntryClosure* cl, uint worker_i, - int stop_at, + size_t stop_at, bool during_pause); - BufferNode* get_completed_buffer(int stop_at); + BufferNode* get_completed_buffer(size_t stop_at); // Applies the current closure to all completed buffers, // non-consumptively. diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index be30e88c541..01907547340 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -1984,8 +1984,8 @@ jint G1CollectedHeap::initialize() { JavaThread::dirty_card_queue_set().initialize(_refine_cte_cl, DirtyCardQ_CBL_mon, DirtyCardQ_FL_lock, - concurrent_g1_refine()->yellow_zone(), - concurrent_g1_refine()->red_zone(), + (int)concurrent_g1_refine()->yellow_zone(), + (int)concurrent_g1_refine()->red_zone(), Shared_DirtyCardQ_lock, NULL, // fl_owner true); // init_free_ids diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index f14e360ce44..bd98877eded 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -1301,12 +1301,12 @@ void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time, const int k_gy = 3, k_gr = 6; const double inc_k = 1.1, dec_k = 0.9; - int g = cg1r->green_zone(); + size_t g = cg1r->green_zone(); if (update_rs_time > goal_ms) { - g = (int)(g * dec_k); // Can become 0, that's OK. That would mean a mutator-only processing. + g = (size_t)(g * dec_k); // Can become 0, that's OK. That would mean a mutator-only processing. } else { if (update_rs_time < goal_ms && update_rs_processed_buffers > g) { - g = (int)MAX2(g * inc_k, g + 1.0); + g = (size_t)MAX2(g * inc_k, g + 1.0); } } // Change the refinement threads params @@ -1315,15 +1315,15 @@ void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time, cg1r->set_red_zone(g * k_gr); cg1r->reinitialize_threads(); - int processing_threshold_delta = MAX2((int)(cg1r->green_zone() * _predictor.sigma()), 1); - int processing_threshold = MIN2(cg1r->green_zone() + processing_threshold_delta, + size_t processing_threshold_delta = MAX2(cg1r->green_zone() * _predictor.sigma(), 1); + size_t processing_threshold = MIN2(cg1r->green_zone() + processing_threshold_delta, cg1r->yellow_zone()); // Change the barrier params - dcqs.set_process_completed_threshold(processing_threshold); - dcqs.set_max_completed_queue(cg1r->red_zone()); + dcqs.set_process_completed_threshold((int)processing_threshold); + dcqs.set_max_completed_queue((int)cg1r->red_zone()); } - int curr_queue_size = dcqs.completed_buffers_num(); + size_t curr_queue_size = dcqs.completed_buffers_num(); if (curr_queue_size >= cg1r->yellow_zone()) { dcqs.set_completed_queue_padding(curr_queue_size); } else { diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp index edfb510d6fe..6605b0cf621 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2271,7 +2271,7 @@ void G1ConcurrentMark::checkpointRootsFinalWork() { SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); guarantee(has_overflown() || satb_mq_set.completed_buffers_num() == 0, - "Invariant: has_overflown = %s, num buffers = %d", + "Invariant: has_overflown = %s, num buffers = " SIZE_FORMAT, BOOL_TO_STR(has_overflown()), satb_mq_set.completed_buffers_num()); diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp index 40e3959c886..3d2917a2184 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp @@ -291,7 +291,6 @@ void G1RemSet::cleanup_after_oops_into_collection_set_do() { _g1->cleanUpCardTable(); DirtyCardQueueSet& into_cset_dcqs = _into_cset_dirty_card_queue_set; - int into_cset_n_buffers = into_cset_dcqs.completed_buffers_num(); if (_g1->evacuation_failed()) { double restore_remembered_set_start = os::elapsedTime(); diff --git a/hotspot/src/share/vm/gc/g1/g1_globals.hpp b/hotspot/src/share/vm/gc/g1/g1_globals.hpp index 086e27bd589..370ba86eb09 100644 --- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,35 +107,35 @@ "Size of an update buffer") \ range(1, NOT_LP64(32*M) LP64_ONLY(1*G)) \ \ - product(intx, G1ConcRefinementYellowZone, 0, \ + product(size_t, G1ConcRefinementYellowZone, 0, \ "Number of enqueued update buffers that will " \ "trigger concurrent processing. Will be selected ergonomically " \ "by default.") \ - range(0, max_intx) \ + range(0, SIZE_MAX) \ \ - product(intx, G1ConcRefinementRedZone, 0, \ + product(size_t, G1ConcRefinementRedZone, 0, \ "Maximum number of enqueued update buffers before mutator " \ "threads start processing new ones instead of enqueueing them. " \ "Will be selected ergonomically by default. Zero will disable " \ "concurrent processing.") \ - range(0, max_intx) \ + range(0, SIZE_MAX) \ \ - product(intx, G1ConcRefinementGreenZone, 0, \ + product(size_t, G1ConcRefinementGreenZone, 0, \ "The number of update buffers that are left in the queue by the " \ "concurrent processing threads. Will be selected ergonomically " \ "by default.") \ - range(0, max_intx) \ + range(0, SIZE_MAX) \ \ - product(intx, G1ConcRefinementServiceIntervalMillis, 300, \ + product(uintx, G1ConcRefinementServiceIntervalMillis, 300, \ "The last concurrent refinement thread wakes up every " \ "specified number of milliseconds to do miscellaneous work.") \ - range(0, max_jint) \ + range(0, max_uintx) \ \ - product(intx, G1ConcRefinementThresholdStep, 0, \ + product(size_t, G1ConcRefinementThresholdStep, 0, \ "Each time the rset update queue increases by this amount " \ "activate the next refinement thread if available. " \ "Will be selected ergonomically by default.") \ - range(0, max_jint) \ + range(0, SIZE_MAX) \ \ product(intx, G1RSetUpdatingPauseTimePercent, 10, \ "A target percentage of time that is allowed to be spend on " \ diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp index 55b41a0b605..d6cf5c50e6a 100644 --- a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp @@ -271,16 +271,17 @@ void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) { _n_completed_buffers++; if (!_process_completed && _process_completed_threshold >= 0 && - _n_completed_buffers >= _process_completed_threshold) { + _n_completed_buffers >= (size_t)_process_completed_threshold) { _process_completed = true; - if (_notify_when_complete) + if (_notify_when_complete) { _cbl_mon->notify(); + } } DEBUG_ONLY(assert_completed_buffer_list_len_correct_locked()); } -int PtrQueueSet::completed_buffers_list_length() { - int n = 0; +size_t PtrQueueSet::completed_buffers_list_length() { + size_t n = 0; BufferNode* cbn = _completed_buffers_head; while (cbn != NULL) { n++; @@ -334,7 +335,8 @@ void PtrQueueSet::merge_bufferlists(PtrQueueSet *src) { void PtrQueueSet::notify_if_necessary() { MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); - if (_n_completed_buffers >= _process_completed_threshold || _max_completed_queue == 0) { + assert(_process_completed_threshold >= 0, "_process_completed is negative"); + if (_n_completed_buffers >= (size_t)_process_completed_threshold || _max_completed_queue == 0) { _process_completed = true; if (_notify_when_complete) _cbl_mon->notify(); diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp index a2207641238..4d5c5e6c28a 100644 --- a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp @@ -209,7 +209,7 @@ protected: Monitor* _cbl_mon; // Protects the fields below. BufferNode* _completed_buffers_head; BufferNode* _completed_buffers_tail; - int _n_completed_buffers; + size_t _n_completed_buffers; int _process_completed_threshold; volatile bool _process_completed; @@ -233,9 +233,9 @@ protected: // Maximum number of elements allowed on completed queue: after that, // enqueuer does the work itself. Zero indicates no maximum. int _max_completed_queue; - int _completed_queue_padding; + size_t _completed_queue_padding; - int completed_buffers_list_length(); + size_t completed_buffers_list_length(); void assert_completed_buffer_list_len_correct_locked(); void assert_completed_buffer_list_len_correct(); @@ -299,15 +299,15 @@ public: // list size may be reduced, if that is deemed desirable. void reduce_free_list(); - int completed_buffers_num() { return _n_completed_buffers; } + size_t completed_buffers_num() { return _n_completed_buffers; } void merge_bufferlists(PtrQueueSet* src); void set_max_completed_queue(int m) { _max_completed_queue = m; } int max_completed_queue() { return _max_completed_queue; } - void set_completed_queue_padding(int padding) { _completed_queue_padding = padding; } - int completed_queue_padding() { return _completed_queue_padding; } + void set_completed_queue_padding(size_t padding) { _completed_queue_padding = padding; } + size_t completed_queue_padding() { return _completed_queue_padding; } // Notify the consumer if the number of buffers crossed the threshold void notify_if_necessary(); From 234373ff31ee35fb5cad93317baa30b26fa6edbe Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Sun, 28 Feb 2016 12:22:05 -0500 Subject: [PATCH 067/129] 8150421: Delete experimental G1UseConcMarkReferenceProcessing Removed the option and supporting code. Reviewed-by: jmasa, tamao --- hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp | 7 ++----- hotspot/src/share/vm/gc/g1/g1_globals.hpp | 4 ---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp index 6605b0cf621..5ece63cea5d 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp @@ -2702,11 +2702,8 @@ public: }; static ReferenceProcessor* get_cm_oop_closure_ref_processor(G1CollectedHeap* g1h) { - ReferenceProcessor* result = NULL; - if (G1UseConcMarkReferenceProcessing) { - result = g1h->ref_processor_cm(); - assert(result != NULL, "should not be NULL"); - } + ReferenceProcessor* result = g1h->ref_processor_cm(); + assert(result != NULL, "CM reference processor should not be NULL"); return result; } diff --git a/hotspot/src/share/vm/gc/g1/g1_globals.hpp b/hotspot/src/share/vm/gc/g1/g1_globals.hpp index 370ba86eb09..fa210295098 100644 --- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp @@ -71,10 +71,6 @@ "draining concurrent marking work queues.") \ range(1, max_intx) \ \ - experimental(bool, G1UseConcMarkReferenceProcessing, true, \ - "If true, enable reference discovery during concurrent " \ - "marking and reference processing at the end of remark.") \ - \ experimental(double, G1LastPLABAverageOccupancy, 50.0, \ "The expected average occupancy of the last PLAB in " \ "percent.") \ From 31f86a2308104bcbf173193ee988c25ece2ec05e Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 29 Feb 2016 08:50:57 +0100 Subject: [PATCH 068/129] 8150619: Improve thread based logging introduced with 8149036 Reviewed-by: coleenp, dholmes --- hotspot/src/os/aix/vm/os_aix.cpp | 18 ++--- hotspot/src/os/bsd/vm/os_bsd.cpp | 6 +- hotspot/src/os/linux/vm/os_linux.cpp | 2 +- hotspot/src/os/solaris/vm/os_solaris.cpp | 9 ++- hotspot/src/os/windows/vm/os_windows.cpp | 5 +- hotspot/src/share/vm/runtime/thread.cpp | 8 +-- .../runtime/logging/ThreadLoggingTest.java | 69 +++++++++++++++++++ 7 files changed, 92 insertions(+), 25 deletions(-) create mode 100644 hotspot/test/runtime/logging/ThreadLoggingTest.java diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index c38d2a3fbd0..2193a9611a3 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -792,8 +792,8 @@ static void *java_start(Thread *thread) { const pthread_t pthread_id = ::pthread_self(); const tid_t kernel_thread_id = ::thread_self(); - log_info(os, thread)("Thread is alive (pthread id " UINTX_FORMAT ", tid " UINTX_FORMAT ")", - (uintx) pthread_id, (uintx) kernel_thread_id); + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", kernel thread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) kernel_thread_id); // Normally, pthread stacks on AIX live in the data segment (are allocated with malloc() // by the pthread library). In rare cases, this may not be the case, e.g. when third-party @@ -801,7 +801,7 @@ static void *java_start(Thread *thread) { // guard pages on those stacks, because the stacks may reside in memory which is not // protectable (shmated). if (thread->stack_base() > ::sbrk(0)) { - log_warning(os, thread)("Thread " UINTX_FORMAT ": stack not in data segment.", (uintx)pthread_id); + log_warning(os, thread)("Thread stack not in data segment."); } // Try to randomize the cache line index of hot stack frames. @@ -835,8 +835,8 @@ static void *java_start(Thread *thread) { // Call one more level start routine. thread->run(); - log_info(os, thread)("Thread finished (pthread id " UINTX_FORMAT ", tid " UINTX_FORMAT ").", - (uintx) pthread_id, (uintx) kernel_thread_id); + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ", kernel thread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) kernel_thread_id); return 0; } @@ -978,8 +978,8 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Aix::hotspot_sigmask(thread); - log_info(os, thread)("Thread attached (pthread id " UINTX_FORMAT ", tid " UINTX_FORMAT ")", - (uintx) pthread_id, (uintx) kernel_thread_id); + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ", kernel thread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) kernel_thread_id); return true; } diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 51fce416eda..3d6f8fd6422 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -682,7 +682,7 @@ static void *java_start(Thread *thread) { osthread->set_thread_id(os::Bsd::gettid()); - log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ".", + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", os::current_thread_id(), (uintx) pthread_self()); #ifdef __APPLE__ @@ -720,7 +720,7 @@ static void *java_start(Thread *thread) { // call one more level start routine thread->run(); - log_info(os, thread)("Thread finished (tid " UINTX_FORMAT ", pthread id " UINTX_FORMAT ").", + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", os::current_thread_id(), (uintx) pthread_self()); return 0; @@ -871,7 +871,7 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Bsd::hotspot_sigmask(thread); - log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ".", + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", os::current_thread_id(), (uintx) pthread_self()); return true; diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 5bf366d3997..d46a1146dd7 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -694,7 +694,7 @@ static void *java_start(Thread *thread) { // call one more level start routine thread->run(); - log_info(os, thread)("Thread finished (tid " UINTX_FORMAT ", pthread id " UINTX_FORMAT ").", + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", os::current_thread_id(), (uintx) pthread_self()); return 0; diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index e454ed165c7..bc8138db6ff 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -891,12 +891,11 @@ bool os::create_main_thread(JavaThread* thread) { // Helper function to trace thread attributes, similar to os::Posix::describe_pthread_attr() static char* describe_thr_create_attributes(char* buf, size_t buflen, - size_t stacksize, long flags) -{ + size_t stacksize, long flags) { stringStream ss(buf, buflen); ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024); ss.print("flags: "); - #define PRINT_FLAG(f) if (flags & f) ss.print( XSTR(f) " "); + #define PRINT_FLAG(f) if (flags & f) ss.print( #f " "); #define ALL(X) \ X(THR_SUSPENDED) \ X(THR_DETACHED) \ @@ -1006,7 +1005,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, char buf[64]; if (status == 0) { - log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + log_info(os, thread)("Thread started (tid: " UINTX_FORMAT ", attributes: %s). ", (uintx) tid, describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); } else { log_warning(os, thread)("Failed to start thread - thr_create failed (%s) for attributes: %s.", diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 7b371739e09..f8bc6081d8b 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -543,8 +543,7 @@ bool os::create_main_thread(JavaThread* thread) { // Helper function to trace _beginthreadex attributes, // similar to os::Posix::describe_pthread_attr() static char* describe_beginthreadex_attributes(char* buf, size_t buflen, - size_t stacksize, unsigned initflag) -{ + size_t stacksize, unsigned initflag) { stringStream ss(buf, buflen); if (stacksize == 0) { ss.print("stacksize: default, "); @@ -552,7 +551,7 @@ static char* describe_beginthreadex_attributes(char* buf, size_t buflen, ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024); } ss.print("flags: "); - #define PRINT_FLAG(f) if (initflag & f) ss.print( XSTR(f) " "); + #define PRINT_FLAG(f) if (initflag & f) ss.print( #f " "); #define ALL(X) \ X(CREATE_SUSPENDED) \ X(STACK_SIZE_PARAM_IS_A_RESERVATION) diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 654aebd9e70..8e1e997f8c1 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -1806,10 +1806,6 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { // Call after last event on thread EVENT_THREAD_EXIT(this); - log_info(os, thread)("Thread " UINTX_FORMAT " %s.", - os::current_thread_id(), - exit_type == JavaThread::normal_exit ? "exiting" : "detaching"); - // Call Thread.exit(). We try 3 times in case we got another Thread.stop during // the execution of the method. If that is not enough, then we don't really care. Thread.stop // is deprecated anyhow. @@ -1932,6 +1928,10 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { } #endif // INCLUDE_ALL_GCS + log_info(os, thread)("JavaThread %s (tid: " UINTX_FORMAT ").", + exit_type == JavaThread::normal_exit ? "exiting" : "detaching", + os::current_thread_id()); + // Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread Threads::remove(this); } diff --git a/hotspot/test/runtime/logging/ThreadLoggingTest.java b/hotspot/test/runtime/logging/ThreadLoggingTest.java new file mode 100644 index 00000000000..a5cde9c845c --- /dev/null +++ b/hotspot/test/runtime/logging/ThreadLoggingTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, SAP SE and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8149036 8150619 + * @summary os+thread output should contain logging calls for thread start stop attaches detaches + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools + * @run driver ThreadLoggingTest + * @author Thomas Stuefe (SAP) + */ + +import java.io.File; +import java.util.Map; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +public class ThreadLoggingTest { + + static void analyzeOutputForInfoLevel(OutputAnalyzer output) throws Exception { + output.shouldContain("Thread started"); + output.shouldContain("Thread is alive"); + output.shouldContain("Thread finished"); + output.shouldHaveExitValue(0); + } + + static void analyzeOutputForDebugLevel(OutputAnalyzer output) throws Exception { + analyzeOutputForInfoLevel(output); + output.shouldContain("stack dimensions"); + output.shouldContain("stack guard pages"); + } + + public static void main(String[] args) throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:os+thread", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + analyzeOutputForInfoLevel(output); + + pb = ProcessTools.createJavaProcessBuilder("-Xlog:os+thread=debug", "-version"); + output = new OutputAnalyzer(pb.start()); + analyzeOutputForDebugLevel(output); + + } + +} From 190c092900e680cb72c423fadbdb811ba4ec9983 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Mon, 29 Feb 2016 13:06:03 +0100 Subject: [PATCH 069/129] 8150068: Log the main G1 phases at info level Reviewed-by: sjohanss, tschatzl --- .../src/share/vm/gc/g1/g1CollectorPolicy.cpp | 9 +- hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp | 421 ++++++------------ hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp | 23 +- hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp | 5 +- hotspot/src/share/vm/gc/g1/g1RemSet.cpp | 2 +- .../src/share/vm/gc/g1/workerDataArray.cpp | 50 ++- .../src/share/vm/gc/g1/workerDataArray.hpp | 46 +- .../share/vm/gc/g1/workerDataArray.inline.hpp | 64 ++- hotspot/src/share/vm/logging/logPrefix.hpp | 1 + hotspot/test/gc/g1/TestGCLogMessages.java | 68 +-- 10 files changed, 295 insertions(+), 394 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index bd98877eded..eda5e18e1a8 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -1117,14 +1117,15 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t _short_lived_surv_rate_group->start_adding_regions(); // Do that for any other surv rate groups + double scan_hcc_time_ms = ConcurrentG1Refine::hot_card_cache_enabled() ? average_time_ms(G1GCPhaseTimes::ScanHCC) : 0.0; + if (update_stats) { double cost_per_card_ms = 0.0; - double cost_scan_hcc = average_time_ms(G1GCPhaseTimes::ScanHCC); if (_pending_cards > 0) { - cost_per_card_ms = (average_time_ms(G1GCPhaseTimes::UpdateRS) - cost_scan_hcc) / (double) _pending_cards; + cost_per_card_ms = (average_time_ms(G1GCPhaseTimes::UpdateRS) - scan_hcc_time_ms) / (double) _pending_cards; _cost_per_card_ms_seq->add(cost_per_card_ms); } - _cost_scan_hcc_seq->add(cost_scan_hcc); + _cost_scan_hcc_seq->add(scan_hcc_time_ms); double cost_per_entry_ms = 0.0; if (cards_scanned > 10) { @@ -1214,8 +1215,6 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t // 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; - double scan_hcc_time_ms = average_time_ms(G1GCPhaseTimes::ScanHCC); - if (update_rs_time_goal_ms < scan_hcc_time_ms) { log_debug(gc, ergo, refine)("Adjust concurrent refinement thresholds (scanning the HCC expected to take longer than Update RS time goal)." "Update RS time goal: %1.2fms Scan HCC time: %1.2fms", diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp index e8c852b051f..b5dce4ffc3d 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp @@ -28,109 +28,70 @@ #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1StringDedup.hpp" #include "gc/g1/workerDataArray.inline.hpp" -#include "memory/allocation.hpp" +#include "memory/resourceArea.hpp" #include "logging/log.hpp" #include "runtime/timer.hpp" #include "runtime/os.hpp" -// Helper class for avoiding interleaved logging -class LineBuffer: public StackObj { - -private: - static const int BUFFER_LEN = 1024; - static const int INDENT_CHARS = 3; - char _buffer[BUFFER_LEN]; - int _indent_level; - int _cur; - - void vappend(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0) { - int res = vsnprintf(&_buffer[_cur], BUFFER_LEN - _cur, format, ap); - if (res != -1) { - _cur += res; - } else { - DEBUG_ONLY(warning("buffer too small in LineBuffer");) - _buffer[BUFFER_LEN -1] = 0; - _cur = BUFFER_LEN; // vsnprintf above should not add to _buffer if we are called again - } - } - -public: - explicit LineBuffer(int indent_level): _indent_level(indent_level), _cur(0) { - for (; (_cur < BUFFER_LEN && _cur < (_indent_level * INDENT_CHARS)); _cur++) { - _buffer[_cur] = ' '; - } - } - -#ifndef PRODUCT - ~LineBuffer() { - assert(_cur == _indent_level * INDENT_CHARS, "pending data in buffer - append_and_print_cr() not called?"); - } -#endif - - void append(const char* format, ...) ATTRIBUTE_PRINTF(2, 3) { - va_list ap; - va_start(ap, format); - vappend(format, ap); - va_end(ap); - } - - const char* to_string() { - _cur = _indent_level * INDENT_CHARS; - return _buffer; - } -}; - -static const char* Indents[4] = {"", " ", " ", " "}; +static const char* Indents[5] = {"", " ", " ", " ", " "}; G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) : _max_gc_threads(max_gc_threads) { assert(max_gc_threads > 0, "Must have some GC threads"); - _gc_par_phases[GCWorkerStart] = new WorkerDataArray(max_gc_threads, "GC Worker Start:", false, 2); - _gc_par_phases[ExtRootScan] = new WorkerDataArray(max_gc_threads, "Ext Root Scanning:", true, 2); + _gc_par_phases[GCWorkerStart] = new WorkerDataArray(max_gc_threads, "GC Worker Start (ms):"); + _gc_par_phases[ExtRootScan] = new WorkerDataArray(max_gc_threads, "Ext Root Scanning (ms):"); // Root scanning phases - _gc_par_phases[ThreadRoots] = new WorkerDataArray(max_gc_threads, "Thread Roots:", true, 3); - _gc_par_phases[StringTableRoots] = new WorkerDataArray(max_gc_threads, "StringTable Roots:", true, 3); - _gc_par_phases[UniverseRoots] = new WorkerDataArray(max_gc_threads, "Universe Roots:", true, 3); - _gc_par_phases[JNIRoots] = new WorkerDataArray(max_gc_threads, "JNI Handles Roots:", true, 3); - _gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray(max_gc_threads, "ObjectSynchronizer Roots:", true, 3); - _gc_par_phases[FlatProfilerRoots] = new WorkerDataArray(max_gc_threads, "FlatProfiler Roots:", true, 3); - _gc_par_phases[ManagementRoots] = new WorkerDataArray(max_gc_threads, "Management Roots:", true, 3); - _gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray(max_gc_threads, "SystemDictionary Roots:", true, 3); - _gc_par_phases[CLDGRoots] = new WorkerDataArray(max_gc_threads, "CLDG Roots:", true, 3); - _gc_par_phases[JVMTIRoots] = new WorkerDataArray(max_gc_threads, "JVMTI Roots:", true, 3); - _gc_par_phases[CMRefRoots] = new WorkerDataArray(max_gc_threads, "CM RefProcessor Roots:", true, 3); - _gc_par_phases[WaitForStrongCLD] = new WorkerDataArray(max_gc_threads, "Wait For Strong CLD:", true, 3); - _gc_par_phases[WeakCLDRoots] = new WorkerDataArray(max_gc_threads, "Weak CLD Roots:", true, 3); - _gc_par_phases[SATBFiltering] = new WorkerDataArray(max_gc_threads, "SATB Filtering:", true, 3); + _gc_par_phases[ThreadRoots] = new WorkerDataArray(max_gc_threads, "Thread Roots (ms):"); + _gc_par_phases[StringTableRoots] = new WorkerDataArray(max_gc_threads, "StringTable Roots (ms):"); + _gc_par_phases[UniverseRoots] = new WorkerDataArray(max_gc_threads, "Universe Roots (ms):"); + _gc_par_phases[JNIRoots] = new WorkerDataArray(max_gc_threads, "JNI Handles Roots (ms):"); + _gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray(max_gc_threads, "ObjectSynchronizer Roots (ms):"); + _gc_par_phases[FlatProfilerRoots] = new WorkerDataArray(max_gc_threads, "FlatProfiler Roots (ms):"); + _gc_par_phases[ManagementRoots] = new WorkerDataArray(max_gc_threads, "Management Roots (ms):"); + _gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray(max_gc_threads, "SystemDictionary Roots (ms):"); + _gc_par_phases[CLDGRoots] = new WorkerDataArray(max_gc_threads, "CLDG Roots (ms):"); + _gc_par_phases[JVMTIRoots] = new WorkerDataArray(max_gc_threads, "JVMTI Roots (ms):"); + _gc_par_phases[CMRefRoots] = new WorkerDataArray(max_gc_threads, "CM RefProcessor Roots (ms):"); + _gc_par_phases[WaitForStrongCLD] = new WorkerDataArray(max_gc_threads, "Wait For Strong CLD (ms):"); + _gc_par_phases[WeakCLDRoots] = new WorkerDataArray(max_gc_threads, "Weak CLD Roots (ms):"); + _gc_par_phases[SATBFiltering] = new WorkerDataArray(max_gc_threads, "SATB Filtering (ms):"); - _gc_par_phases[UpdateRS] = new WorkerDataArray(max_gc_threads, "Update RS:", true, 2); - _gc_par_phases[ScanHCC] = new WorkerDataArray(max_gc_threads, "Scan HCC:", true, 3); - _gc_par_phases[ScanHCC]->set_enabled(ConcurrentG1Refine::hot_card_cache_enabled()); - _gc_par_phases[ScanRS] = new WorkerDataArray(max_gc_threads, "Scan RS:", true, 2); - _gc_par_phases[CodeRoots] = new WorkerDataArray(max_gc_threads, "Code Root Scanning:", true, 2); - _gc_par_phases[ObjCopy] = new WorkerDataArray(max_gc_threads, "Object Copy:", true, 2); - _gc_par_phases[Termination] = new WorkerDataArray(max_gc_threads, "Termination:", true, 2); - _gc_par_phases[GCWorkerTotal] = new WorkerDataArray(max_gc_threads, "GC Worker Total:", true, 2); - _gc_par_phases[GCWorkerEnd] = new WorkerDataArray(max_gc_threads, "GC Worker End:", false, 2); - _gc_par_phases[Other] = new WorkerDataArray(max_gc_threads, "GC Worker Other:", true, 2); + _gc_par_phases[UpdateRS] = new WorkerDataArray(max_gc_threads, "Update RS (ms):"); + if (ConcurrentG1Refine::hot_card_cache_enabled()) { + _gc_par_phases[ScanHCC] = new WorkerDataArray(max_gc_threads, "Scan HCC (ms):"); + } else { + _gc_par_phases[ScanHCC] = NULL; + } + _gc_par_phases[ScanRS] = new WorkerDataArray(max_gc_threads, "Scan RS (ms):"); + _gc_par_phases[CodeRoots] = new WorkerDataArray(max_gc_threads, "Code Root Scanning (ms):"); + _gc_par_phases[ObjCopy] = new WorkerDataArray(max_gc_threads, "Object Copy (ms):"); + _gc_par_phases[Termination] = new WorkerDataArray(max_gc_threads, "Termination (ms):"); + _gc_par_phases[GCWorkerTotal] = new WorkerDataArray(max_gc_threads, "GC Worker Total (ms):"); + _gc_par_phases[GCWorkerEnd] = new WorkerDataArray(max_gc_threads, "GC Worker End (ms):"); + _gc_par_phases[Other] = new WorkerDataArray(max_gc_threads, "GC Worker Other (ms):"); - _update_rs_processed_buffers = new WorkerDataArray(max_gc_threads, "Processed Buffers:", true, 3); + _update_rs_processed_buffers = new WorkerDataArray(max_gc_threads, "Processed Buffers:"); _gc_par_phases[UpdateRS]->link_thread_work_items(_update_rs_processed_buffers); - _termination_attempts = new WorkerDataArray(max_gc_threads, "Termination Attempts:", true, 3); + _termination_attempts = new WorkerDataArray(max_gc_threads, "Termination Attempts:"); _gc_par_phases[Termination]->link_thread_work_items(_termination_attempts); - _gc_par_phases[StringDedupQueueFixup] = new WorkerDataArray(max_gc_threads, "Queue Fixup:", true, 2); - _gc_par_phases[StringDedupTableFixup] = new WorkerDataArray(max_gc_threads, "Table Fixup:", true, 2); + if (UseStringDeduplication) { + _gc_par_phases[StringDedupQueueFixup] = new WorkerDataArray(max_gc_threads, "Queue Fixup (ms):"); + _gc_par_phases[StringDedupTableFixup] = new WorkerDataArray(max_gc_threads, "Table Fixup (ms):"); + } else { + _gc_par_phases[StringDedupQueueFixup] = NULL; + _gc_par_phases[StringDedupTableFixup] = NULL; + } - _gc_par_phases[RedirtyCards] = new WorkerDataArray(max_gc_threads, "Parallel Redirty:", true, 3); - _redirtied_cards = new WorkerDataArray(max_gc_threads, "Redirtied Cards:", true, 3); + _gc_par_phases[RedirtyCards] = new WorkerDataArray(max_gc_threads, "Parallel Redirty (ms):"); + _redirtied_cards = new WorkerDataArray(max_gc_threads, "Redirtied Cards:"); _gc_par_phases[RedirtyCards]->link_thread_work_items(_redirtied_cards); - _gc_par_phases[PreserveCMReferents] = new WorkerDataArray(max_gc_threads, "Parallel Preserve CM Refs:", true, 3); + _gc_par_phases[PreserveCMReferents] = new WorkerDataArray(max_gc_threads, "Parallel Preserve CM Refs (ms):"); } void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) { @@ -142,11 +103,10 @@ void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) { _external_accounted_time_ms = 0.0; for (int i = 0; i < GCParPhasesSentinel; i++) { - _gc_par_phases[i]->reset(); + if (_gc_par_phases[i] != NULL) { + _gc_par_phases[i]->reset(); + } } - - _gc_par_phases[StringDedupQueueFixup]->set_enabled(G1StringDedup::is_enabled()); - _gc_par_phases[StringDedupTableFixup]->set_enabled(G1StringDedup::is_enabled()); } void G1GCPhaseTimes::note_gc_end() { @@ -168,43 +128,10 @@ void G1GCPhaseTimes::note_gc_end() { } for (int i = 0; i < GCParPhasesSentinel; i++) { - _gc_par_phases[i]->verify(_active_gc_threads); - } -} - -void G1GCPhaseTimes::print_stats(const char* indent, const char* str, double value) { - log_debug(gc, phases)("%s%s: %.1lf ms", indent, str, value); -} - -double G1GCPhaseTimes::accounted_time_ms() { - // First subtract any externally accounted time - double misc_time_ms = _external_accounted_time_ms; - - // Subtract the root region scanning wait time. It's initialized to - // zero at the start of the pause. - misc_time_ms += _root_region_scan_wait_time_ms; - - misc_time_ms += _cur_collection_par_time_ms; - - // Now subtract the time taken to fix up roots in generated code - misc_time_ms += _cur_collection_code_root_fixup_time_ms; - - // Strong code root purge time - misc_time_ms += _cur_strong_code_root_purge_time_ms; - - if (G1StringDedup::is_enabled()) { - // String dedup fixup time - misc_time_ms += _cur_string_dedup_fixup_time_ms; + if (_gc_par_phases[i] != NULL) { + _gc_par_phases[i]->verify(_active_gc_threads); } - - // Subtract the time taken to clean the card table from the - // current value of "other time" - misc_time_ms += _cur_clear_ct_time_ms; - - // Remove expand heap time from "other time" - misc_time_ms += _cur_expand_heap_time_ms; - - return misc_time_ms; + } } // record the time a phase took in seconds @@ -226,196 +153,144 @@ double G1GCPhaseTimes::average_time_ms(GCParPhases phase) { return _gc_par_phases[phase]->average(_active_gc_threads) * 1000.0; } -double G1GCPhaseTimes::get_time_ms(GCParPhases phase, uint worker_i) { - return _gc_par_phases[phase]->get(worker_i) * 1000.0; -} - -double G1GCPhaseTimes::sum_time_ms(GCParPhases phase) { - return _gc_par_phases[phase]->sum(_active_gc_threads) * 1000.0; -} - -double G1GCPhaseTimes::min_time_ms(GCParPhases phase) { - return _gc_par_phases[phase]->minimum(_active_gc_threads) * 1000.0; -} - -double G1GCPhaseTimes::max_time_ms(GCParPhases phase) { - return _gc_par_phases[phase]->maximum(_active_gc_threads) * 1000.0; -} - -size_t G1GCPhaseTimes::get_thread_work_item(GCParPhases phase, uint worker_i) { - assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); - return _gc_par_phases[phase]->thread_work_items()->get(worker_i); -} - size_t G1GCPhaseTimes::sum_thread_work_items(GCParPhases phase) { assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); return _gc_par_phases[phase]->thread_work_items()->sum(_active_gc_threads); } -double G1GCPhaseTimes::average_thread_work_items(GCParPhases phase) { - assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); - return _gc_par_phases[phase]->thread_work_items()->average(_active_gc_threads); +template +void G1GCPhaseTimes::details(T* phase, const char* indent) { + LogHandle(gc, phases, task) log; + if (log.is_level(LogLevel::Trace)) { + outputStream* trace_out = log.trace_stream(); + trace_out->print("%s", indent); + phase->print_details_on(trace_out, _active_gc_threads); + } } -size_t G1GCPhaseTimes::min_thread_work_items(GCParPhases phase) { - assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); - return _gc_par_phases[phase]->thread_work_items()->minimum(_active_gc_threads); +void G1GCPhaseTimes::log_phase(WorkerDataArray* phase, uint indent, outputStream* out, bool print_sum) { + out->print("%s", Indents[indent]); + phase->print_summary_on(out, _active_gc_threads, print_sum); + details(phase, Indents[indent]); + + WorkerDataArray* work_items = phase->thread_work_items(); + if (work_items != NULL) { + out->print("%s", Indents[indent + 1]); + work_items->print_summary_on(out, _active_gc_threads, true); + details(work_items, Indents[indent + 1]); + } } -size_t G1GCPhaseTimes::max_thread_work_items(GCParPhases phase) { - assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); - return _gc_par_phases[phase]->thread_work_items()->maximum(_active_gc_threads); +void G1GCPhaseTimes::debug_phase(WorkerDataArray* phase) { + LogHandle(gc, phases) log; + if (log.is_level(LogLevel::Debug)) { + ResourceMark rm; + log_phase(phase, 2, log.debug_stream(), true); + } } -class G1GCParPhasePrinter : public StackObj { - G1GCPhaseTimes* _phase_times; - public: - G1GCParPhasePrinter(G1GCPhaseTimes* phase_times) : _phase_times(phase_times) {} - - void print(G1GCPhaseTimes::GCParPhases phase_id) { - WorkerDataArray* phase = _phase_times->_gc_par_phases[phase_id]; - - if (phase->_length == 1) { - print_single_length(phase_id, phase); - } else { - print_multi_length(phase_id, phase); - } +void G1GCPhaseTimes::trace_phase(WorkerDataArray* phase, bool print_sum) { + LogHandle(gc, phases) log; + if (log.is_level(LogLevel::Trace)) { + ResourceMark rm; + log_phase(phase, 3, log.trace_stream(), print_sum); } +} +#define PHASE_DOUBLE_FORMAT "%s%s: %.1lfms" +#define PHASE_SIZE_FORMAT "%s%s: " SIZE_FORMAT - private: - void print_single_length(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* phase) { - // No need for min, max, average and sum for only one worker - log_debug(gc, phases)("%s%s: %.1lf", Indents[phase->_indent_level], phase->_title, _phase_times->get_time_ms(phase_id, 0)); +#define info_line(str, value) \ + log_info(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[1], str, value); - WorkerDataArray* work_items = phase->_thread_work_items; - if (work_items != NULL) { - log_debug(gc, phases)("%s%s: " SIZE_FORMAT, Indents[work_items->_indent_level], work_items->_title, _phase_times->sum_thread_work_items(phase_id)); - } - } +#define debug_line(str, value) \ + log_debug(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[2], str, value); - void print_time_values(const char* indent, G1GCPhaseTimes::GCParPhases phase_id) { - if (log_is_enabled(Trace, gc)) { - LineBuffer buf(0); - uint active_length = _phase_times->_active_gc_threads; - for (uint i = 0; i < active_length; ++i) { - buf.append(" %4.1lf", _phase_times->get_time_ms(phase_id, i)); - } - const char* line = buf.to_string(); - log_trace(gc, phases)("%s%-25s%s", indent, "", line); - } - } +#define trace_line(str, value) \ + log_trace(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[3], str, value); - void print_count_values(const char* indent, G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* thread_work_items) { - if (log_is_enabled(Trace, gc)) { - LineBuffer buf(0); - uint active_length = _phase_times->_active_gc_threads; - for (uint i = 0; i < active_length; ++i) { - buf.append(" " SIZE_FORMAT, _phase_times->get_thread_work_item(phase_id, i)); - } - const char* line = buf.to_string(); - log_trace(gc, phases)("%s%-25s%s", indent, "", line); - } - } +#define trace_line_sz(str, value) \ + log_trace(gc, phases)(PHASE_SIZE_FORMAT, Indents[3], str, value); - void print_thread_work_items(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* thread_work_items) { - const char* indent = Indents[thread_work_items->_indent_level]; +#define trace_line_ms(str, value) \ + log_trace(gc, phases)(PHASE_SIZE_FORMAT, Indents[3], str, value); - assert(thread_work_items->_print_sum, "%s does not have print sum true even though it is a count", thread_work_items->_title); - - log_debug(gc, phases)("%s%-25s Min: " SIZE_FORMAT ", Avg: %4.1lf, Max: " SIZE_FORMAT ", Diff: " SIZE_FORMAT ", Sum: " SIZE_FORMAT, - indent, thread_work_items->_title, - _phase_times->min_thread_work_items(phase_id), _phase_times->average_thread_work_items(phase_id), _phase_times->max_thread_work_items(phase_id), - _phase_times->max_thread_work_items(phase_id) - _phase_times->min_thread_work_items(phase_id), _phase_times->sum_thread_work_items(phase_id)); - - print_count_values(indent, phase_id, thread_work_items); - } - - void print_multi_length(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* phase) { - const char* indent = Indents[phase->_indent_level]; - - if (phase->_print_sum) { - log_debug(gc, phases)("%s%-25s Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf, Sum: %4.1lf", - indent, phase->_title, - _phase_times->min_time_ms(phase_id), _phase_times->average_time_ms(phase_id), _phase_times->max_time_ms(phase_id), - _phase_times->max_time_ms(phase_id) - _phase_times->min_time_ms(phase_id), _phase_times->sum_time_ms(phase_id)); - } else { - log_debug(gc, phases)("%s%-25s Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf", - indent, phase->_title, - _phase_times->min_time_ms(phase_id), _phase_times->average_time_ms(phase_id), _phase_times->max_time_ms(phase_id), - _phase_times->max_time_ms(phase_id) - _phase_times->min_time_ms(phase_id)); - } - - print_time_values(indent, phase_id); - - if (phase->_thread_work_items != NULL) { - print_thread_work_items(phase_id, phase->_thread_work_items); - } - } -}; +#define info_line_and_account(str, value) \ + info_line(str, value); \ + accounted_time_ms += value; void G1GCPhaseTimes::print() { note_gc_end(); - G1GCParPhasePrinter par_phase_printer(this); - + double accounted_time_ms = _external_accounted_time_ms; if (_root_region_scan_wait_time_ms > 0.0) { - print_stats(Indents[1], "Root Region Scan Waiting", _root_region_scan_wait_time_ms); + info_line_and_account("Root Region Scan Waiting", _root_region_scan_wait_time_ms); } - print_stats(Indents[1], "Parallel Time", _cur_collection_par_time_ms); - for (int i = 0; i <= GCMainParPhasesLast; i++) { - par_phase_printer.print((GCParPhases) i); + info_line_and_account("Evacuate Collection Set", _cur_collection_par_time_ms); + trace_phase(_gc_par_phases[GCWorkerStart], false); + debug_phase(_gc_par_phases[ExtRootScan]); + for (int i = ThreadRoots; i <= SATBFiltering; i++) { + trace_phase(_gc_par_phases[i]); } + debug_phase(_gc_par_phases[UpdateRS]); + if (ConcurrentG1Refine::hot_card_cache_enabled()) { + trace_phase(_gc_par_phases[ScanHCC]); + } + debug_phase(_gc_par_phases[ScanRS]); + debug_phase(_gc_par_phases[CodeRoots]); + debug_phase(_gc_par_phases[ObjCopy]); + debug_phase(_gc_par_phases[Termination]); + debug_phase(_gc_par_phases[Other]); + debug_phase(_gc_par_phases[GCWorkerTotal]); + trace_phase(_gc_par_phases[GCWorkerEnd], false); + + info_line_and_account("Code Roots", _cur_collection_code_root_fixup_time_ms + _cur_strong_code_root_purge_time_ms); + debug_line("Code Roots Fixup", _cur_collection_code_root_fixup_time_ms); + debug_line("Code Roots Purge", _cur_strong_code_root_purge_time_ms); - print_stats(Indents[1], "Code Root Fixup", _cur_collection_code_root_fixup_time_ms); - print_stats(Indents[1], "Code Root Purge", _cur_strong_code_root_purge_time_ms); if (G1StringDedup::is_enabled()) { - print_stats(Indents[1], "String Dedup Fixup", _cur_string_dedup_fixup_time_ms); - for (int i = StringDedupPhasesFirst; i <= StringDedupPhasesLast; i++) { - par_phase_printer.print((GCParPhases) i); - } + info_line_and_account("String Dedup Fixup", _cur_string_dedup_fixup_time_ms); + debug_phase(_gc_par_phases[StringDedupQueueFixup]); + debug_phase(_gc_par_phases[StringDedupTableFixup]); } - print_stats(Indents[1], "Clear CT", _cur_clear_ct_time_ms); - print_stats(Indents[1], "Expand Heap After Collection", _cur_expand_heap_time_ms); - double misc_time_ms = _gc_pause_time_ms - accounted_time_ms(); - print_stats(Indents[1], "Other", misc_time_ms); + info_line_and_account("Clear Card Table", _cur_clear_ct_time_ms); + info_line_and_account("Expand Heap After Collection", _cur_expand_heap_time_ms); + + double free_cset_time = _recorded_young_free_cset_time_ms + _recorded_non_young_free_cset_time_ms; + info_line_and_account("Free Collection Set", free_cset_time); + debug_line("Young Free Collection Set", _recorded_young_free_cset_time_ms); + debug_line("Non-Young Free Collection Set", _recorded_non_young_free_cset_time_ms); + info_line_and_account("Merge Per-Thread State", _recorded_merge_pss_time_ms); + + info_line("Other", _gc_pause_time_ms - accounted_time_ms); if (_cur_verify_before_time_ms > 0.0) { - print_stats(Indents[2], "Verify Before", _cur_verify_before_time_ms); + debug_line("Verify Before", _cur_verify_before_time_ms); } if (G1CollectedHeap::heap()->evacuation_failed()) { double evac_fail_handling = _cur_evac_fail_recalc_used + _cur_evac_fail_remove_self_forwards + _cur_evac_fail_restore_remsets; - print_stats(Indents[2], "Evacuation Failure", evac_fail_handling); - log_trace(gc, phases)("%sRecalculate Used: %.1lf ms", Indents[3], _cur_evac_fail_recalc_used); - log_trace(gc, phases)("%sRemove Self Forwards: %.1lf ms", Indents[3], _cur_evac_fail_remove_self_forwards); - log_trace(gc, phases)("%sRestore RemSet: %.1lf ms", Indents[3], _cur_evac_fail_restore_remsets); + debug_line("Evacuation Failure", evac_fail_handling); + trace_line("Recalculate Used", _cur_evac_fail_recalc_used); + trace_line("Remove Self Forwards",_cur_evac_fail_remove_self_forwards); + trace_line("Restore RemSet", _cur_evac_fail_restore_remsets); } - print_stats(Indents[2], "Choose CSet", - (_recorded_young_cset_choice_time_ms + - _recorded_non_young_cset_choice_time_ms)); - print_stats(Indents[2], "Preserve CM Refs", _recorded_preserve_cm_referents_time_ms); - print_stats(Indents[2], "Ref Proc", _cur_ref_proc_time_ms); - print_stats(Indents[2], "Ref Enq", _cur_ref_enq_time_ms); - print_stats(Indents[2], "Redirty Cards", _recorded_redirty_logged_cards_time_ms); - par_phase_printer.print(RedirtyCards); - par_phase_printer.print(PreserveCMReferents); + debug_line("Choose CSet", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms)); + debug_line("Preserve CM Refs", _recorded_preserve_cm_referents_time_ms); + debug_line("Ref Proc", _cur_ref_proc_time_ms); + debug_line("Ref Enq", _cur_ref_enq_time_ms); + debug_line("Redirty Cards", _recorded_redirty_logged_cards_time_ms); + trace_phase(_gc_par_phases[RedirtyCards]); + trace_phase(_gc_par_phases[PreserveCMReferents]); if (G1EagerReclaimHumongousObjects) { - print_stats(Indents[2], "Humongous Register", _cur_fast_reclaim_humongous_register_time_ms); - - log_trace(gc, phases)("%sHumongous Total: " SIZE_FORMAT, Indents[3], _cur_fast_reclaim_humongous_total); - log_trace(gc, phases)("%sHumongous Candidate: " SIZE_FORMAT, Indents[3], _cur_fast_reclaim_humongous_candidates); - print_stats(Indents[2], "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms); - log_trace(gc, phases)("%sHumongous Reclaimed: " SIZE_FORMAT, Indents[3], _cur_fast_reclaim_humongous_reclaimed); + debug_line("Humongous Register", _cur_fast_reclaim_humongous_register_time_ms); + trace_line_sz("Humongous Total", _cur_fast_reclaim_humongous_total); + trace_line_sz("Humongous Candidate", _cur_fast_reclaim_humongous_candidates); + debug_line("Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms); + trace_line_sz("Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed); } - print_stats(Indents[2], "Free CSet", - (_recorded_young_free_cset_time_ms + - _recorded_non_young_free_cset_time_ms)); - log_trace(gc, phases)("%sYoung Free CSet: %.1lf ms", Indents[3], _recorded_young_free_cset_time_ms); - log_trace(gc, phases)("%sNon-Young Free CSet: %.1lf ms", Indents[3], _recorded_non_young_free_cset_time_ms); - print_stats(Indents[2], "Merge Per-Thread State", _recorded_merge_pss_time_ms); if (_cur_verify_after_time_ms > 0.0) { - print_stats(Indents[2], "Verify After", _cur_verify_after_time_ms); + debug_line("Verify After", _cur_verify_after_time_ms); } } diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp index c474659a849..e87075b5e93 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp @@ -32,8 +32,6 @@ class LineBuffer; template class WorkerDataArray; class G1GCPhaseTimes : public CHeapObj { - friend class G1GCParPhasePrinter; - uint _active_gc_threads; uint _max_gc_threads; jlong _gc_start_counter; @@ -125,11 +123,14 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_verify_before_time_ms; double _cur_verify_after_time_ms; - // Helper methods for detailed logging - void print_stats(const char*, const char* str, double value); - void note_gc_end(); + template + void details(T* phase, const char* indent); + void log_phase(WorkerDataArray* phase, uint indent, outputStream* out, bool print_sum); + void debug_phase(WorkerDataArray* phase); + void trace_phase(WorkerDataArray* phase, bool print_sum = true); + public: G1GCPhaseTimes(uint max_gc_threads); void note_gc_start(uint active_gc_threads); @@ -148,16 +149,6 @@ class G1GCPhaseTimes : public CHeapObj { size_t sum_thread_work_items(GCParPhases phase); - private: - double get_time_ms(GCParPhases phase, uint worker_i); - double sum_time_ms(GCParPhases phase); - double min_time_ms(GCParPhases phase); - double max_time_ms(GCParPhases phase); - size_t get_thread_work_item(GCParPhases phase, uint worker_i); - double average_thread_work_items(GCParPhases phase); - size_t min_thread_work_items(GCParPhases phase); - size_t max_thread_work_items(GCParPhases phase); - public: void record_clear_ct_time(double ms) { @@ -263,8 +254,6 @@ class G1GCPhaseTimes : public CHeapObj { _external_accounted_time_ms += time_ms; } - double accounted_time_ms(); - double cur_collection_start_sec() { return _cur_collection_start_sec; } diff --git a/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp b/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp index b7c176d632b..013be1a12f8 100644 --- a/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp +++ b/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp @@ -81,10 +81,7 @@ jbyte* G1HotCardCache::insert(jbyte* card_ptr) { } void G1HotCardCache::drain(CardTableEntryClosure* cl, uint worker_i) { - if (!default_use_cache()) { - assert(_hot_cache == NULL, "Logic"); - return; - } + assert(default_use_cache(), "Drain only necessary if we use the hot card cache."); assert(_hot_cache != NULL, "Logic"); assert(!use_cache(), "cache should be disabled"); diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp index 3d2917a2184..8c31430e185 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp @@ -238,7 +238,7 @@ void G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, uint worker_i) { RefineRecordRefsIntoCSCardTableEntryClosure into_cset_update_rs_cl(_g1, into_cset_dcq); G1GCParPhaseTimesTracker x(_g1p->phase_times(), G1GCPhaseTimes::UpdateRS, worker_i); - { + if (ConcurrentG1Refine::hot_card_cache_enabled()) { // Apply the closure to the entries of the hot card cache. G1GCParPhaseTimesTracker y(_g1p->phase_times(), G1GCPhaseTimes::ScanHCC, worker_i); _g1->iterate_hcc_closure(&into_cset_update_rs_cl, worker_i); diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.cpp b/hotspot/src/share/vm/gc/g1/workerDataArray.cpp index 0e3305d5c2a..62b66559a53 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.cpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.cpp @@ -24,18 +24,53 @@ #include "precompiled.hpp" #include "gc/g1/workerDataArray.inline.hpp" +#include "utilities/ostream.hpp" + +template <> +void WorkerDataArray::WDAPrinter::summary(outputStream* out, const char* title, double min, double avg, double max, double diff, double sum, bool print_sum) { + out->print("%-25s Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf", title, min * MILLIUNITS, avg * MILLIUNITS, max * MILLIUNITS, diff* MILLIUNITS); + if (print_sum) { + out->print_cr(", Sum: %4.1lf", sum * MILLIUNITS); + } else { + out->cr(); + } +} + +template <> +void WorkerDataArray::WDAPrinter::summary(outputStream* out, const char* title, size_t min, double avg, size_t max, size_t diff, size_t sum, bool print_sum) { + out->print("%-25s Min: " SIZE_FORMAT ", Avg: %4.1lf, Max: " SIZE_FORMAT ", Diff: " SIZE_FORMAT, title, min, avg, max, diff); + if (print_sum) { + out->print_cr(", Sum: " SIZE_FORMAT, sum); + } else { + out->cr(); + } +} + +template <> +void WorkerDataArray::WDAPrinter::details(const WorkerDataArray* phase, outputStream* out, uint active_threads) { + out->print("%-25s", ""); + for (uint i = 0; i < active_threads; ++i) { + out->print(" %4.1lf", phase->get(i) * 1000.0); + } + out->cr(); +} + +template <> +void WorkerDataArray::WDAPrinter::details(const WorkerDataArray* phase, outputStream* out, uint active_threads) { + out->print("%-25s", ""); + for (uint i = 0; i < active_threads; ++i) { + out->print(" " SIZE_FORMAT, phase->get(i)); + } + out->cr(); +} #ifndef PRODUCT void WorkerDataArray_test() { const uint length = 3; const char* title = "Test array"; - const bool print_sum = false; - const uint indent_level = 2; - WorkerDataArray array(length, title, print_sum, indent_level); + WorkerDataArray array(length, title); assert(strncmp(array.title(), title, strlen(title)) == 0 , "Expected titles to match"); - assert(array.should_print_sum() == print_sum, "Expected should_print_sum to match print_sum"); - assert(array.indentation() == indent_level, "Expected indentation to match"); const size_t expected[length] = {5, 3, 7}; for (uint i = 0; i < length; i++) { @@ -46,10 +81,7 @@ void WorkerDataArray_test() { } assert(array.sum(length) == (5 + 3 + 7), "Expected sums to match"); - assert(array.minimum(length) == 3, "Expected mininum to match"); - assert(array.maximum(length) == 7, "Expected maximum to match"); - assert(array.diff(length) == (7 - 3), "Expected diffs to match"); - assert(array.average(length) == 5, "Expected averages to match"); + assert(array.average(length) == 5.0, "Expected averages to match"); for (uint i = 0; i < length; i++) { array.add(i, 1); diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.hpp b/hotspot/src/share/vm/gc/g1/workerDataArray.hpp index 09f0b61a5f7..e1e972327ea 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.hpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.hpp @@ -22,18 +22,19 @@ * */ +#ifndef SHARE_VM_GC_G1_WORKERDATAARRAY_HPP +#define SHARE_VM_GC_G1_WORKERDATAARRAY_HPP + #include "memory/allocation.hpp" #include "utilities/debug.hpp" +class outputStream; + template class WorkerDataArray : public CHeapObj { - friend class G1GCParPhasePrinter; T* _data; uint _length; const char* _title; - bool _print_sum; - uint _indent_level; - bool _enabled; WorkerDataArray* _thread_work_items; @@ -42,11 +43,7 @@ class WorkerDataArray : public CHeapObj { void set_all(T value); public: - WorkerDataArray(uint length, - const char* title, - bool print_sum, - uint indent_level); - + WorkerDataArray(uint length, const char* title); ~WorkerDataArray(); void link_thread_work_items(WorkerDataArray* thread_work_items); @@ -62,27 +59,30 @@ class WorkerDataArray : public CHeapObj { double average(uint active_threads) const; T sum(uint active_threads) const; - T minimum(uint active_threads) const; - T maximum(uint active_threads) const; - T diff(uint active_threads) const; - - uint indentation() const { - return _indent_level; - } const char* title() const { return _title; } - bool should_print_sum() const { - return _print_sum; - } - void clear(); - void set_enabled(bool enabled) { - _enabled = enabled; - } void reset() PRODUCT_RETURN; void verify(uint active_threads) const PRODUCT_RETURN; + + + private: + class WDAPrinter { + public: + static void summary(outputStream* out, const char* title, double min, double avg, double max, double diff, double sum, bool print_sum); + static void summary(outputStream* out, const char* title, size_t min, double avg, size_t max, size_t diff, size_t sum, bool print_sum); + + static void details(const WorkerDataArray* phase, outputStream* out, uint active_threads); + static void details(const WorkerDataArray* phase, outputStream* out, uint active_threads); + }; + + public: + void print_summary_on(outputStream* out, uint active_threads, bool print_sum = true) const; + void print_details_on(outputStream* out, uint active_threads) const; }; + +#endif // SHARE_VM_GC_G1_WORKERDATAARRAY_HPP diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp b/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp index 713eb125cff..7b4df8628b8 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp @@ -22,20 +22,18 @@ * */ +#ifndef SHARE_VM_GC_G1_WORKERDATAARRAY_INLINE_HPP +#define SHARE_VM_GC_G1_WORKERDATAARRAY_INLINE_HPP + #include "gc/g1/workerDataArray.hpp" #include "memory/allocation.inline.hpp" +#include "utilities/ostream.hpp" template -WorkerDataArray::WorkerDataArray(uint length, - const char* title, - bool print_sum, - uint indent_level) : +WorkerDataArray::WorkerDataArray(uint length, const char* title) : _title(title), _length(0), - _print_sum(print_sum), - _indent_level(indent_level), - _thread_work_items(NULL), - _enabled(true) { + _thread_work_items(NULL) { assert(length > 0, "Must have some workers to store data for"); _length = length; _data = NEW_C_HEAP_ARRAY(T, _length, mtGC); @@ -93,29 +91,6 @@ T WorkerDataArray::sum(uint active_threads) const { return s; } -template -T WorkerDataArray::minimum(uint active_threads) const { - T min = get(0); - for (uint i = 1; i < active_threads; ++i) { - min = MIN2(min, get(i)); - } - return min; -} - -template -T WorkerDataArray::maximum(uint active_threads) const { - T max = get(0); - for (uint i = 1; i < active_threads; ++i) { - max = MAX2(max, get(i)); - } - return max; -} - -template -T WorkerDataArray::diff(uint active_threads) const { - return maximum(active_threads) - minimum(active_threads); -} - template void WorkerDataArray::clear() { set_all(0); @@ -128,6 +103,27 @@ void WorkerDataArray::set_all(T value) { } } +template +void WorkerDataArray::print_summary_on(outputStream* out, uint active_threads, bool print_sum) const { + T max = get(0); + T min = max; + T sum = 0; + for (uint i = 1; i < active_threads; ++i) { + T value = get(i); + max = MAX2(max, value); + min = MIN2(min, value); + sum += value; + } + T diff = max - min; + double avg = sum / (double) active_threads; + WDAPrinter::summary(out, title(), min, avg, max, diff, sum, print_sum); +} + +template +void WorkerDataArray::print_details_on(outputStream* out, uint active_threads) const { + WDAPrinter::details(this, out, active_threads); +} + #ifndef PRODUCT template void WorkerDataArray::reset() { @@ -139,10 +135,6 @@ void WorkerDataArray::reset() { template void WorkerDataArray::verify(uint active_threads) const { - if (!_enabled) { - return; - } - assert(active_threads <= _length, "Wrong number of active threads"); for (uint i = 0; i < active_threads; i++) { assert(_data[i] != uninitialized(), @@ -163,3 +155,5 @@ inline double WorkerDataArray::uninitialized() const { return -1.0; } #endif + +#endif // SHARE_VM_GC_G1_WORKERDATAARRAY_INLINE_HPP diff --git a/hotspot/src/share/vm/logging/logPrefix.hpp b/hotspot/src/share/vm/logging/logPrefix.hpp index 039e5f44416..213fa7c2806 100644 --- a/hotspot/src/share/vm/logging/logPrefix.hpp +++ b/hotspot/src/share/vm/logging/logPrefix.hpp @@ -58,6 +58,7 @@ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, metaspace)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, start)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, task)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, plab)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, region)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, remset)) \ diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java index 0659c98f1c9..81526644c59 100644 --- a/hotspot/test/gc/g1/TestGCLogMessages.java +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -38,10 +38,24 @@ import jdk.test.lib.OutputAnalyzer; public class TestGCLogMessages { private enum Level { - OFF, DEBUG, TRACE; - public boolean lessOrEqualTo(Level other) { + OFF(""), + INFO("info"), + DEBUG("debug"), + TRACE("trace"); + + private String logName; + + Level(String logName) { + this.logName = logName; + } + + public boolean lessThan(Level other) { return this.compareTo(other) < 0; } + + public String toString() { + return logName; + } } private class LogMessageWithLevel { @@ -56,48 +70,48 @@ public class TestGCLogMessages { private LogMessageWithLevel allLogMessages[] = new LogMessageWithLevel[] { // Update RS - new LogMessageWithLevel("Scan HCC", Level.DEBUG), + new LogMessageWithLevel("Scan HCC", Level.TRACE), // Ext Root Scan - new LogMessageWithLevel("Thread Roots:", Level.DEBUG), - new LogMessageWithLevel("StringTable Roots:", Level.DEBUG), - new LogMessageWithLevel("Universe Roots:", Level.DEBUG), - new LogMessageWithLevel("JNI Handles Roots:", Level.DEBUG), - new LogMessageWithLevel("ObjectSynchronizer Roots:", Level.DEBUG), - new LogMessageWithLevel("FlatProfiler Roots", Level.DEBUG), - new LogMessageWithLevel("Management Roots", Level.DEBUG), - new LogMessageWithLevel("SystemDictionary Roots", Level.DEBUG), - new LogMessageWithLevel("CLDG Roots", Level.DEBUG), - new LogMessageWithLevel("JVMTI Roots", Level.DEBUG), - new LogMessageWithLevel("SATB Filtering", Level.DEBUG), - new LogMessageWithLevel("CM RefProcessor Roots", Level.DEBUG), - new LogMessageWithLevel("Wait For Strong CLD", Level.DEBUG), - new LogMessageWithLevel("Weak CLD Roots", Level.DEBUG), + new LogMessageWithLevel("Thread Roots", Level.TRACE), + new LogMessageWithLevel("StringTable Roots", Level.TRACE), + new LogMessageWithLevel("Universe Roots", Level.TRACE), + new LogMessageWithLevel("JNI Handles Roots", Level.TRACE), + new LogMessageWithLevel("ObjectSynchronizer Roots", Level.TRACE), + new LogMessageWithLevel("FlatProfiler Roots", Level.TRACE), + new LogMessageWithLevel("Management Roots", Level.TRACE), + new LogMessageWithLevel("SystemDictionary Roots", Level.TRACE), + new LogMessageWithLevel("CLDG Roots", Level.TRACE), + new LogMessageWithLevel("JVMTI Roots", Level.TRACE), + new LogMessageWithLevel("SATB Filtering", Level.TRACE), + new LogMessageWithLevel("CM RefProcessor Roots", Level.TRACE), + new LogMessageWithLevel("Wait For Strong CLD", Level.TRACE), + new LogMessageWithLevel("Weak CLD Roots", Level.TRACE), // Redirty Cards new LogMessageWithLevel("Redirty Cards", Level.DEBUG), - new LogMessageWithLevel("Parallel Redirty", Level.DEBUG), - new LogMessageWithLevel("Redirtied Cards", Level.DEBUG), + new LogMessageWithLevel("Parallel Redirty", Level.TRACE), + new LogMessageWithLevel("Redirtied Cards", Level.TRACE), // Misc Top-level - new LogMessageWithLevel("Code Root Purge", Level.DEBUG), - new LogMessageWithLevel("String Dedup Fixup", Level.DEBUG), - new LogMessageWithLevel("Expand Heap After Collection", Level.DEBUG), + new LogMessageWithLevel("Code Roots Purge", Level.DEBUG), + new LogMessageWithLevel("String Dedup Fixup", Level.INFO), + new LogMessageWithLevel("Expand Heap After Collection", Level.INFO), // Free CSet - new LogMessageWithLevel("Young Free CSet", Level.TRACE), - new LogMessageWithLevel("Non-Young Free CSet", Level.TRACE), + new LogMessageWithLevel("Young Free Collection Set", Level.DEBUG), + new LogMessageWithLevel("Non-Young Free Collection Set", Level.DEBUG), // Humongous Eager Reclaim new LogMessageWithLevel("Humongous Reclaim", Level.DEBUG), new LogMessageWithLevel("Humongous Register", Level.DEBUG), // Preserve CM Referents new LogMessageWithLevel("Preserve CM Refs", Level.DEBUG), // Merge PSS - new LogMessageWithLevel("Merge Per-Thread State", Level.DEBUG), + new LogMessageWithLevel("Merge Per-Thread State", Level.INFO), }; void checkMessagesAtLevel(OutputAnalyzer output, LogMessageWithLevel messages[], Level level) throws Exception { for (LogMessageWithLevel l : messages) { - if (level.lessOrEqualTo(l.level)) { + if (level.lessThan(l.level)) { output.shouldNotContain(l.message); } else { - output.shouldContain(l.message); + output.shouldMatch("\\[" + l.level + ".*" + l.message); } } } From cd790e86a4d52a177cc7f3e99d5f9abe31107b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Tue, 1 Mar 2016 23:41:57 +0100 Subject: [PATCH 070/129] 8143228: Update module exports for Java Flight Recorder Reviewed-by: alanb, egahlin --- common/bin/compare_exceptions.sh.incl | 2 -- modules.xml | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/common/bin/compare_exceptions.sh.incl b/common/bin/compare_exceptions.sh.incl index fb68ede81d4..30ae49c6fc1 100644 --- a/common/bin/compare_exceptions.sh.incl +++ b/common/bin/compare_exceptions.sh.incl @@ -185,7 +185,6 @@ if [ "$OPENJDK_TARGET_OS" = "solaris" ] && [ "$OPENJDK_TARGET_CPU" = "x86_64" ]; ./lib/amd64/libjava.so ./lib/amd64/libjawt.so ./lib/amd64/libjdwp.so - ./lib/amd64/libjfr.so ./lib/amd64/libjpeg.so ./lib/amd64/libjsdt.so ./lib/amd64/libjsound.so @@ -321,7 +320,6 @@ if [ "$OPENJDK_TARGET_OS" = "solaris" ] && [ "$OPENJDK_TARGET_CPU" = "sparcv9" ] ./lib/sparcv9/libjava.so ./lib/sparcv9/libjawt.so ./lib/sparcv9/libjdwp.so - ./lib/sparcv9/libjfr.so ./lib/sparcv9/libjpeg.so ./lib/sparcv9/libjsdt.so ./lib/sparcv9/libjsound.so diff --git a/modules.xml b/modules.xml index 75a523a8cc8..7c3ab34f827 100644 --- a/modules.xml +++ b/modules.xml @@ -239,6 +239,7 @@ java.xml jdk.charsets jdk.management.resource + jdk.jfr jdk.net jdk.scripting.nashorn jdk.vm.ci @@ -249,6 +250,22 @@ java.management jdk.jvmstat + + jdk.internal.org.xml.sax + jdk.jfr + + + jdk.internal.org.xml.sax.helpers + jdk.jfr + + + jdk.internal.util.xml + jdk.jfr + + + jdk.internal.util.xml.impl + jdk.jfr + jdk.internal.org.objectweb.asm java.instrument @@ -314,6 +331,7 @@ jdk.vm.ci jdk.zipfs java.instrument + jdk.jfr sun.net @@ -914,6 +932,7 @@ sun.management.spi jdk.management jdk.management.cmm + jdk.management.jfr From 2d3d1ed1476a9af6f22d25754dbe04d6cd260dfe Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Mon, 29 Feb 2016 22:55:13 +0900 Subject: [PATCH 071/129] 8150723: HSDB toolbar icons are missing Reviewed-by: erikj, dsamersoff --- make/CompileJavaModules.gmk | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index 8593b3c784f..e8928e2130d 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -368,21 +368,7 @@ jdk.compiler_CLEAN_FILES := $(wildcard \ ################################################################################ jdk.hotspot.agent_ADD_JAVAC_FLAGS := $(DISABLE_WARNINGS),-overrides -jdk.hotspot.agent_COPY := .png sa.js .properties - -ifeq ($(MODULE), jdk.hotspot.agent) - ### Copy gif files - # Special handling to copy gif files in images/toolbarButtonGraphics \ - # -> classes/toolbarButtonGraphics. - # These can't be handled by COPY to SetupJavaCompilation since they chop off - # one directory level. - $(eval $(call SetupCopyFiles, COPY_SA_IMAGES, \ - SRC := $(HOTSPOT_TOPDIR)/src/jdk.hotspot.agent/share/classes/images, \ - DEST := $(JDK_OUTPUTDIR)/modules/$(MODULE), \ - FILES := $(wildcard $(HOTSPOT_TOPDIR)/src/jdk.hotspot.agent/share/classes/images/*/*/*.gif), \ - )) - jdk.hotspot.agent: $(COPY_SA_IMAGES) -endif +jdk.hotspot.agent_COPY := .gif .png sa.js .properties ################################################################################ From dbaa70361f45f8801b4854cce64cd64a1da29329 Mon Sep 17 00:00:00 2001 From: Derek White Date: Mon, 29 Feb 2016 11:32:12 -0500 Subject: [PATCH 072/129] 8140600: Convert unnecessarily malloc'd Monitors to value members Change a malloc'd monitor into an embedded monitor. Reviewed-by: tschatzl, kbarrett --- .../vm/gc/g1/g1YoungRemSetSamplingThread.cpp | 20 +++++++++---------- .../vm/gc/g1/g1YoungRemSetSamplingThread.hpp | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp index 8c8d216478c..060b7feb3ad 100644 --- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp +++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp @@ -57,21 +57,21 @@ void G1YoungRemSetSamplingThread::stop() { } } -G1YoungRemSetSamplingThread::G1YoungRemSetSamplingThread() : ConcurrentGCThread() { - _monitor = new Monitor(Mutex::nonleaf, - "G1YoungRemSetSamplingThread monitor", - true, - Monitor::_safepoint_check_never); - +G1YoungRemSetSamplingThread::G1YoungRemSetSamplingThread() : + ConcurrentGCThread(), + _monitor(Mutex::nonleaf, + "G1YoungRemSetSamplingThread monitor", + true, + Monitor::_safepoint_check_never) { set_name("G1 Young RemSet Sampling"); create_and_start(); } void G1YoungRemSetSamplingThread::sleep_before_next_cycle() { - MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); + MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag); if (!_should_terminate) { intx waitms = G1ConcRefinementServiceIntervalMillis; // 300, really should be? - _monitor->wait(Mutex::_no_safepoint_check_flag, waitms); + _monitor.wait(Mutex::_no_safepoint_check_flag, waitms); } } @@ -92,8 +92,8 @@ void G1YoungRemSetSamplingThread::run_service() { } void G1YoungRemSetSamplingThread::stop_service() { - MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); - _monitor->notify(); + MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag); + _monitor.notify(); } void G1YoungRemSetSamplingThread::sample_young_list_rs_lengths() { diff --git a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp index d5837e42aee..78e82e7e352 100644 --- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp +++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ // increase the young gen size to keep pause time length goal. class G1YoungRemSetSamplingThread: public ConcurrentGCThread { private: - Monitor* _monitor; + Monitor _monitor; void sample_young_list_rs_lengths(); From 5a873632f38264c0f5cd14898fedaa3177f12274 Mon Sep 17 00:00:00 2001 From: Max Ockner Date: Mon, 29 Feb 2016 16:58:09 -0500 Subject: [PATCH 073/129] 8149064: TraceProtectionDomainVerification has been converted to Unified Logging TraceProtectionDomainVerification has been converted to Unified Logging with tag protectiondomain. Reviewed-by: coleenp, iklam --- hotspot/src/share/vm/classfile/dictionary.cpp | 6 +- hotspot/src/share/vm/classfile/dictionary.hpp | 5 +- .../share/vm/classfile/systemDictionary.cpp | 24 +++---- hotspot/src/share/vm/logging/logTag.hpp | 1 + hotspot/src/share/vm/runtime/globals.hpp | 3 - .../ProtectionDomainVerificationTest.java | 62 +++++++++++++++++++ 6 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 hotspot/test/runtime/logging/ProtectionDomainVerificationTest.java diff --git a/hotspot/src/share/vm/classfile/dictionary.cpp b/hotspot/src/share/vm/classfile/dictionary.cpp index 6f70ef9b47e..61c3bad0f8e 100644 --- a/hotspot/src/share/vm/classfile/dictionary.cpp +++ b/hotspot/src/share/vm/classfile/dictionary.cpp @@ -135,8 +135,10 @@ void DictionaryEntry::add_protection_domain(Dictionary* dict, oop protection_dom // via a store to _pd_set. OrderAccess::release_store_ptr(&_pd_set, new_head); } - if (TraceProtectionDomainVerification && WizardMode) { - print(); + if (log_is_enabled(Trace, protectiondomain)) { + ResourceMark rm; + outputStream* log = LogHandle(protectiondomain)::trace_stream(); + print_count(log); } } diff --git a/hotspot/src/share/vm/classfile/dictionary.hpp b/hotspot/src/share/vm/classfile/dictionary.hpp index a77f33717f3..a873fdd3e47 100644 --- a/hotspot/src/share/vm/classfile/dictionary.hpp +++ b/hotspot/src/share/vm/classfile/dictionary.hpp @@ -29,6 +29,7 @@ #include "oops/instanceKlass.hpp" #include "oops/oop.hpp" #include "utilities/hashtable.hpp" +#include "utilities/ostream.hpp" class DictionaryEntry; class PSPromotionManager; @@ -323,14 +324,14 @@ class DictionaryEntry : public HashtableEntry { return (klass->name() == class_name && _loader_data == loader_data); } - void print() { + void print_count(outputStream *st) { int count = 0; for (ProtectionDomainEntry* current = _pd_set; current != NULL; current = current->_next) { count++; } - tty->print_cr("pd set = #%d", count); + st->print_cr("pd set count = #%d", count); } }; diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index 2a61613e910..549182e82cf 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -430,12 +430,15 @@ void SystemDictionary::validate_protection_domain(instanceKlassHandle klass, // Now we have to call back to java to check if the initating class has access JavaValue result(T_VOID); - if (TraceProtectionDomainVerification) { + if (log_is_enabled(Debug, protectiondomain)) { + ResourceMark rm; // Print out trace information - tty->print_cr("Checking package access"); - tty->print(" - class loader: "); class_loader()->print_value_on(tty); tty->cr(); - tty->print(" - protection domain: "); protection_domain()->print_value_on(tty); tty->cr(); - tty->print(" - loading: "); klass()->print_value_on(tty); tty->cr(); + outputStream* log = LogHandle(protectiondomain)::debug_stream(); + log->print_cr("Checking package access"); + log->print("class loader: "); class_loader()->print_value_on(log); + log->print(" protection domain: "); protection_domain()->print_value_on(log); + log->print(" loading: "); klass()->print_value_on(log); + log->cr(); } KlassHandle system_loader(THREAD, SystemDictionary::ClassLoader_klass()); @@ -448,13 +451,10 @@ void SystemDictionary::validate_protection_domain(instanceKlassHandle klass, protection_domain, THREAD); - if (TraceProtectionDomainVerification) { - if (HAS_PENDING_EXCEPTION) { - tty->print_cr(" -> DENIED !!!!!!!!!!!!!!!!!!!!!"); - } else { - tty->print_cr(" -> granted"); - } - tty->cr(); + if (HAS_PENDING_EXCEPTION) { + log_debug(protectiondomain)("DENIED !!!!!!!!!!!!!!!!!!!!!"); + } else { + log_debug(protectiondomain)("granted"); } if (HAS_PENDING_EXCEPTION) return; diff --git a/hotspot/src/share/vm/logging/logTag.hpp b/hotspot/src/share/vm/logging/logTag.hpp index 08a78c6b2ba..d292c8339e9 100644 --- a/hotspot/src/share/vm/logging/logTag.hpp +++ b/hotspot/src/share/vm/logging/logTag.hpp @@ -67,6 +67,7 @@ LOG_TAG(phases) \ LOG_TAG(plab) \ LOG_TAG(promotion) \ + LOG_TAG(protectiondomain) /* "Trace protection domain verification" */ \ LOG_TAG(ref) \ LOG_TAG(refine) \ LOG_TAG(region) \ diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 848bb5d2607..672b3c340ab 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1478,9 +1478,6 @@ public: develop(bool, TraceCompiledIC, false, \ "Trace changes of compiled IC") \ \ - develop(bool, TraceProtectionDomainVerification, false, \ - "Trace protection domain verification") \ - \ develop(bool, TraceClearedExceptions, false, \ "Print when an exception is forcibly cleared") \ \ diff --git a/hotspot/test/runtime/logging/ProtectionDomainVerificationTest.java b/hotspot/test/runtime/logging/ProtectionDomainVerificationTest.java new file mode 100644 index 00000000000..57790ad1248 --- /dev/null +++ b/hotspot/test/runtime/logging/ProtectionDomainVerificationTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test ProtectionDomainVerificationTest + * @bug 8149064 + * @library /testlibrary + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.Platform jdk.test.lib.ProcessTools + * @run driver ProtectionDomainVerificationTest + */ + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.Platform; +import jdk.test.lib.ProcessTools; + +public class ProtectionDomainVerificationTest { + + public static void main(String... args) throws Exception { + + // -Xlog:protectiondomain=trace + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:protectiondomain=trace", + "-Xmx64m", + Hello.class.getName()); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldContain("[protectiondomain] Checking package access"); + out.shouldContain("[protectiondomain] pd set count = #"); + + // -Xlog:protectiondomain=debug + pb = ProcessTools.createJavaProcessBuilder("-Xlog:protectiondomain=debug", + "-Xmx64m", + Hello.class.getName()); + out = new OutputAnalyzer(pb.start()); + out.shouldContain("[protectiondomain] Checking package access"); + out.shouldNotContain("pd set count = #"); + } + + public static class Hello { + public static void main(String[] args) { + System.out.print("Hello!"); + } + } +} From 12d9b13eee9abdb71a4e4817e25a2b3dd17b9f88 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Tue, 1 Mar 2016 09:42:19 +0100 Subject: [PATCH 074/129] 8150822: Fix typo in JDK-8150201 Reviewed-by: ihse, dholmes --- hotspot/make/solaris/makefiles/amd64.make | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/make/solaris/makefiles/amd64.make b/hotspot/make/solaris/makefiles/amd64.make index 7b1bdf3d8b3..3eb6dee9b92 100644 --- a/hotspot/make/solaris/makefiles/amd64.make +++ b/hotspot/make/solaris/makefiles/amd64.make @@ -39,7 +39,7 @@ OPT_CFLAGS/c1_LinearScan.o = -xO2 # of OPT_CFLAGS. Restore it here. ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) OPT_CFLAGS/generateOptoStub.o += -g0 -xs - OPT_CFLAGS/LinearScan.o += -g0 -xs + OPT_CFLAGS/c1_LinearScan.o += -g0 -xs endif else From a1b61d28278f48e2ad0b8072e4ce04ea41df5a25 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Tue, 1 Mar 2016 20:06:47 +0300 Subject: [PATCH 075/129] 8150933: System::arraycopy intrinsic doesn't mark mismatched loads Reviewed-by: kvn, shade --- hotspot/src/share/vm/opto/macroArrayCopy.cpp | 10 ++++++++-- hotspot/src/share/vm/opto/memnode.cpp | 9 ++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/hotspot/src/share/vm/opto/macroArrayCopy.cpp b/hotspot/src/share/vm/opto/macroArrayCopy.cpp index 82816b2462b..17065895bff 100644 --- a/hotspot/src/share/vm/opto/macroArrayCopy.cpp +++ b/hotspot/src/share/vm/opto/macroArrayCopy.cpp @@ -880,8 +880,14 @@ bool PhaseMacroExpand::generate_block_arraycopy(Node** ctrl, MergeMemNode** mem, Node* sptr = basic_plus_adr(src, src_off); Node* dptr = basic_plus_adr(dest, dest_off); uint alias_idx = C->get_alias_index(adr_type); - Node* sval = transform_later(LoadNode::make(_igvn, *ctrl, (*mem)->memory_at(alias_idx), sptr, adr_type, TypeInt::INT, T_INT, MemNode::unordered)); - Node* st = transform_later(StoreNode::make(_igvn, *ctrl, (*mem)->memory_at(alias_idx), dptr, adr_type, sval, T_INT, MemNode::unordered)); + bool is_mismatched = (basic_elem_type != T_INT); + Node* sval = transform_later( + LoadNode::make(_igvn, *ctrl, (*mem)->memory_at(alias_idx), sptr, adr_type, + TypeInt::INT, T_INT, MemNode::unordered, LoadNode::DependsOnlyOnTest, + false /*unaligned*/, is_mismatched)); + Node* st = transform_later( + StoreNode::make(_igvn, *ctrl, (*mem)->memory_at(alias_idx), dptr, adr_type, + sval, T_INT, MemNode::unordered)); (*mem)->set_memory_at(alias_idx, st); src_off += BytesPerInt; dest_off += BytesPerInt; diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 2d2b40d334e..51733c8fa65 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -1582,7 +1582,6 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls, return NULL; } -#ifdef ASSERT static bool is_mismatched_access(ciConstant con, BasicType loadbt) { BasicType conbt = con.basic_type(); switch (conbt) { @@ -1597,7 +1596,6 @@ static bool is_mismatched_access(ciConstant con, BasicType loadbt) { } return (conbt != loadbt); } -#endif // ASSERT // Try to constant-fold a stable array element. static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) { @@ -1608,10 +1606,11 @@ static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicTyp ciArray* aobj = ary->const_oop()->as_array(); ciConstant con = aobj->element_value_by_offset(off); if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) { - assert(!is_mismatched_access(con, loadbt), - "conbt=%s; loadbt=%s", type2name(con.basic_type()), type2name(loadbt)); + bool is_mismatched = is_mismatched_access(con, loadbt); + assert(!is_mismatched, "conbt=%s; loadbt=%s", type2name(con.basic_type()), type2name(loadbt)); const Type* con_type = Type::make_from_constant(con); - if (con_type != NULL) { + // Guard against erroneous constant folding. + if (!is_mismatched && con_type != NULL) { if (con_type->isa_aryptr()) { // Join with the array element type, in case it is also stable. int dim = ary->stable_dimension(); From a42172d65bad78299f588eacf476b5943ab6abdf Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Thu, 3 Mar 2016 09:12:05 -0800 Subject: [PATCH 076/129] 8149159: Clean up Unsafe Reviewed-by: jrose, kvn, stsmirno, chegar, aph, psandoz, redestad, twisti --- .../classes/jdk/internal/misc/Unsafe.java | 547 +++++++++++-- .../share/classes/sun/misc/Unsafe.java | 720 ++++++++++++------ .../jdk/internal/misc/Unsafe/CopyMemory.java | 667 ++++++++++++++++ .../jdk/internal/misc/Unsafe/CopySwap.java | 16 - 4 files changed, 1627 insertions(+), 323 deletions(-) create mode 100644 jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java index 8905977111b..db643df591b 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java @@ -40,6 +40,15 @@ import jdk.internal.HotSpotIntrinsicCandidate; * Although the class and all methods are public, use of this class is * limited because only trusted code can obtain instances of it. * + * Note: It is the resposibility of the caller to make sure + * arguments are checked before methods of this class are + * called. While some rudimentary checks are performed on the input, + * the checks are best effort and when performance is an overriding + * priority, as when methods of this class are optimized by the + * runtime compiler, some or all checks (if any) may be elided. Hence, + * the caller must not rely on the checks and corresponding + * exceptions! + * * @author John R. Rose * @see #getUnsafe */ @@ -358,6 +367,169 @@ public final class Unsafe { @HotSpotIntrinsicCandidate public native void putAddress(long address, long x); + + + /// helper methods for validating various types of objects/values + + /** + * Create an exception reflecting that some of the input was invalid + * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @return an exception object + */ + private RuntimeException invalidInput() { + return new IllegalArgumentException(); + } + + /** + * Check if a value is 32-bit clean (32 MSB are all zero) + * + * @param value the 64-bit value to check + * + * @return true if the value is 32-bit clean + */ + private boolean is32BitClean(long value) { + return value >>> 32 == 0; + } + + /** + * Check the validity of a size (the equivalent of a size_t) + * + * @throws RuntimeException if the size is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkSize(long size) { + if (ADDRESS_SIZE == 4) { + // Note: this will also check for negative sizes + if (!is32BitClean(size)) { + throw invalidInput(); + } + } else if (size < 0) { + throw invalidInput(); + } + } + + /** + * Check the validity of a native address (the equivalent of void*) + * + * @throws RuntimeException if the address is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkNativeAddress(long address) { + if (ADDRESS_SIZE == 4) { + // Accept both zero and sign extended pointers. A valid + // pointer will, after the +1 below, either have produced + // the value 0x0 or 0x1. Masking off the low bit allows + // for testing against 0. + if ((((address >> 32) + 1) & ~1) != 0) { + throw invalidInput(); + } + } + } + + /** + * Check the validity of an offset, relative to a base object + * + * @param o the base object + * @param offset the offset to check + * + * @throws RuntimeException if the size is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkOffset(Object o, long offset) { + if (ADDRESS_SIZE == 4) { + // Note: this will also check for negative offsets + if (!is32BitClean(offset)) { + throw invalidInput(); + } + } else if (offset < 0) { + throw invalidInput(); + } + } + + /** + * Check the validity of a double-register pointer + * + * Note: This code deliberately does *not* check for NPE for (at + * least) three reasons: + * + * 1) NPE is not just NULL/0 - there is a range of values all + * resulting in an NPE, which is not trivial to check for + * + * 2) It is the responsibility of the callers of Unsafe methods + * to verify the input, so throwing an exception here is not really + * useful - passing in a NULL pointer is a critical error and the + * must not expect an exception to be thrown anyway. + * + * 3) the actual operations will detect NULL pointers anyway by + * means of traps and signals (like SIGSEGV). + * + * @param o Java heap object, or null + * @param offset indication of where the variable resides in a Java heap + * object, if any, else a memory address locating the variable + * statically + * + * @throws RuntimeException if the pointer is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkPointer(Object o, long offset) { + if (o == null) { + checkNativeAddress(offset); + } else { + checkOffset(o, offset); + } + } + + /** + * Check if a type is a primitive array type + * + * @param c the type to check + * + * @return true if the type is a primitive array type + */ + private void checkPrimitiveArray(Class c) { + Class componentType = c.getComponentType(); + if (componentType == null || !componentType.isPrimitive()) { + throw invalidInput(); + } + } + + /** + * Check that a pointer is a valid primitive array type pointer + * + * Note: pointers off-heap are considered to be primitive arrays + * + * @throws RuntimeException if the pointer is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void checkPrimitivePointer(Object o, long offset) { + checkPointer(o, offset); + + if (o != null) { + // If on heap, it it must be a primitive array + checkPrimitiveArray(o.getClass()); + } + } + + /// wrappers for malloc, realloc, free: /** @@ -367,7 +539,16 @@ public final class Unsafe { * aligned for all value types. Dispose of this memory by calling {@link * #freeMemory}, or resize it with {@link #reallocateMemory}. * - * @throws IllegalArgumentException if the size is negative or too large + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if the size is negative or too large * for the native size_t type * * @throws OutOfMemoryError if the allocation is refused by the system @@ -375,7 +556,32 @@ public final class Unsafe { * @see #getByte(long) * @see #putByte(long, byte) */ - public native long allocateMemory(long bytes); + public long allocateMemory(long bytes) { + allocateMemoryChecks(bytes); + + if (bytes == 0) { + return 0; + } + + long p = allocateMemory0(bytes); + if (p == 0) { + throw new OutOfMemoryError(); + } + + return p; + } + + /** + * Validate the arguments to allocateMemory + * + * @throws RuntimeException if the arguments are invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void allocateMemoryChecks(long bytes) { + checkSize(bytes); + } /** * Resizes a new block of native memory, to the given size in bytes. The @@ -387,14 +593,50 @@ public final class Unsafe { * #reallocateMemory}. The address passed to this method may be null, in * which case an allocation will be performed. * - * @throws IllegalArgumentException if the size is negative or too large + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if the size is negative or too large * for the native size_t type * * @throws OutOfMemoryError if the allocation is refused by the system * * @see #allocateMemory */ - public native long reallocateMemory(long address, long bytes); + public long reallocateMemory(long address, long bytes) { + reallocateMemoryChecks(address, bytes); + + if (bytes == 0) { + freeMemory(address); + return 0; + } + + long p = (address == 0) ? allocateMemory0(bytes) : reallocateMemory0(address, bytes); + if (p == 0) { + throw new OutOfMemoryError(); + } + + return p; + } + + /** + * Validate the arguments to reallocateMemory + * + * @throws RuntimeException if the arguments are invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void reallocateMemoryChecks(long address, long bytes) { + checkPointer(null, address); + checkSize(bytes); + } /** * Sets all bytes in a given block of memory to a fixed value @@ -411,9 +653,28 @@ public final class Unsafe { * If the effective address and length are (resp.) even modulo 4 or 2, * the stores take place in units of 'int' or 'short'. * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * * @since 1.7 */ - public native void setMemory(Object o, long offset, long bytes, byte value); + public void setMemory(Object o, long offset, long bytes, byte value) { + setMemoryChecks(o, offset, bytes, value); + + if (bytes == 0) { + return; + } + + setMemory0(o, offset, bytes, value); + } /** * Sets all bytes in a given block of memory to a fixed value @@ -426,6 +687,19 @@ public final class Unsafe { setMemory(null, address, bytes, value); } + /** + * Validate the arguments to setMemory + * + * @throws RuntimeException if the arguments are invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void setMemoryChecks(Object o, long offset, long bytes, byte value) { + checkPrimitivePointer(o, offset); + checkSize(bytes); + } + /** * Sets all bytes in a given block of memory to a copy of another * block. @@ -441,12 +715,31 @@ public final class Unsafe { * If the effective addresses and length are (resp.) even modulo 4 or 2, * the transfer takes place in units of 'int' or 'short'. * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * * @since 1.7 */ - @HotSpotIntrinsicCandidate - public native void copyMemory(Object srcBase, long srcOffset, - Object destBase, long destOffset, - long bytes); + public void copyMemory(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes) { + copyMemoryChecks(srcBase, srcOffset, destBase, destOffset, bytes); + + if (bytes == 0) { + return; + } + + copyMemory0(srcBase, srcOffset, destBase, destOffset, bytes); + } + /** * Sets all bytes in a given block of memory to a copy of another * block. This provides a single-register addressing mode, @@ -458,15 +751,22 @@ public final class Unsafe { copyMemory(null, srcAddress, null, destAddress, bytes); } - private boolean isPrimitiveArray(Class c) { - Class componentType = c.getComponentType(); - return componentType != null && componentType.isPrimitive(); + /** + * Validate the arguments to copyMemory + * + * @throws RuntimeException if any of the arguments is invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void copyMemoryChecks(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes) { + checkSize(bytes); + checkPrimitivePointer(srcBase, srcOffset); + checkPrimitivePointer(destBase, destOffset); } - private native void copySwapMemory0(Object srcBase, long srcOffset, - Object destBase, long destOffset, - long bytes, long elemSize); - /** * Copies all elements from one block of memory to another block, * *unconditionally* byte swapping the elements on the fly. @@ -476,39 +776,23 @@ public final class Unsafe { * as discussed in {@link #getInt(Object,long)}. When the object reference is null, * the offset supplies an absolute base address. * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * * @since 9 */ public void copySwapMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes, long elemSize) { - if (bytes < 0) { - throw new IllegalArgumentException(); - } - if (elemSize != 2 && elemSize != 4 && elemSize != 8) { - throw new IllegalArgumentException(); - } - if (bytes % elemSize != 0) { - throw new IllegalArgumentException(); - } - if ((srcBase == null && srcOffset == 0) || - (destBase == null && destOffset == 0)) { - throw new NullPointerException(); - } - - // Must be off-heap, or primitive heap arrays - if (srcBase != null && (srcOffset < 0 || !isPrimitiveArray(srcBase.getClass()))) { - throw new IllegalArgumentException(); - } - if (destBase != null && (destOffset < 0 || !isPrimitiveArray(destBase.getClass()))) { - throw new IllegalArgumentException(); - } - - // Sanity check size and offsets on 32-bit platforms. Most - // significant 32 bits must be zero. - if (ADDRESS_SIZE == 4 && - (bytes >>> 32 != 0 || srcOffset >>> 32 != 0 || destOffset >>> 32 != 0)) { - throw new IllegalArgumentException(); - } + copySwapMemoryChecks(srcBase, srcOffset, destBase, destOffset, bytes, elemSize); if (bytes == 0) { return; @@ -517,6 +801,22 @@ public final class Unsafe { copySwapMemory0(srcBase, srcOffset, destBase, destOffset, bytes, elemSize); } + private void copySwapMemoryChecks(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes, long elemSize) { + checkSize(bytes); + + if (elemSize != 2 && elemSize != 4 && elemSize != 8) { + throw invalidInput(); + } + if (bytes % elemSize != 0) { + throw invalidInput(); + } + + checkPrimitivePointer(srcBase, srcOffset); + checkPrimitivePointer(destBase, destOffset); + } + /** * Copies all elements from one block of memory to another block, byte swapping the * elements on the fly. @@ -535,9 +835,40 @@ public final class Unsafe { * #allocateMemory} or {@link #reallocateMemory}. The address passed to * this method may be null, in which case no action is taken. * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * * @see #allocateMemory */ - public native void freeMemory(long address); + public void freeMemory(long address) { + freeMemoryChecks(address); + + if (address == 0) { + return; + } + + freeMemory0(address); + } + + /** + * Validate the arguments to freeMemory + * + * @throws RuntimeException if the arguments are invalid + * (Note: after optimization, invalid inputs may + * go undetected, which will lead to unpredictable + * behavior) + */ + private void freeMemoryChecks(long address) { + checkPointer(null, address); + } /// random queries @@ -546,7 +877,7 @@ public final class Unsafe { * {@link #staticFieldOffset}, {@link #objectFieldOffset}, * or {@link #arrayBaseOffset}. */ - public static final int INVALID_FIELD_OFFSET = -1; + public static final int INVALID_FIELD_OFFSET = -1; /** * Reports the location of a given field in the storage allocation of its @@ -566,7 +897,13 @@ public final class Unsafe { * must preserve all bits of static field offsets. * @see #getInt(Object, long) */ - public native long objectFieldOffset(Field f); + public long objectFieldOffset(Field f) { + if (f == null) { + throw new NullPointerException(); + } + + return objectFieldOffset0(f); + } /** * Reports the location of a given static field, in conjunction with {@link @@ -585,7 +922,13 @@ public final class Unsafe { * this method reports its result as a long value. * @see #getInt(Object, long) */ - public native long staticFieldOffset(Field f); + public long staticFieldOffset(Field f) { + if (f == null) { + throw new NullPointerException(); + } + + return staticFieldOffset0(f); + } /** * Reports the location of a given static field, in conjunction with {@link @@ -597,7 +940,13 @@ public final class Unsafe { * not be used in any way except as argument to the get and put routines in * this class. */ - public native Object staticFieldBase(Field f); + public Object staticFieldBase(Field f) { + if (f == null) { + throw new NullPointerException(); + } + + return staticFieldBase0(f); + } /** * Detects if the given class may need to be initialized. This is often @@ -605,14 +954,26 @@ public final class Unsafe { * class. * @return false only if a call to {@code ensureClassInitialized} would have no effect */ - public native boolean shouldBeInitialized(Class c); + public boolean shouldBeInitialized(Class c) { + if (c == null) { + throw new NullPointerException(); + } + + return shouldBeInitialized0(c); + } /** * Ensures the given class has been initialized. This is often * needed in conjunction with obtaining the static field base of a * class. */ - public native void ensureClassInitialized(Class c); + public void ensureClassInitialized(Class c) { + if (c == null) { + throw new NullPointerException(); + } + + ensureClassInitialized0(c); + } /** * Reports the offset of the first element in the storage allocation of a @@ -624,7 +985,14 @@ public final class Unsafe { * @see #getInt(Object, long) * @see #putInt(Object, long, int) */ - public native int arrayBaseOffset(Class arrayClass); + public int arrayBaseOffset(Class arrayClass) { + if (arrayClass == null) { + throw new NullPointerException(); + } + + return arrayBaseOffset0(arrayClass); + } + /** The value of {@code arrayBaseOffset(boolean[].class)} */ public static final int ARRAY_BOOLEAN_BASE_OFFSET @@ -673,7 +1041,14 @@ public final class Unsafe { * @see #getInt(Object, long) * @see #putInt(Object, long, int) */ - public native int arrayIndexScale(Class arrayClass); + public int arrayIndexScale(Class arrayClass) { + if (arrayClass == null) { + throw new NullPointerException(); + } + + return arrayIndexScale0(arrayClass); + } + /** The value of {@code arrayIndexScale(boolean[].class)} */ public static final int ARRAY_BOOLEAN_INDEX_SCALE @@ -717,10 +1092,12 @@ public final class Unsafe { * other primitive types (as stored in native memory blocks) is determined * fully by their information content. */ - public native int addressSize(); + public int addressSize() { + return ADDRESS_SIZE; + } /** The value of {@code addressSize()} */ - public static final int ADDRESS_SIZE = theUnsafe.addressSize(); + public static final int ADDRESS_SIZE = theUnsafe.addressSize0(); /** * Reports the size in bytes of a native memory page (whatever that is). @@ -735,9 +1112,22 @@ public final class Unsafe { * Tells the VM to define a class, without security checks. By default, the * class loader and protection domain come from the caller's class. */ - public native Class defineClass(String name, byte[] b, int off, int len, - ClassLoader loader, - ProtectionDomain protectionDomain); + public Class defineClass(String name, byte[] b, int off, int len, + ClassLoader loader, + ProtectionDomain protectionDomain) { + if (b == null) { + throw new NullPointerException(); + } + if (len < 0) { + throw new ArrayIndexOutOfBoundsException(); + } + + return defineClass0(name, b, off, len, loader, protectionDomain); + } + + public native Class defineClass0(String name, byte[] b, int off, int len, + ClassLoader loader, + ProtectionDomain protectionDomain); /** * Defines a class but does not make it known to the class loader or system dictionary. @@ -755,7 +1145,13 @@ public final class Unsafe { * @param data bytes of a class file * @param cpPatches where non-null entries exist, they replace corresponding CP entries in data */ - public native Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches); + public Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches) { + if (hostClass == null || data == null) { + throw new NullPointerException(); + } + + return defineAnonymousClass0(hostClass, data, cpPatches); + } /** * Allocates an instance but does not run any constructor. @@ -1290,7 +1686,13 @@ public final class Unsafe { * @return the number of samples actually retrieved; or -1 * if the load average is unobtainable. */ - public native int getLoadAverage(double[] loadavg, int nelems); + public int getLoadAverage(double[] loadavg, int nelems) { + if (nelems < 0 || nelems > 3 || nelems > loadavg.length) { + throw new ArrayIndexOutOfBoundsException(); + } + + return getLoadAverage0(loadavg, nelems); + } // The following contain CAS-based Java implementations used on // platforms not supporting native instructions @@ -1718,9 +2120,6 @@ public final class Unsafe { } // JVM interface methods - private native boolean unalignedAccess0(); - private native boolean isBigEndian0(); - // BE is true iff the native endianness of this platform is big. private static final boolean BE = theUnsafe.isBigEndian0(); @@ -1820,4 +2219,26 @@ public final class Unsafe { private static short convEndian(boolean big, short n) { return big == BE ? n : Short.reverseBytes(n) ; } private static int convEndian(boolean big, int n) { return big == BE ? n : Integer.reverseBytes(n) ; } private static long convEndian(boolean big, long n) { return big == BE ? n : Long.reverseBytes(n) ; } + + + + private native long allocateMemory0(long bytes); + private native long reallocateMemory0(long address, long bytes); + private native void freeMemory0(long address); + private native void setMemory0(Object o, long offset, long bytes, byte value); + @HotSpotIntrinsicCandidate + private native void copyMemory0(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes); + private native void copySwapMemory0(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes, long elemSize); + private native long objectFieldOffset0(Field f); + private native long staticFieldOffset0(Field f); + private native Object staticFieldBase0(Field f); + private native boolean shouldBeInitialized0(Class c); + private native void ensureClassInitialized0(Class c); + private native int arrayBaseOffset0(Class arrayClass); + private native int arrayIndexScale0(Class arrayClass); + private native int addressSize0(); + private native Class defineAnonymousClass0(Class hostClass, byte[] data, Object[] cpPatches); + private native int getLoadAverage0(double[] loadavg, int nelems); + private native boolean unalignedAccess0(); + private native boolean isBigEndian0(); } diff --git a/jdk/src/java.base/share/classes/sun/misc/Unsafe.java b/jdk/src/java.base/share/classes/sun/misc/Unsafe.java index 77d2c8afa71..15ba929c32f 100644 --- a/jdk/src/java.base/share/classes/sun/misc/Unsafe.java +++ b/jdk/src/java.base/share/classes/sun/misc/Unsafe.java @@ -25,7 +25,7 @@ package sun.misc; -import jdk.internal.HotSpotIntrinsicCandidate; +import jdk.internal.vm.annotation.ForceInline; import jdk.internal.misc.VM; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; @@ -39,21 +39,29 @@ import java.security.ProtectionDomain; * Although the class and all methods are public, use of this class is * limited because only trusted code can obtain instances of it. * + * Note: It is the resposibility of the caller to make sure + * arguments are checked before methods of this class are + * called. While some rudimentary checks are performed on the input, + * the checks are best effort and when performance is an overriding + * priority, as when methods of this class are optimized by the + * runtime compiler, some or all checks (if any) may be elided. Hence, + * the caller must not rely on the checks and corresponding + * exceptions! + * * @author John R. Rose * @see #getUnsafe */ public final class Unsafe { - private static native void registerNatives(); static { - registerNatives(); sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe"); } private Unsafe() {} private static final Unsafe theUnsafe = new Unsafe(); + private static final jdk.internal.misc.Unsafe theInternalUnsafe = jdk.internal.misc.Unsafe.getUnsafe(); /** * Provides the caller with the capability of performing unsafe @@ -150,8 +158,10 @@ public final class Unsafe { * @throws RuntimeException No defined exceptions are thrown, not even * {@link NullPointerException} */ - @HotSpotIntrinsicCandidate - public native int getInt(Object o, long offset); + @ForceInline + public int getInt(Object o, long offset) { + return theInternalUnsafe.getInt(o, offset); + } /** * Stores a value into a given Java variable. @@ -173,15 +183,19 @@ public final class Unsafe { * @throws RuntimeException No defined exceptions are thrown, not even * {@link NullPointerException} */ - @HotSpotIntrinsicCandidate - public native void putInt(Object o, long offset, int x); + @ForceInline + public void putInt(Object o, long offset, int x) { + theInternalUnsafe.putInt(o, offset, x); + } /** * Fetches a reference value from a given Java variable. * @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native Object getObject(Object o, long offset); + @ForceInline + public Object getObject(Object o, long offset) { + return theInternalUnsafe.getObject(o, offset); + } /** * Stores a reference value into a given Java variable. @@ -193,51 +207,95 @@ public final class Unsafe { * are updated. * @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putObject(Object o, long offset, Object x); + @ForceInline + public void putObject(Object o, long offset, Object x) { + theInternalUnsafe.putObject(o, offset, x); + } /** @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native boolean getBoolean(Object o, long offset); + @ForceInline + public boolean getBoolean(Object o, long offset) { + return theInternalUnsafe.getBoolean(o, offset); + } + /** @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putBoolean(Object o, long offset, boolean x); + @ForceInline + public void putBoolean(Object o, long offset, boolean x) { + theInternalUnsafe.putBoolean(o, offset, x); + } + /** @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native byte getByte(Object o, long offset); + @ForceInline + public byte getByte(Object o, long offset) { + return theInternalUnsafe.getByte(o, offset); + } + /** @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putByte(Object o, long offset, byte x); + @ForceInline + public void putByte(Object o, long offset, byte x) { + theInternalUnsafe.putByte(o, offset, x); + } + /** @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native short getShort(Object o, long offset); + @ForceInline + public short getShort(Object o, long offset) { + return theInternalUnsafe.getShort(o, offset); + } + /** @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putShort(Object o, long offset, short x); + @ForceInline + public void putShort(Object o, long offset, short x) { + theInternalUnsafe.putShort(o, offset, x); + } + /** @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native char getChar(Object o, long offset); + @ForceInline + public char getChar(Object o, long offset) { + return theInternalUnsafe.getChar(o, offset); + } + /** @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putChar(Object o, long offset, char x); + @ForceInline + public void putChar(Object o, long offset, char x) { + theInternalUnsafe.putChar(o, offset, x); + } + /** @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native long getLong(Object o, long offset); + @ForceInline + public long getLong(Object o, long offset) { + return theInternalUnsafe.getLong(o, offset); + } + /** @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putLong(Object o, long offset, long x); + @ForceInline + public void putLong(Object o, long offset, long x) { + theInternalUnsafe.putLong(o, offset, x); + } + /** @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native float getFloat(Object o, long offset); + @ForceInline + public float getFloat(Object o, long offset) { + return theInternalUnsafe.getFloat(o, offset); + } + /** @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putFloat(Object o, long offset, float x); + @ForceInline + public void putFloat(Object o, long offset, float x) { + theInternalUnsafe.putFloat(o, offset, x); + } + /** @see #getInt(Object, long) */ - @HotSpotIntrinsicCandidate - public native double getDouble(Object o, long offset); + @ForceInline + public double getDouble(Object o, long offset) { + return theInternalUnsafe.getDouble(o, offset); + } + /** @see #putInt(Object, long, int) */ - @HotSpotIntrinsicCandidate - public native void putDouble(Object o, long offset, double x); + @ForceInline + public void putDouble(Object o, long offset, double x) { + theInternalUnsafe.putDouble(o, offset, x); + } + // These read VM internal data. @@ -248,7 +306,10 @@ public final class Unsafe { * @param address a memory address locating the variable * @return the value fetched from the indicated native variable */ - public native Object getUncompressedObject(long address); + @ForceInline + public Object getUncompressedObject(long address) { + return theInternalUnsafe.getUncompressedObject(address); + } /** * Fetches the {@link java.lang.Class} Java mirror for the given native @@ -257,7 +318,10 @@ public final class Unsafe { * @param metaspaceKlass a native metaspace {@code Klass} pointer * @return the {@link java.lang.Class} Java mirror */ - public native Class getJavaMirror(long metaspaceKlass); + @ForceInline + public Class getJavaMirror(long metaspaceKlass) { + return theInternalUnsafe.getJavaMirror(metaspaceKlass); + } /** * Fetches a native metaspace {@code Klass} pointer for the given Java @@ -266,7 +330,10 @@ public final class Unsafe { * @param o Java heap object for which to fetch the class pointer * @return a native metaspace {@code Klass} pointer */ - public native long getKlassPointer(Object o); + @ForceInline + public long getKlassPointer(Object o) { + return theInternalUnsafe.getKlassPointer(o); + } // These work on values in the C heap. @@ -277,8 +344,10 @@ public final class Unsafe { * * @see #allocateMemory */ - @HotSpotIntrinsicCandidate - public native byte getByte(long address); + @ForceInline + public byte getByte(long address) { + return theInternalUnsafe.getByte(address); + } /** * Stores a value into a given memory address. If the address is zero, or @@ -287,45 +356,83 @@ public final class Unsafe { * * @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native void putByte(long address, byte x); + @ForceInline + public void putByte(long address, byte x) { + theInternalUnsafe.putByte(address, x); + } /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native short getShort(long address); + @ForceInline + public short getShort(long address) { + return theInternalUnsafe.getShort(address); + } + /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putShort(long address, short x); + @ForceInline + public void putShort(long address, short x) { + theInternalUnsafe.putShort(address, x); + } + /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native char getChar(long address); + @ForceInline + public char getChar(long address) { + return theInternalUnsafe.getChar(address); + } + /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putChar(long address, char x); + @ForceInline + public void putChar(long address, char x) { + theInternalUnsafe.putChar(address, x); + } + /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native int getInt(long address); + @ForceInline + public int getInt(long address) { + return theInternalUnsafe.getInt(address); + } + /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putInt(long address, int x); + @ForceInline + public void putInt(long address, int x) { + theInternalUnsafe.putInt(address, x); + } + /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native long getLong(long address); + @ForceInline + public long getLong(long address) { + return theInternalUnsafe.getLong(address); + } + /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putLong(long address, long x); + @ForceInline + public void putLong(long address, long x) { + theInternalUnsafe.putLong(address, x); + } + /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native float getFloat(long address); + @ForceInline + public float getFloat(long address) { + return theInternalUnsafe.getFloat(address); + } + /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putFloat(long address, float x); + @ForceInline + public void putFloat(long address, float x) { + theInternalUnsafe.putFloat(address, x); + } + /** @see #getByte(long) */ - @HotSpotIntrinsicCandidate - public native double getDouble(long address); + @ForceInline + public double getDouble(long address) { + return theInternalUnsafe.getDouble(address); + } + /** @see #putByte(long, byte) */ - @HotSpotIntrinsicCandidate - public native void putDouble(long address, double x); + @ForceInline + public void putDouble(long address, double x) { + theInternalUnsafe.putDouble(address, x); + } + /** * Fetches a native pointer from a given memory address. If the address is @@ -341,8 +448,10 @@ public final class Unsafe { * * @see #allocateMemory */ - @HotSpotIntrinsicCandidate - public native long getAddress(long address); + @ForceInline + public long getAddress(long address) { + return theInternalUnsafe.getAddress(address); + } /** * Stores a native pointer into a given memory address. If the address is @@ -354,8 +463,11 @@ public final class Unsafe { * * @see #getAddress(long) */ - @HotSpotIntrinsicCandidate - public native void putAddress(long address, long x); + @ForceInline + public void putAddress(long address, long x) { + theInternalUnsafe.putAddress(address, x); + } + /// wrappers for malloc, realloc, free: @@ -366,7 +478,16 @@ public final class Unsafe { * aligned for all value types. Dispose of this memory by calling {@link * #freeMemory}, or resize it with {@link #reallocateMemory}. * - * @throws IllegalArgumentException if the size is negative or too large + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if the size is negative or too large * for the native size_t type * * @throws OutOfMemoryError if the allocation is refused by the system @@ -374,7 +495,10 @@ public final class Unsafe { * @see #getByte(long) * @see #putByte(long, byte) */ - public native long allocateMemory(long bytes); + @ForceInline + public long allocateMemory(long bytes) { + return theInternalUnsafe.allocateMemory(bytes); + } /** * Resizes a new block of native memory, to the given size in bytes. The @@ -386,14 +510,26 @@ public final class Unsafe { * #reallocateMemory}. The address passed to this method may be null, in * which case an allocation will be performed. * - * @throws IllegalArgumentException if the size is negative or too large + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if the size is negative or too large * for the native size_t type * * @throws OutOfMemoryError if the allocation is refused by the system * * @see #allocateMemory */ - public native long reallocateMemory(long address, long bytes); + @ForceInline + public long reallocateMemory(long address, long bytes) { + return theInternalUnsafe.reallocateMemory(address, bytes); + } /** * Sets all bytes in a given block of memory to a fixed value @@ -410,9 +546,23 @@ public final class Unsafe { * If the effective address and length are (resp.) even modulo 4 or 2, * the stores take place in units of 'int' or 'short'. * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * * @since 1.7 */ - public native void setMemory(Object o, long offset, long bytes, byte value); + @ForceInline + public void setMemory(Object o, long offset, long bytes, byte value) { + theInternalUnsafe.setMemory(o, offset, bytes, value); + } /** * Sets all bytes in a given block of memory to a fixed value @@ -421,8 +571,9 @@ public final class Unsafe { * *

Equivalent to {@code setMemory(null, address, bytes, value)}. */ + @ForceInline public void setMemory(long address, long bytes, byte value) { - setMemory(null, address, bytes, value); + theInternalUnsafe.setMemory(address, bytes, value); } /** @@ -440,12 +591,26 @@ public final class Unsafe { * If the effective addresses and length are (resp.) even modulo 4 or 2, * the transfer takes place in units of 'int' or 'short'. * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * * @since 1.7 */ - @HotSpotIntrinsicCandidate - public native void copyMemory(Object srcBase, long srcOffset, - Object destBase, long destOffset, - long bytes); + @ForceInline + public void copyMemory(Object srcBase, long srcOffset, + Object destBase, long destOffset, + long bytes) { + theInternalUnsafe.copyMemory(srcBase, srcOffset, destBase, destOffset, bytes); + } + /** * Sets all bytes in a given block of memory to a copy of another * block. This provides a single-register addressing mode, @@ -453,8 +618,9 @@ public final class Unsafe { * * Equivalent to {@code copyMemory(null, srcAddress, null, destAddress, bytes)}. */ + @ForceInline public void copyMemory(long srcAddress, long destAddress, long bytes) { - copyMemory(null, srcAddress, null, destAddress, bytes); + theInternalUnsafe.copyMemory(srcAddress, destAddress, bytes); } /** @@ -462,9 +628,23 @@ public final class Unsafe { * #allocateMemory} or {@link #reallocateMemory}. The address passed to * this method may be null, in which case no action is taken. * + * Note: It is the resposibility of the caller to make + * sure arguments are checked before the methods are called. While + * some rudimentary checks are performed on the input, the checks + * are best effort and when performance is an overriding priority, + * as when methods of this class are optimized by the runtime + * compiler, some or all checks (if any) may be elided. Hence, the + * caller must not rely on the checks and corresponding + * exceptions! + * + * @throws RuntimeException if any of the arguments is invalid + * * @see #allocateMemory */ - public native void freeMemory(long address); + @ForceInline + public void freeMemory(long address) { + theInternalUnsafe.freeMemory(address); + } /// random queries @@ -473,7 +653,7 @@ public final class Unsafe { * {@link #staticFieldOffset}, {@link #objectFieldOffset}, * or {@link #arrayBaseOffset}. */ - public static final int INVALID_FIELD_OFFSET = -1; + public static final int INVALID_FIELD_OFFSET = jdk.internal.misc.Unsafe.INVALID_FIELD_OFFSET; /** * Reports the location of a given field in the storage allocation of its @@ -493,7 +673,10 @@ public final class Unsafe { * must preserve all bits of static field offsets. * @see #getInt(Object, long) */ - public native long objectFieldOffset(Field f); + @ForceInline + public long objectFieldOffset(Field f) { + return theInternalUnsafe.objectFieldOffset(f); + } /** * Reports the location of a given static field, in conjunction with {@link @@ -512,7 +695,10 @@ public final class Unsafe { * this method reports its result as a long value. * @see #getInt(Object, long) */ - public native long staticFieldOffset(Field f); + @ForceInline + public long staticFieldOffset(Field f) { + return theInternalUnsafe.staticFieldOffset(f); + } /** * Reports the location of a given static field, in conjunction with {@link @@ -524,7 +710,10 @@ public final class Unsafe { * not be used in any way except as argument to the get and put routines in * this class. */ - public native Object staticFieldBase(Field f); + @ForceInline + public Object staticFieldBase(Field f) { + return theInternalUnsafe.staticFieldBase(f); + } /** * Detects if the given class may need to be initialized. This is often @@ -532,14 +721,20 @@ public final class Unsafe { * class. * @return false only if a call to {@code ensureClassInitialized} would have no effect */ - public native boolean shouldBeInitialized(Class c); + @ForceInline + public boolean shouldBeInitialized(Class c) { + return theInternalUnsafe.shouldBeInitialized(c); + } /** * Ensures the given class has been initialized. This is often * needed in conjunction with obtaining the static field base of a * class. */ - public native void ensureClassInitialized(Class c); + @ForceInline + public void ensureClassInitialized(Class c) { + theInternalUnsafe.ensureClassInitialized(c); + } /** * Reports the offset of the first element in the storage allocation of a @@ -551,43 +746,37 @@ public final class Unsafe { * @see #getInt(Object, long) * @see #putInt(Object, long, int) */ - public native int arrayBaseOffset(Class arrayClass); + @ForceInline + public int arrayBaseOffset(Class arrayClass) { + return theInternalUnsafe.arrayBaseOffset(arrayClass); + } /** The value of {@code arrayBaseOffset(boolean[].class)} */ - public static final int ARRAY_BOOLEAN_BASE_OFFSET - = theUnsafe.arrayBaseOffset(boolean[].class); + public static final int ARRAY_BOOLEAN_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_BOOLEAN_BASE_OFFSET; /** The value of {@code arrayBaseOffset(byte[].class)} */ - public static final int ARRAY_BYTE_BASE_OFFSET - = theUnsafe.arrayBaseOffset(byte[].class); + public static final int ARRAY_BYTE_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET; /** The value of {@code arrayBaseOffset(short[].class)} */ - public static final int ARRAY_SHORT_BASE_OFFSET - = theUnsafe.arrayBaseOffset(short[].class); + public static final int ARRAY_SHORT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_SHORT_BASE_OFFSET; /** The value of {@code arrayBaseOffset(char[].class)} */ - public static final int ARRAY_CHAR_BASE_OFFSET - = theUnsafe.arrayBaseOffset(char[].class); + public static final int ARRAY_CHAR_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_CHAR_BASE_OFFSET; /** The value of {@code arrayBaseOffset(int[].class)} */ - public static final int ARRAY_INT_BASE_OFFSET - = theUnsafe.arrayBaseOffset(int[].class); + public static final int ARRAY_INT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_INT_BASE_OFFSET; /** The value of {@code arrayBaseOffset(long[].class)} */ - public static final int ARRAY_LONG_BASE_OFFSET - = theUnsafe.arrayBaseOffset(long[].class); + public static final int ARRAY_LONG_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_LONG_BASE_OFFSET; /** The value of {@code arrayBaseOffset(float[].class)} */ - public static final int ARRAY_FLOAT_BASE_OFFSET - = theUnsafe.arrayBaseOffset(float[].class); + public static final int ARRAY_FLOAT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_FLOAT_BASE_OFFSET; /** The value of {@code arrayBaseOffset(double[].class)} */ - public static final int ARRAY_DOUBLE_BASE_OFFSET - = theUnsafe.arrayBaseOffset(double[].class); + public static final int ARRAY_DOUBLE_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_DOUBLE_BASE_OFFSET; /** The value of {@code arrayBaseOffset(Object[].class)} */ - public static final int ARRAY_OBJECT_BASE_OFFSET - = theUnsafe.arrayBaseOffset(Object[].class); + public static final int ARRAY_OBJECT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_OBJECT_BASE_OFFSET; /** * Reports the scale factor for addressing elements in the storage @@ -600,43 +789,37 @@ public final class Unsafe { * @see #getInt(Object, long) * @see #putInt(Object, long, int) */ - public native int arrayIndexScale(Class arrayClass); + @ForceInline + public int arrayIndexScale(Class arrayClass) { + return theInternalUnsafe.arrayIndexScale(arrayClass); + } /** The value of {@code arrayIndexScale(boolean[].class)} */ - public static final int ARRAY_BOOLEAN_INDEX_SCALE - = theUnsafe.arrayIndexScale(boolean[].class); + public static final int ARRAY_BOOLEAN_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_BOOLEAN_INDEX_SCALE; /** The value of {@code arrayIndexScale(byte[].class)} */ - public static final int ARRAY_BYTE_INDEX_SCALE - = theUnsafe.arrayIndexScale(byte[].class); + public static final int ARRAY_BYTE_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_BYTE_INDEX_SCALE; /** The value of {@code arrayIndexScale(short[].class)} */ - public static final int ARRAY_SHORT_INDEX_SCALE - = theUnsafe.arrayIndexScale(short[].class); + public static final int ARRAY_SHORT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_SHORT_INDEX_SCALE; /** The value of {@code arrayIndexScale(char[].class)} */ - public static final int ARRAY_CHAR_INDEX_SCALE - = theUnsafe.arrayIndexScale(char[].class); + public static final int ARRAY_CHAR_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_CHAR_INDEX_SCALE; /** The value of {@code arrayIndexScale(int[].class)} */ - public static final int ARRAY_INT_INDEX_SCALE - = theUnsafe.arrayIndexScale(int[].class); + public static final int ARRAY_INT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_INT_INDEX_SCALE; /** The value of {@code arrayIndexScale(long[].class)} */ - public static final int ARRAY_LONG_INDEX_SCALE - = theUnsafe.arrayIndexScale(long[].class); + public static final int ARRAY_LONG_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_LONG_INDEX_SCALE; /** The value of {@code arrayIndexScale(float[].class)} */ - public static final int ARRAY_FLOAT_INDEX_SCALE - = theUnsafe.arrayIndexScale(float[].class); + public static final int ARRAY_FLOAT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_FLOAT_INDEX_SCALE; /** The value of {@code arrayIndexScale(double[].class)} */ - public static final int ARRAY_DOUBLE_INDEX_SCALE - = theUnsafe.arrayIndexScale(double[].class); + public static final int ARRAY_DOUBLE_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_DOUBLE_INDEX_SCALE; /** The value of {@code arrayIndexScale(Object[].class)} */ - public static final int ARRAY_OBJECT_INDEX_SCALE - = theUnsafe.arrayIndexScale(Object[].class); + public static final int ARRAY_OBJECT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_OBJECT_INDEX_SCALE; /** * Reports the size in bytes of a native pointer, as stored via {@link @@ -644,16 +827,22 @@ public final class Unsafe { * other primitive types (as stored in native memory blocks) is determined * fully by their information content. */ - public native int addressSize(); + @ForceInline + public int addressSize() { + return theInternalUnsafe.addressSize(); + } /** The value of {@code addressSize()} */ - public static final int ADDRESS_SIZE = theUnsafe.addressSize(); + public static final int ADDRESS_SIZE = theInternalUnsafe.addressSize(); /** * Reports the size in bytes of a native memory page (whatever that is). * This value will always be a power of two. */ - public native int pageSize(); + @ForceInline + public int pageSize() { + return theInternalUnsafe.pageSize(); + } /// random trusted operations from JNI: @@ -662,9 +851,12 @@ public final class Unsafe { * Tells the VM to define a class, without security checks. By default, the * class loader and protection domain come from the caller's class. */ - public native Class defineClass(String name, byte[] b, int off, int len, - ClassLoader loader, - ProtectionDomain protectionDomain); + @ForceInline + public Class defineClass(String name, byte[] b, int off, int len, + ClassLoader loader, + ProtectionDomain protectionDomain) { + return theInternalUnsafe.defineClass(name, b, off, len, loader, protectionDomain); + } /** * Defines a class but does not make it known to the class loader or system dictionary. @@ -682,18 +874,26 @@ public final class Unsafe { * @param data bytes of a class file * @param cpPatches where non-null entries exist, they replace corresponding CP entries in data */ - public native Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches); + @ForceInline + public Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches) { + return theInternalUnsafe.defineAnonymousClass(hostClass, data, cpPatches); + } /** * Allocates an instance but does not run any constructor. * Initializes the class if it has not yet been. */ - @HotSpotIntrinsicCandidate - public native Object allocateInstance(Class cls) - throws InstantiationException; + @ForceInline + public Object allocateInstance(Class cls) + throws InstantiationException { + return theInternalUnsafe.allocateInstance(cls); + } /** Throws the exception without telling the verifier. */ - public native void throwException(Throwable ee); + @ForceInline + public void throwException(Throwable ee) { + theInternalUnsafe.throwException(ee); + } /** * Atomically updates Java variable to {@code x} if it is currently @@ -704,10 +904,12 @@ public final class Unsafe { * * @return {@code true} if successful */ - @HotSpotIntrinsicCandidate - public final native boolean compareAndSwapObject(Object o, long offset, - Object expected, - Object x); + @ForceInline + public final boolean compareAndSwapObject(Object o, long offset, + Object expected, + Object x) { + return theInternalUnsafe.compareAndSwapObject(o, offset, expected, x); + } /** * Atomically updates Java variable to {@code x} if it is currently @@ -718,10 +920,12 @@ public final class Unsafe { * * @return {@code true} if successful */ - @HotSpotIntrinsicCandidate - public final native boolean compareAndSwapInt(Object o, long offset, - int expected, - int x); + @ForceInline + public final boolean compareAndSwapInt(Object o, long offset, + int expected, + int x) { + return theInternalUnsafe.compareAndSwapInt(o, offset, expected, x); + } /** * Atomically updates Java variable to {@code x} if it is currently @@ -732,88 +936,126 @@ public final class Unsafe { * * @return {@code true} if successful */ - @HotSpotIntrinsicCandidate - public final native boolean compareAndSwapLong(Object o, long offset, - long expected, - long x); + @ForceInline + public final boolean compareAndSwapLong(Object o, long offset, + long expected, + long x) { + return theInternalUnsafe.compareAndSwapLong(o, offset, expected, x); + } /** * Fetches a reference value from a given Java variable, with volatile * load semantics. Otherwise identical to {@link #getObject(Object, long)} */ - @HotSpotIntrinsicCandidate - public native Object getObjectVolatile(Object o, long offset); + @ForceInline + public Object getObjectVolatile(Object o, long offset) { + return theInternalUnsafe.getObjectVolatile(o, offset); + } /** * Stores a reference value into a given Java variable, with * volatile store semantics. Otherwise identical to {@link #putObject(Object, long, Object)} */ - @HotSpotIntrinsicCandidate - public native void putObjectVolatile(Object o, long offset, Object x); + @ForceInline + public void putObjectVolatile(Object o, long offset, Object x) { + theInternalUnsafe.putObjectVolatile(o, offset, x); + } /** Volatile version of {@link #getInt(Object, long)} */ - @HotSpotIntrinsicCandidate - public native int getIntVolatile(Object o, long offset); + @ForceInline + public int getIntVolatile(Object o, long offset) { + return theInternalUnsafe.getIntVolatile(o, offset); + } /** Volatile version of {@link #putInt(Object, long, int)} */ - @HotSpotIntrinsicCandidate - public native void putIntVolatile(Object o, long offset, int x); + @ForceInline + public void putIntVolatile(Object o, long offset, int x) { + theInternalUnsafe.putIntVolatile(o, offset, x); + } /** Volatile version of {@link #getBoolean(Object, long)} */ - @HotSpotIntrinsicCandidate - public native boolean getBooleanVolatile(Object o, long offset); + @ForceInline + public boolean getBooleanVolatile(Object o, long offset) { + return theInternalUnsafe.getBooleanVolatile(o, offset); + } /** Volatile version of {@link #putBoolean(Object, long, boolean)} */ - @HotSpotIntrinsicCandidate - public native void putBooleanVolatile(Object o, long offset, boolean x); + @ForceInline + public void putBooleanVolatile(Object o, long offset, boolean x) { + theInternalUnsafe.putBooleanVolatile(o, offset, x); + } /** Volatile version of {@link #getByte(Object, long)} */ - @HotSpotIntrinsicCandidate - public native byte getByteVolatile(Object o, long offset); + @ForceInline + public byte getByteVolatile(Object o, long offset) { + return theInternalUnsafe.getByteVolatile(o, offset); + } /** Volatile version of {@link #putByte(Object, long, byte)} */ - @HotSpotIntrinsicCandidate - public native void putByteVolatile(Object o, long offset, byte x); + @ForceInline + public void putByteVolatile(Object o, long offset, byte x) { + theInternalUnsafe.putByteVolatile(o, offset, x); + } /** Volatile version of {@link #getShort(Object, long)} */ - @HotSpotIntrinsicCandidate - public native short getShortVolatile(Object o, long offset); + @ForceInline + public short getShortVolatile(Object o, long offset) { + return theInternalUnsafe.getShortVolatile(o, offset); + } /** Volatile version of {@link #putShort(Object, long, short)} */ - @HotSpotIntrinsicCandidate - public native void putShortVolatile(Object o, long offset, short x); + @ForceInline + public void putShortVolatile(Object o, long offset, short x) { + theInternalUnsafe.putShortVolatile(o, offset, x); + } /** Volatile version of {@link #getChar(Object, long)} */ - @HotSpotIntrinsicCandidate - public native char getCharVolatile(Object o, long offset); + @ForceInline + public char getCharVolatile(Object o, long offset) { + return theInternalUnsafe.getCharVolatile(o, offset); + } /** Volatile version of {@link #putChar(Object, long, char)} */ - @HotSpotIntrinsicCandidate - public native void putCharVolatile(Object o, long offset, char x); + @ForceInline + public void putCharVolatile(Object o, long offset, char x) { + theInternalUnsafe.putCharVolatile(o, offset, x); + } /** Volatile version of {@link #getLong(Object, long)} */ - @HotSpotIntrinsicCandidate - public native long getLongVolatile(Object o, long offset); + @ForceInline + public long getLongVolatile(Object o, long offset) { + return theInternalUnsafe.getLongVolatile(o, offset); + } /** Volatile version of {@link #putLong(Object, long, long)} */ - @HotSpotIntrinsicCandidate - public native void putLongVolatile(Object o, long offset, long x); + @ForceInline + public void putLongVolatile(Object o, long offset, long x) { + theInternalUnsafe.putLongVolatile(o, offset, x); + } /** Volatile version of {@link #getFloat(Object, long)} */ - @HotSpotIntrinsicCandidate - public native float getFloatVolatile(Object o, long offset); + @ForceInline + public float getFloatVolatile(Object o, long offset) { + return theInternalUnsafe.getFloatVolatile(o, offset); + } /** Volatile version of {@link #putFloat(Object, long, float)} */ - @HotSpotIntrinsicCandidate - public native void putFloatVolatile(Object o, long offset, float x); + @ForceInline + public void putFloatVolatile(Object o, long offset, float x) { + theInternalUnsafe.putFloatVolatile(o, offset, x); + } /** Volatile version of {@link #getDouble(Object, long)} */ - @HotSpotIntrinsicCandidate - public native double getDoubleVolatile(Object o, long offset); + @ForceInline + public double getDoubleVolatile(Object o, long offset) { + return theInternalUnsafe.getDoubleVolatile(o, offset); + } /** Volatile version of {@link #putDouble(Object, long, double)} */ - @HotSpotIntrinsicCandidate - public native void putDoubleVolatile(Object o, long offset, double x); + @ForceInline + public void putDoubleVolatile(Object o, long offset, double x) { + theInternalUnsafe.putDoubleVolatile(o, offset, x); + } /** * Version of {@link #putObjectVolatile(Object, long, Object)} @@ -824,16 +1066,22 @@ public final class Unsafe { * * Corresponds to C11 atomic_store_explicit(..., memory_order_release). */ - @HotSpotIntrinsicCandidate - public native void putOrderedObject(Object o, long offset, Object x); + @ForceInline + public void putOrderedObject(Object o, long offset, Object x) { + theInternalUnsafe.putOrderedObject(o, offset, x); + } /** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)} */ - @HotSpotIntrinsicCandidate - public native void putOrderedInt(Object o, long offset, int x); + @ForceInline + public void putOrderedInt(Object o, long offset, int x) { + theInternalUnsafe.putOrderedInt(o, offset, x); + } /** Ordered/Lazy version of {@link #putLongVolatile(Object, long, long)} */ - @HotSpotIntrinsicCandidate - public native void putOrderedLong(Object o, long offset, long x); + @ForceInline + public void putOrderedLong(Object o, long offset, long x) { + theInternalUnsafe.putOrderedLong(o, offset, x); + } /** * Unblocks the given thread blocked on {@code park}, or, if it is @@ -847,8 +1095,10 @@ public final class Unsafe { * * @param thread the thread to unpark. */ - @HotSpotIntrinsicCandidate - public native void unpark(Object thread); + @ForceInline + public void unpark(Object thread) { + theInternalUnsafe.unpark(thread); + } /** * Blocks current thread, returning when a balancing @@ -861,8 +1111,10 @@ public final class Unsafe { * because {@code unpark} is, so it would be strange to place it * elsewhere. */ - @HotSpotIntrinsicCandidate - public native void park(boolean isAbsolute, long time); + @ForceInline + public void park(boolean isAbsolute, long time) { + theInternalUnsafe.park(isAbsolute, time); + } /** * Gets the load average in the system run queue assigned @@ -879,7 +1131,10 @@ public final class Unsafe { * @return the number of samples actually retrieved; or -1 * if the load average is unobtainable. */ - public native int getLoadAverage(double[] loadavg, int nelems); + @ForceInline + public int getLoadAverage(double[] loadavg, int nelems) { + return theInternalUnsafe.getLoadAverage(loadavg, nelems); + } // The following contain CAS-based Java implementations used on // platforms not supporting native instructions @@ -895,13 +1150,9 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ - @HotSpotIntrinsicCandidate + @ForceInline public final int getAndAddInt(Object o, long offset, int delta) { - int v; - do { - v = getIntVolatile(o, offset); - } while (!compareAndSwapInt(o, offset, v, v + delta)); - return v; + return theInternalUnsafe.getAndAddInt(o, offset, delta); } /** @@ -915,13 +1166,9 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ - @HotSpotIntrinsicCandidate + @ForceInline public final long getAndAddLong(Object o, long offset, long delta) { - long v; - do { - v = getLongVolatile(o, offset); - } while (!compareAndSwapLong(o, offset, v, v + delta)); - return v; + return theInternalUnsafe.getAndAddLong(o, offset, delta); } /** @@ -935,13 +1182,9 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ - @HotSpotIntrinsicCandidate + @ForceInline public final int getAndSetInt(Object o, long offset, int newValue) { - int v; - do { - v = getIntVolatile(o, offset); - } while (!compareAndSwapInt(o, offset, v, newValue)); - return v; + return theInternalUnsafe.getAndSetInt(o, offset, newValue); } /** @@ -955,13 +1198,9 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ - @HotSpotIntrinsicCandidate + @ForceInline public final long getAndSetLong(Object o, long offset, long newValue) { - long v; - do { - v = getLongVolatile(o, offset); - } while (!compareAndSwapLong(o, offset, v, newValue)); - return v; + return theInternalUnsafe.getAndSetLong(o, offset, newValue); } /** @@ -975,13 +1214,9 @@ public final class Unsafe { * @return the previous value * @since 1.8 */ - @HotSpotIntrinsicCandidate + @ForceInline public final Object getAndSetObject(Object o, long offset, Object newValue) { - Object v; - do { - v = getObjectVolatile(o, offset); - } while (!compareAndSwapObject(o, offset, v, newValue)); - return v; + return theInternalUnsafe.getAndSetObject(o, offset, newValue); } @@ -997,8 +1232,10 @@ public final class Unsafe { * provide a LoadLoad barrier also provide a LoadStore barrier for free. * @since 1.8 */ - @HotSpotIntrinsicCandidate - public native void loadFence(); + @ForceInline + public void loadFence() { + theInternalUnsafe.loadFence(); + } /** * Ensures that loads and stores before the fence will not be reordered with @@ -1012,8 +1249,10 @@ public final class Unsafe { * provide a StoreStore barrier also provide a LoadStore barrier for free. * @since 1.8 */ - @HotSpotIntrinsicCandidate - public native void storeFence(); + @ForceInline + public void storeFence() { + theInternalUnsafe.storeFence(); + } /** * Ensures that loads and stores before the fence will not be reordered @@ -1024,15 +1263,8 @@ public final class Unsafe { * Corresponds to C11 atomic_thread_fence(memory_order_seq_cst). * @since 1.8 */ - @HotSpotIntrinsicCandidate - public native void fullFence(); - - /** - * Throws IllegalAccessError; for use by the VM for access control - * error support. - * @since 1.8 - */ - private static void throwIllegalAccessError() { - throw new IllegalAccessError(); + @ForceInline + public void fullFence() { + theInternalUnsafe.fullFence(); } } diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java b/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java new file mode 100644 index 00000000000..c87bb1b6895 --- /dev/null +++ b/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java @@ -0,0 +1,667 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.internal.misc.Unsafe; +import java.lang.reflect.Field; + +/* + * @test + * @summary Test Unsafe.copyMemory + * @modules java.base/jdk.internal.misc + */ +public class CopyMemory { + private static final boolean DEBUG = Boolean.getBoolean("CopyMemory.DEBUG"); + + public static final long KB = 1024; + public static final long MB = KB * 1024; + public static final long GB = MB * 1024; + + private static final Unsafe UNSAFE; + private static final int SMALL_COPY_SIZE = 32; + private static final int BASE_ALIGNMENT = 16; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + } + + private static long alignDown(long value, long alignment) { + return value & ~(alignment - 1); + } + + private static long alignUp(long value, long alignment) { + return (value + alignment - 1) & ~(alignment - 1); + } + + private static boolean isAligned(long value, long alignment) { + return value == alignDown(value, alignment); + } + + private CopyMemory() { + } + + /** + * Generate verification data for a given offset + * + * The verification data is used to verify that the correct bytes + * have indeed been copied and byte swapped. + * + * The data is generated based on the offset (in bytes) into the + * source buffer. For a native buffer the offset is relative to + * the base pointer. For a heap array it is relative to the + * address of the first array element. + * + * This method will return the result of doing an elementSize byte + * read starting at offset (in bytes). + * + * @param offset offset into buffer + * @param elemSize size (in bytes) of the element + * + * @return the verification data, only the least significant + * elemSize*8 bits are set, zero extended + */ + private long getVerificationDataForOffset(long offset, long elemSize) { + byte[] bytes = new byte[(int)elemSize]; + + for (long i = 0; i < elemSize; i++) { + bytes[(int)i] = (byte)(offset + i); + } + + long o = UNSAFE.arrayBaseOffset(byte[].class); + + switch ((int)elemSize) { + case 1: return Byte.toUnsignedLong(UNSAFE.getByte(bytes, o)); + case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(bytes, o)); + case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(bytes, o)); + case 8: return UNSAFE.getLongUnaligned(bytes, o); + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Verify byte swapped data + * + * @param ptr the data to verify + * @param srcOffset the srcOffset (in bytes) from which the copy started, + * used as key to regenerate the verification data + * @param dstOffset the offset (in bytes) in the array at which to start + * the verification, relative to the first element in the array + * @param size size (in bytes) of data to to verify + * @param elemSize size (in bytes) of the individual array elements + * + * @throws RuntimeException if an error is found + */ + private void verifySwappedData(GenericPointer ptr, long srcOffset, long dstOffset, long size, long elemSize) { + for (long offset = 0; offset < size; offset += elemSize) { + long expectedUnswapped = getVerificationDataForOffset(srcOffset + offset, elemSize); + long expected = byteSwap(expectedUnswapped, elemSize); + + long actual = getArrayElem(ptr, dstOffset + offset, elemSize); + + if (expected != actual) { + throw new RuntimeException("srcOffset: 0x" + Long.toHexString(srcOffset) + + " dstOffset: 0x" + Long.toHexString(dstOffset) + + " size: 0x" + Long.toHexString(size) + + " offset: 0x" + Long.toHexString(offset) + + " expectedUnswapped: 0x" + Long.toHexString(expectedUnswapped) + + " expected: 0x" + Long.toHexString(expected) + + " != actual: 0x" + Long.toHexString(actual)); + } + } + } + + /** + * Initialize an array with verification friendly data + * + * @param ptr pointer to the data to initialize + * @param size size (in bytes) of the data + * @param elemSize size (in bytes) of the individual elements + */ + private void initVerificationData(GenericPointer ptr, long size, long elemSize) { + for (long offset = 0; offset < size; offset++) { + byte data = (byte)getVerificationDataForOffset(offset, 1); + + if (ptr.isOnHeap()) { + UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data); + } else { + UNSAFE.putByte(ptr.getOffset() + offset, data); + } + } + } + + /** + * Allocate a primitive array + * + * @param size size (in bytes) of all the array elements (elemSize * length) + * @param elemSize the size of the array elements + * + * @return a newly allocated primitive array + */ + Object allocArray(long size, long elemSize) { + int length = (int)(size / elemSize); + + switch ((int)elemSize) { + case 1: return new byte[length]; + case 2: return new short[length]; + case 4: return new int[length]; + case 8: return new long[length]; + default: + throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Get the value of a primitive array entry + * + * @param ptr pointer to the data + * @param offset offset (in bytes) of the array element, relative to the first element in the array + * + * @return the array element, as an unsigned long + */ + private long getArrayElem(GenericPointer ptr, long offset, long elemSize) { + if (ptr.isOnHeap()) { + Object o = ptr.getObject(); + int index = (int)(offset / elemSize); + + if (o instanceof short[]) { + short[] arr = (short[])o; + return Short.toUnsignedLong(arr[index]); + } else if (o instanceof int[]) { + int[] arr = (int[])o; + return Integer.toUnsignedLong(arr[index]); + } else if (o instanceof long[]) { + long[] arr = (long[])o; + return arr[index]; + } else { + throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); + } + } else { + long addr = ptr.getOffset() + offset; + + switch ((int)elemSize) { + case 1: return Byte.toUnsignedLong(UNSAFE.getByte(addr)); + case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(null, addr)); + case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(null, addr)); + case 8: return UNSAFE.getLongUnaligned(null, addr); + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + } + + private void putValue(long addr, long elemSize, long value) { + switch ((int)elemSize) { + case 1: UNSAFE.putByte(addr, (byte)value); break; + case 2: UNSAFE.putShortUnaligned(null, addr, (short)value); break; + case 4: UNSAFE.putIntUnaligned(null, addr, (int)value); break; + case 8: UNSAFE.putLongUnaligned(null, addr, value); break; + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Get the size of the elements for an array + * + * @param o a primitive heap array + * + * @return the size (in bytes) of the individual array elements + */ + private long getArrayElemSize(Object o) { + if (o instanceof short[]) { + return 2; + } else if (o instanceof int[]) { + return 4; + } else if (o instanceof long[]) { + return 8; + } else { + throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); + } + } + + /** + * Byte swap a value + * + * @param value the value to swap, only the bytes*8 least significant bits are used + * @param size size (in bytes) of the value + * + * @return the byte swapped value in the bytes*8 least significant bits + */ + private long byteSwap(long value, long size) { + switch ((int)size) { + case 2: return Short.toUnsignedLong(Short.reverseBytes((short)value)); + case 4: return Integer.toUnsignedLong(Integer.reverseBytes((int)value)); + case 8: return Long.reverseBytes(value); + default: throw new IllegalArgumentException("Invalid element size: " + size); + } + } + + /** + * Verify data which has *not* been byte swapped + * + * @param ptr the data to verify + * @param startOffset the offset (in bytes) at which to start the verification + * @param size size (in bytes) of the data to verify + * + * @throws RuntimeException if an error is found + */ + private void verifyUnswappedData(GenericPointer ptr, long startOffset, long srcOffset, long size) { + for (long i = 0; i < size; i++) { + byte expected = (byte)getVerificationDataForOffset(srcOffset + i, 1); + + byte actual; + if (ptr.isOnHeap()) { + actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + startOffset + i); + } else { + actual = UNSAFE.getByte(ptr.getOffset() + startOffset + i); + } + + if (expected != actual) { + throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) + + " srcOffset: 0x" + Long.toHexString(srcOffset) + + " size: 0x" + Long.toHexString(size) + + " i: 0x" + Long.toHexString(i) + + " expected: 0x" + Long.toHexString(expected) + + " != actual: 0x" + Long.toHexString(actual)); + } + } + } + + + /** + * Copy and byte swap data from the source to the destination + * + * This method will pre-populate the whole source and destination + * buffers with verification friendly data. It will then use + * copypMemory to fill part of the destination buffer with + * data from the source. Some space (padding) will be + * left before and after the data in the destination buffer, which + * should not be touched/overwritten by the copy call. + * + * Note: Both source and destination buffers will be overwritten! + * + * @param src source buffer to copy from + * @param srcOffset the offset (in bytes) in the source buffer, relative to + * the first array element, at which to start reading data + * @param dst destination buffer to copy to + * @param dstOffset the offset (in bytes) in the destination + * buffer, relative to the first array element, at which to + * start writing data + * @param bufSize the size (in bytes) of the src and dst arrays + * @param copyBytes the size (in bytes) of the copy to perform, + * must be a multiple of elemSize + * + * @throws RuntimeException if an error is found + */ + private void testCopy(GenericPointer src, long srcOffset, + GenericPointer dst, long dstOffset, + long bufSize, long copyBytes) { + if (srcOffset + copyBytes > bufSize) { + throw new IllegalArgumentException( + "srcOffset (" + srcOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); + } + if (dstOffset + copyBytes > bufSize) { + throw new IllegalArgumentException( + "dstOffset (" + dstOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); + } + + // Initialize the whole source buffer with a verification friendly pattern (no 0x00 bytes) + initVerificationData(src, bufSize, 1); + if (!src.equals(dst)) { + initVerificationData(dst, bufSize, 1); + } + + if (DEBUG) { + System.out.println("===before==="); + for (int offset = 0; offset < bufSize; offset++) { + long srcValue = getArrayElem(src, offset, 1); + long dstValue = getArrayElem(dst, offset, 1); + + System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + + " src=0x" + Long.toHexString(srcValue) + + " dst=0x" + Long.toHexString(dstValue)); + } + } + + // Copy & swap data into the middle of the destination buffer + UNSAFE.copyMemory(src.getObject(), + src.getOffset() + srcOffset, + dst.getObject(), + dst.getOffset() + dstOffset, + copyBytes); + + if (DEBUG) { + System.out.println("===after==="); + for (int offset = 0; offset < bufSize; offset++) { + long srcValue = getArrayElem(src, offset, 1); + long dstValue = getArrayElem(dst, offset, 1); + + System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + + " src=0x" + Long.toHexString(srcValue) + + " dst=0x" + Long.toHexString(dstValue)); + } + } + + // Verify the the front padding is unchanged + verifyUnswappedData(dst, 0, 0, dstOffset); + + // Verify copied data + verifyUnswappedData(dst, dstOffset, srcOffset, copyBytes); + + // Verify that the back back padding is unchanged + long frontAndDataBytes = dstOffset + copyBytes; + long trailingBytes = bufSize - frontAndDataBytes; + verifyUnswappedData(dst, frontAndDataBytes, frontAndDataBytes, trailingBytes); + } + + /** + * Test various configurations copying from one buffer to the other + * + * @param src the source buffer to copy from + * @param dst the destination buffer to copy to + * @param size size (in bytes) of the buffers + * @param elemSize size (in bytes) of the individual elements + * + * @throws RuntimeException if an error is found + */ + public void testBufferPair(GenericPointer src, GenericPointer dst, long size, long elemSize) { + // offset in source from which to start reading data + for (long srcOffset = 0; srcOffset < size; srcOffset += (src.isOnHeap() ? elemSize : 1)) { + + // offset in destination at which to start writing data + for (int dstOffset = 0; dstOffset < size; dstOffset += (dst.isOnHeap() ? elemSize : 1)) { + + // number of bytes to copy + long maxCopyBytes = Math.min(size - srcOffset, size - dstOffset); + for (long copyBytes = 0; copyBytes < maxCopyBytes; copyBytes += elemSize) { + try { + testCopy(src, srcOffset, dst, dstOffset, size, copyBytes); + } catch (RuntimeException e) { + // Wrap the exception in another exception to catch the relevant configuration data + throw new RuntimeException("testBufferPair: " + + "src=" + src + + " dst=" + dst + + " elemSize=0x" + Long.toHexString(elemSize) + + " copyBytes=0x" + Long.toHexString(copyBytes) + + " srcOffset=0x" + Long.toHexString(srcOffset) + + " dstOffset=0x" + Long.toHexString(dstOffset), + e); + } + } + } + } + } + + /** + * Test copying between various permutations of buffers + * + * @param buffers buffers to permute (src x dst) + * @param size size (in bytes) of buffers + * @param elemSize size (in bytes) of individual elements + * + * @throws RuntimeException if an error is found + */ + public void testPermuteBuffers(GenericPointer[] buffers, long size, long elemSize) { + for (int srcIndex = 0; srcIndex < buffers.length; srcIndex++) { + for (int dstIndex = 0; dstIndex < buffers.length; dstIndex++) { + testBufferPair(buffers[srcIndex], buffers[dstIndex], size, elemSize); + } + } + } + + /** + * Test copying of a specific element size + * + * @param size size (in bytes) of buffers to allocate + * @param elemSize size (in bytes) of individual elements + * + * @throws RuntimeException if an error is found + */ + private void testElemSize(long size, long elemSize) { + long buf1Raw = 0; + long buf2Raw = 0; + + try { + buf1Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + long buf1 = alignUp(buf1Raw, BASE_ALIGNMENT); + + buf2Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + long buf2 = alignUp(buf2Raw, BASE_ALIGNMENT); + + GenericPointer[] buffers = { + new GenericPointer(buf1), + new GenericPointer(buf2), + new GenericPointer(allocArray(size, elemSize)), + new GenericPointer(allocArray(size, elemSize)) + }; + + testPermuteBuffers(buffers, size, elemSize); + } finally { + if (buf1Raw != 0) { + UNSAFE.freeMemory(buf1Raw); + } + if (buf2Raw != 0) { + UNSAFE.freeMemory(buf2Raw); + } + } + } + + /** + * Verify that small copies work + */ + private void testSmallCopy() { + int smallBufSize = SMALL_COPY_SIZE; + + testElemSize(smallBufSize, 1); + } + + + /** + * Verify that large copies work + */ + private void testLargeCopy() { + long size = 2 * GB + 8; + long bufRaw = 0; + + // Check that a large native copy succeeds + try { + try { + bufRaw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + } catch (OutOfMemoryError e) { + // Accept failure, skip test + return; + } + + long buf = alignUp(bufRaw, BASE_ALIGNMENT); + + UNSAFE.copyMemory(null, buf, null, buf, size); + } catch (Exception e) { + throw new RuntimeException("copyMemory of large buffer failed"); + } finally { + if (bufRaw != 0) { + UNSAFE.freeMemory(bufRaw); + } + } + } + + /** + * Run positive tests + * + * @throws RuntimeException if an error is found + */ + private void testPositive() { + testSmallCopy(); + testLargeCopy(); + } + + /** + * Run negative tests, testing corner cases and the various exceptions + * + * @throws RuntimeException if an error is found + */ + private void testNegative() { + long bufRaw = 0; + + try { + bufRaw = UNSAFE.allocateMemory(1024); + long buf = alignUp(bufRaw, BASE_ALIGNMENT); + short[] arr = new short[16]; + + // Check illegal sizes + System.out.println("Testing negative size"); + try { + UNSAFE.copyMemory(null, buf, null, buf, -1); + throw new RuntimeException("copyMemory failed to throw IAE for size=-1"); + } catch (IllegalArgumentException e) { + // good + } + + System.out.println("Testing negative srcOffset"); + try { + // Check that negative srcOffset throws an IAE + UNSAFE.copyMemory(arr, -1, arr, UNSAFE.arrayBaseOffset(arr.getClass()), 16); + throw new RuntimeException("copyMemory failed to throw IAE for srcOffset=-1"); + } catch (IllegalArgumentException e) { + // good + } + + System.out.println("Testing negative destOffset"); + try { + // Check that negative dstOffset throws an IAE + UNSAFE.copyMemory(arr, UNSAFE.arrayBaseOffset(arr.getClass()), arr, -1, 16); + throw new RuntimeException("copyMemory failed to throw IAE for destOffset=-1"); + } catch (IllegalArgumentException e) { + // good + } + + System.out.println("Testing reference array"); + try { + // Check that a reference array destination throws IAE + UNSAFE.copyMemory(null, buf, new Object[16], UNSAFE.arrayBaseOffset(Object[].class), 16); + throw new RuntimeException("copyMemory failed to throw IAE"); + } catch (IllegalArgumentException e) { + // good + } + + // Check that invalid source & dest pointers throw IAEs (only relevant on 32-bit platforms) + if (UNSAFE.addressSize() == 4) { + long invalidPtr = (long)1 << 35; // Pick a random bit in upper 32 bits + + try { + // Check that an invalid (not 32-bit clean) source pointer throws IAE + UNSAFE.copyMemory(null, invalidPtr, null, buf, 16); + throw new RuntimeException("copyMemory failed to throw IAE for srcOffset 0x" + + Long.toHexString(invalidPtr)); + } catch (IllegalArgumentException e) { + // good + } + + try { + // Check that an invalid (not 32-bit clean) source pointer throws IAE + UNSAFE.copyMemory(null, buf, null, invalidPtr, 16); + throw new RuntimeException("copyMemory failed to throw IAE for destOffset 0x" + + Long.toHexString(invalidPtr)); + } catch (IllegalArgumentException e) { + // good + } + } + } finally { + if (bufRaw != 0) { + UNSAFE.freeMemory(bufRaw); + } + } + } + + /** + * Run all tests + * + * @throws RuntimeException if an error is found + */ + private void test() { + testPositive(); + testNegative(); + } + + public static void main(String[] args) { + CopyMemory cs = new CopyMemory(); + cs.test(); + } + + /** + * Helper class to represent a "pointer" - either a heap array or + * a pointer to a native buffer. + * + * In the case of a native pointer, the Object is null and the offset is + * the absolute address of the native buffer. + * + * In the case of a heap object, the Object is a primitive array, and + * the offset will be set to the base offset to the first element, meaning + * the object and the offset together form a double-register pointer. + */ + static class GenericPointer { + private final Object o; + private final long offset; + + private GenericPointer(Object o, long offset) { + this.o = o; + this.offset = offset; + } + + public String toString() { + return "GenericPointer(o={" + o + "}, offset=0x" + Long.toHexString(offset) + ")"; + } + + public boolean equals(Object other) { + if (!(other instanceof GenericPointer)) { + return false; + } + + GenericPointer otherp = (GenericPointer)other; + + return o == otherp.o && offset == otherp.offset; + } + + GenericPointer(Object o) { + this(o, UNSAFE.arrayBaseOffset(o.getClass())); + } + + GenericPointer(long offset) { + this(null, offset); + } + + public boolean isOnHeap() { + return o != null; + } + + public Object getObject() { + return o; + } + + public long getOffset() { + return offset; + } + } +} diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java index ba61e23fcc9..bb94c200765 100644 --- a/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java +++ b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java @@ -586,22 +586,6 @@ public class CopySwap { } } - try { - // Check that a NULL source throws NPE - UNSAFE.copySwapMemory(null, 0, null, buf, 16, 2); - throw new RuntimeException("copySwapMemory failed to throw NPE"); - } catch (NullPointerException e) { - // good - } - - try { - // Check that a NULL destination throws NPE - UNSAFE.copySwapMemory(null, buf, null, 0, 16, 2); - throw new RuntimeException("copySwapMemory failed to throw NPE"); - } catch (NullPointerException e) { - // good - } - try { // Check that a reference array destination throws IAE UNSAFE.copySwapMemory(null, buf, new Object[16], UNSAFE.arrayBaseOffset(Object[].class), 16, 8); From f6ca30aea569ad3877535a0849870afc290e9e0f Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 3 Mar 2016 23:57:07 +0300 Subject: [PATCH 077/129] 8150465: Unsafe methods to produce uninitialized arrays Reviewed-by: jrose, kvn, psandoz, aph, twisti, flar --- .../classes/jdk/internal/misc/Unsafe.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java index db643df591b..8b8a0ff9531 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java @@ -1161,6 +1161,59 @@ public final class Unsafe { public native Object allocateInstance(Class cls) throws InstantiationException; + /** + * Allocates an array of a given type, but does not do zeroing. + *

+ * This method should only be used in the very rare cases where a high-performance code + * overwrites the destination array completely, and compilers cannot assist in zeroing elimination. + * In an overwhelming majority of cases, a normal Java allocation should be used instead. + *

+ * Users of this method are required to overwrite the initial (garbage) array contents + * before allowing untrusted code, or code in other threads, to observe the reference + * to the newly allocated array. In addition, the publication of the array reference must be + * safe according to the Java Memory Model requirements. + *

+ * The safest approach to deal with an uninitialized array is to keep the reference to it in local + * variable at least until the initialization is complete, and then publish it once, either + * by writing it to a volatile field, or storing it into a final field in constructor, + * or issuing a {@link #storeFence} before publishing the reference. + *

+ * @implnote This method can only allocate primitive arrays, to avoid garbage reference + * elements that could break heap integrity. + * + * @param componentType array component type to allocate + * @param length array size to allocate + * @throws IllegalArgumentException if component type is null, or not a primitive class; + * or the length is negative + */ + public Object allocateUninitializedArray(Class componentType, int length) { + if (componentType == null) { + throw new IllegalArgumentException("Component type is null"); + } + if (!componentType.isPrimitive()) { + throw new IllegalArgumentException("Component type is not primitive"); + } + if (length < 0) { + throw new IllegalArgumentException("Negative length"); + } + return allocateUninitializedArray0(componentType, length); + } + + @HotSpotIntrinsicCandidate + private Object allocateUninitializedArray0(Class componentType, int length) { + // These fallbacks provide zeroed arrays, but intrinsic is not required to + // return the zeroed arrays. + if (componentType == byte.class) return new byte[length]; + if (componentType == boolean.class) return new boolean[length]; + if (componentType == short.class) return new short[length]; + if (componentType == char.class) return new char[length]; + if (componentType == int.class) return new int[length]; + if (componentType == float.class) return new float[length]; + if (componentType == long.class) return new long[length]; + if (componentType == double.class) return new double[length]; + return null; + } + /** Throws the exception without telling the verifier. */ public native void throwException(Throwable ee); From 57494c431d51ba2a87f218fa2bdb7ef9c188d469 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 11 Mar 2016 15:30:20 -0800 Subject: [PATCH 078/129] 8151750: Mark ChangingInterests.java as intermittently failing Reviewed-by: lancea --- jdk/test/java/nio/channels/Selector/ChangingInterests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jdk/test/java/nio/channels/Selector/ChangingInterests.java b/jdk/test/java/nio/channels/Selector/ChangingInterests.java index c3e1dbd0964..bd8ab27a1b5 100644 --- a/jdk/test/java/nio/channels/Selector/ChangingInterests.java +++ b/jdk/test/java/nio/channels/Selector/ChangingInterests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ /* @test * @bug 7200742 + * @key intermittent * @summary Test that Selector doesn't spin when changing interest ops */ From 1c1cec5a6f54edfab2c4f5c5ffc6c1309e15c7d3 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Fri, 11 Mar 2016 17:07:57 -0800 Subject: [PATCH 079/129] 8151734: Mark Unreachable.java and MaxRetries.java as intermittently failing Reviewed-by: weijun --- jdk/test/sun/security/krb5/auto/MaxRetries.java | 3 ++- jdk/test/sun/security/krb5/auto/Unreachable.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/jdk/test/sun/security/krb5/auto/MaxRetries.java b/jdk/test/sun/security/krb5/auto/MaxRetries.java index 5c5da91653f..d23cd1043b5 100644 --- a/jdk/test/sun/security/krb5/auto/MaxRetries.java +++ b/jdk/test/sun/security/krb5/auto/MaxRetries.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /* * @test * @bug 6844193 + * @key intermittent * @compile -XDignore.symbol.file MaxRetries.java * @run main/othervm/timeout=300 MaxRetries * @summary support max_retries in krb5.conf diff --git a/jdk/test/sun/security/krb5/auto/Unreachable.java b/jdk/test/sun/security/krb5/auto/Unreachable.java index 52339786a9f..b010b54837e 100644 --- a/jdk/test/sun/security/krb5/auto/Unreachable.java +++ b/jdk/test/sun/security/krb5/auto/Unreachable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /* * @test * @bug 7162687 + * @key intermittent * @summary enhance KDC server availability detection * @compile -XDignore.symbol.file Unreachable.java * @run main/othervm/timeout=10 Unreachable From bfb7e8cd0755d7c2a4411afa999e786eb97a8319 Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Sun, 13 Mar 2016 20:26:29 +0100 Subject: [PATCH 080/129] 8150782: findClass / accessClass throw unexpected exceptions Reviewed-by: sundar --- .../java/lang/invoke/MethodHandles.java | 19 +++- .../lang/invoke/t8150782/TestAccessClass.java | 80 +++++++++++++++++ .../java/lang/invoke/t8150782/TestCls.java | 38 ++++++++ .../lang/invoke/t8150782/TestFindClass.java | 90 +++++++++++++++++++ .../java/lang/invoke/t8150782/TestLookup.java | 67 ++++++++++++++ 5 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 jdk/test/java/lang/invoke/t8150782/TestAccessClass.java create mode 100644 jdk/test/java/lang/invoke/t8150782/TestCls.java create mode 100644 jdk/test/java/lang/invoke/t8150782/TestFindClass.java create mode 100644 jdk/test/java/lang/invoke/t8150782/TestLookup.java diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 70791273212..dea7d6c6c14 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -99,13 +99,16 @@ public class MethodHandles { *

* As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class} * of this lookup object will be {@link java.lang.Object}. + * Consequently, the lookup context of this lookup object will be the bootstrap + * class loader, which means it cannot find user classes. * *

* Discussion: * The lookup class can be changed to any other class {@code C} using an expression of the form * {@link Lookup#in publicLookup().in(C.class)}. * Since all classes have equal access to public names, - * such a change would confer no new access rights. + * such a change would confer no new access rights, + * but may change the lookup context by virtue of changing the class loader. * A public lookup object is always subject to * security manager checks. * Also, it cannot access @@ -641,6 +644,11 @@ public class MethodHandles { * then no members, not even public members, will be accessible. * (In all other cases, public members will continue to be accessible.) * + *

+ * The resulting lookup's capabilities for loading classes + * (used during {@link #findClass} invocations) + * are determined by the lookup class' loader, + * which may change due to this operation. * * @param requestedLookupClass the desired lookup class for the new lookup object * @return a lookup object which reports the desired lookup class @@ -939,13 +947,17 @@ assertEquals("[x, y, z]", pb.command().toString()); /** * Looks up a class by name from the lookup context defined by this {@code Lookup} object. The static * initializer of the class is not run. + *

+ * The lookup context here is determined by the {@linkplain #lookupClass() lookup class}, its class + * loader, and the {@linkplain #lookupModes() lookup modes}. In particular, the method first attempts to + * load the requested class, and then determines whether the class is accessible to this lookup object. * * @param targetName the fully qualified name of the class to be looked up. * @return the requested class. * @exception SecurityException if a security manager is present and it * refuses access * @throws LinkageError if the linkage fails - * @throws ClassNotFoundException if the class does not exist. + * @throws ClassNotFoundException if the class cannot be loaded by the lookup class' loader. * @throws IllegalAccessException if the class is not accessible, using the allowed access * modes. * @exception SecurityException if a security manager is present and it @@ -960,6 +972,9 @@ assertEquals("[x, y, z]", pb.command().toString()); /** * Determines if a class can be accessed from the lookup context defined by this {@code Lookup} object. The * static initializer of the class is not run. + *

+ * The lookup context here is determined by the {@linkplain #lookupClass() lookup class} and the + * {@linkplain #lookupModes() lookup modes}. * * @param targetClass the class to be access-checked * diff --git a/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java b/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java new file mode 100644 index 00000000000..5acf3f3bee0 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @compile TestAccessClass.java TestCls.java + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestAccessClass + */ +package test.java.lang.invoke.t8150782; + +import java.lang.invoke.*; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +import org.testng.annotations.*; + +public class TestAccessClass { + + private static boolean initializedClass1; + + private static class Class1 { + static { + initializedClass1 = true; + } + } + + @Test + public void initializerNotRun() throws IllegalAccessException { + lookup().accessClass(Class1.class); + assertFalse(initializedClass1); + } + + @Test + public void returnsSameClass() throws IllegalAccessException, ClassNotFoundException { + Class aClass = lookup().accessClass(Class1.class); + assertEquals(Class1.class, aClass); + } + + @DataProvider + Object[][] illegalAccessAccess() { + return new Object[][] { + {publicLookup(), Class1.class}, + {publicLookup(), TestCls.getPrivateSIC()} + }; + } + + @Test(dataProvider = "illegalAccessAccess", expectedExceptions = {IllegalAccessException.class}) + public void illegalAccessExceptionTest(Lookup lookup, Class klass) throws IllegalAccessException, ClassNotFoundException { + lookup.accessClass(klass); + } + + @Test + public void okAccess() throws IllegalAccessException { + lookup().accessClass(TestCls.getPrivateSIC()); + } + +} diff --git a/jdk/test/java/lang/invoke/t8150782/TestCls.java b/jdk/test/java/lang/invoke/t8150782/TestCls.java new file mode 100644 index 00000000000..1aec2657d0a --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestCls.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package test.java.lang.invoke.t8150782; + +import static java.lang.invoke.MethodHandles.*; + +public class TestCls { + + public static final Lookup LOOKUP = lookup(); + + private static class PrivateSIC {} + public static Class getPrivateSIC() { return PrivateSIC.class; } + public static Lookup getLookupForPrivateSIC() { return lookup(); } + +} + diff --git a/jdk/test/java/lang/invoke/t8150782/TestFindClass.java b/jdk/test/java/lang/invoke/t8150782/TestFindClass.java new file mode 100644 index 00000000000..b49118c2b16 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestFindClass.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 + * @compile TestFindClass.java TestCls.java + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestFindClass + */ +package test.java.lang.invoke.t8150782; + +import java.lang.invoke.*; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +import org.testng.annotations.*; + +public class TestFindClass { + + private static final String PACKAGE_PREFIX = "test.java.lang.invoke.t8150782."; + + private static boolean initializedClass1; + + private static class Class1 { + static { + initializedClass1 = true; + } + } + + @Test + public void initializerNotRun() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestFindClass$Class1"); + assertFalse(initializedClass1); + } + + @Test + public void returnsRequestedClass() throws IllegalAccessException, ClassNotFoundException { + Class aClass = lookup().findClass(PACKAGE_PREFIX + "TestFindClass$Class1"); + assertEquals(Class1.class, aClass); + } + + @Test(expectedExceptions = {ClassNotFoundException.class}) + public void classNotFoundExceptionTest() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestFindClass$NonExistent"); + } + + @DataProvider + Object[][] illegalAccessFind() { + return new Object[][] { + {publicLookup(), PACKAGE_PREFIX + "TestFindClass$Class1"}, + {publicLookup(), PACKAGE_PREFIX + "TestCls$PrivateSIC"} + }; + } + + /** + * Assertion: @throws IllegalAccessException if the class is not accessible, using the allowed access modes. + */ + @Test(dataProvider = "illegalAccessFind", expectedExceptions = {ClassNotFoundException.class}) + public void illegalAccessExceptionTest(Lookup lookup, String className) throws IllegalAccessException, ClassNotFoundException { + lookup.findClass(className); + } + + @Test + public void okAccess() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestCls$PrivateSIC"); + } + +} diff --git a/jdk/test/java/lang/invoke/t8150782/TestLookup.java b/jdk/test/java/lang/invoke/t8150782/TestLookup.java new file mode 100644 index 00000000000..9a3e2cd9085 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestLookup.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestLookup + */ +package test.java.lang.invoke.t8150782; + +import org.testng.annotations.Test; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +public class TestLookup { + + @Test + public void testClassLoaderChange() { + Lookup lookup = lookup(); + assertNotNull(lookup.lookupClass().getClassLoader()); + Lookup lookup2 = lookup.in(Object.class); + assertNull(lookup2.lookupClass().getClassLoader()); + } + + @Test(expectedExceptions = {ClassNotFoundException.class}) + public void testPublicCannotLoadUserClass() throws IllegalAccessException, ClassNotFoundException { + Lookup lookup = publicLookup(); + lookup.findClass("test.java.lang.invoke.t8150782.TestCls"); + } + + @Test + public void testPublicCanLoadSystemClass() throws IllegalAccessException, ClassNotFoundException { + Lookup lookup = publicLookup(); + lookup.findClass("java.util.HashMap"); + } + + @Test + public void testPublicInChangesClassLoader() { + Lookup lookup = publicLookup(); + assertNull(lookup.lookupClass().getClassLoader()); + Lookup lookup2 = lookup.in(TestCls.class); + assertNotNull(lookup2.lookupClass().getClassLoader()); + } + +} From cc3d80e38ac213233aa69b468597cf46e90c3857 Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Mon, 14 Mar 2016 08:10:44 +0100 Subject: [PATCH 081/129] 8151778: TestLookup.java fails after push of JDK-8150782 Reviewed-by: darcy --- jdk/test/java/lang/invoke/t8150782/TestLookup.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/test/java/lang/invoke/t8150782/TestLookup.java b/jdk/test/java/lang/invoke/t8150782/TestLookup.java index 9a3e2cd9085..833ac70f254 100644 --- a/jdk/test/java/lang/invoke/t8150782/TestLookup.java +++ b/jdk/test/java/lang/invoke/t8150782/TestLookup.java @@ -24,6 +24,7 @@ */ /* @test + * @compile TestLookup.java TestCls.java * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestLookup */ package test.java.lang.invoke.t8150782; From c53d88d41f668950d44ef7c4f1059c43ea9dab8f Mon Sep 17 00:00:00 2001 From: Amy Lu Date: Mon, 14 Mar 2016 19:46:19 +0800 Subject: [PATCH 082/129] 8151798: Mark java/util/TimeZone/Bug6772689.java as intermittently failing and demote to tier2 Reviewed-by: lancea --- jdk/test/TEST.groups | 2 ++ jdk/test/java/util/TimeZone/Bug6772689.java | 1 + 2 files changed, 3 insertions(+) diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index ea9a6d6fa7e..8b3a337c346 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -32,6 +32,7 @@ tier1 = \ -java/util/WeakHashMap/GCDuringIteration.java \ -java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \ -java/util/concurrent/forkjoin/FJExceptionTableLeak.java \ + -java/util/TimeZone/Bug6772689.java \ sun/nio/cs/ISO8859x.java \ java/nio/Buffer \ com/sun/crypto/provider/Cipher \ @@ -42,6 +43,7 @@ tier2 = \ java/util/WeakHashMap/GCDuringIteration.java \ java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \ java/util/concurrent/forkjoin/FJExceptionTableLeak.java \ + java/util/TimeZone/Bug6772689.java \ :jdk_io \ :jdk_nio \ -sun/nio/cs/ISO8859x.java \ diff --git a/jdk/test/java/util/TimeZone/Bug6772689.java b/jdk/test/java/util/TimeZone/Bug6772689.java index f730567013d..a1ce49682b4 100644 --- a/jdk/test/java/util/TimeZone/Bug6772689.java +++ b/jdk/test/java/util/TimeZone/Bug6772689.java @@ -24,6 +24,7 @@ /* * @test * @bug 6772689 + * @key intermittent * @summary Test for standard-to-daylight transitions at midnight: * date stays on the given day. */ From c6a6f496a86de67082b1535c5e0053bf27ec45de Mon Sep 17 00:00:00 2001 From: Abhijit Roy Date: Sat, 12 Mar 2016 00:58:39 +0530 Subject: [PATCH 083/129] 8151062: Unclosed parenthesis in java.util.EnumMap.clone() Javadoc Reviewed-by: rriggs --- jdk/src/java.base/share/classes/java/util/EnumMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/classes/java/util/EnumMap.java b/jdk/src/java.base/share/classes/java/util/EnumMap.java index 686a0a9b98e..e6d63cf4ae8 100644 --- a/jdk/src/java.base/share/classes/java/util/EnumMap.java +++ b/jdk/src/java.base/share/classes/java/util/EnumMap.java @@ -718,7 +718,7 @@ public class EnumMap, V> extends AbstractMap } /** - * Returns a shallow copy of this enum map. (The values themselves + * Returns a shallow copy of this enum map. The values themselves * are not cloned. * * @return a shallow copy of this enum map From 887760ee885c5aa796e625e356f67a501f6f65ec Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 14 Mar 2016 10:48:18 -0700 Subject: [PATCH 084/129] 8151835: Mark SmallPrimeExponentP.java as intermittently failing Reviewed-by: vinnie --- jdk/test/sun/security/mscapi/SmallPrimeExponentP.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java b/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java index 1ee0f5bb069..0013bd86e03 100644 --- a/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java +++ b/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java @@ -32,6 +32,7 @@ import java.security.interfaces.RSAPrivateCrtKey; /* * @test * @bug 8023546 + * @key intermittent * @modules java.base/sun.security.x509 * java.base/sun.security.tools.keytool * @summary sun/security/mscapi/ShortRSAKey1024.sh fails intermittently From 04c17721d6d45ba7426ff63f0f76f23a39dbccc3 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Mon, 14 Mar 2016 16:13:09 -0700 Subject: [PATCH 085/129] 8151847: rmic should support v53 classfiles Reviewed-by: alanb --- .../share/classes/sun/tools/java/RuntimeConstants.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/jdk.rmic/share/classes/sun/tools/java/RuntimeConstants.java b/jdk/src/jdk.rmic/share/classes/sun/tools/java/RuntimeConstants.java index 87fa33f6197..1c7ada16f06 100644 --- a/jdk/src/jdk.rmic/share/classes/sun/tools/java/RuntimeConstants.java +++ b/jdk/src/jdk.rmic/share/classes/sun/tools/java/RuntimeConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,7 @@ public interface RuntimeConstants { /* Class File Constants */ int JAVA_MAGIC = 0xcafebabe; int JAVA_MIN_SUPPORTED_VERSION = 45; - int JAVA_MAX_SUPPORTED_VERSION = 52; + int JAVA_MAX_SUPPORTED_VERSION = 53; int JAVA_MAX_SUPPORTED_MINOR_VERSION = 0; /* Generate class file version for 1.1 by default */ From 569de7b0ea85f9bd95e0bc53966f329f60a9dfec Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 15 Mar 2016 12:38:35 +0800 Subject: [PATCH 086/129] 8151785: Doc typo in src/../java/util/stream/PipelineHelper.java Change from "intoWrapped" to "copyInto". Reviewed-by: rriggs --- .../share/classes/java/util/stream/PipelineHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java b/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java index 081f68d1a0e..8d989930386 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java +++ b/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java @@ -98,7 +98,7 @@ abstract class PipelineHelper { * @implSpec * The implementation behaves as if: *

{@code
-     *     intoWrapped(wrapSink(sink), spliterator);
+     *     copyInto(wrapSink(sink), spliterator);
      * }
* * @param sink the {@code Sink} to receive the results From 99bfb14042e8d9ba3aa28dcdd015e0a2042f0a5f Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Tue, 1 Mar 2016 12:33:04 -0800 Subject: [PATCH 087/129] 8147755: ASM should create correct constant tag for invokestatic on handle point to interface static method Updates asm to v5.1 Reviewed-by: forax --- .../org/objectweb/asm/ClassReader.java | 27 +- .../org/objectweb/asm/ClassWriter.java | 47 +- .../jdk/internal/org/objectweb/asm/Frame.java | 2 +- .../internal/org/objectweb/asm/Handle.java | 60 +- .../jdk/internal/org/objectweb/asm/Label.java | 9 +- .../org/objectweb/asm/MethodVisitor.java | 19 +- .../org/objectweb/asm/MethodWriter.java | 14 +- .../jdk/internal/org/objectweb/asm/Type.java | 14 +- .../internal/org/objectweb/asm/TypePath.java | 8 +- .../org/objectweb/asm/TypeReference.java | 44 +- .../objectweb/asm/commons/AdviceAdapter.java | 4 +- .../asm/commons/AnnotationRemapper.java | 108 +++ .../objectweb/asm/commons/ClassRemapper.java | 161 ++++ .../objectweb/asm/commons/FieldRemapper.java | 100 +++ .../asm/commons/InstructionAdapter.java | 2 +- .../asm/commons/LocalVariablesSorter.java | 14 - .../objectweb/asm/commons/MethodRemapper.java | 252 ++++++ .../org/objectweb/asm/commons/Remapper.java | 23 +- .../commons/RemappingAnnotationAdapter.java | 2 + .../asm/commons/RemappingClassAdapter.java | 2 + .../asm/commons/RemappingFieldAdapter.java | 2 + .../asm/commons/RemappingMethodAdapter.java | 2 + .../commons/RemappingSignatureAdapter.java | 2 + .../asm/commons/SerialVersionUIDAdder.java | 7 +- .../asm/commons/SignatureRemapper.java | 188 +++++ .../objectweb/asm/commons/SimpleRemapper.java | 6 + .../asm/signature/SignatureVisitor.java | 8 +- .../asm/signature/SignatureWriter.java | 4 +- .../org/objectweb/asm/tree/InsnList.java | 3 + .../org/objectweb/asm/util/ASMifier.java | 12 +- .../asm/util/CheckMethodAdapter.java | 3 + .../org/objectweb/asm/util/Printer.java | 786 ++++++++++++++++-- .../objectweb/asm/util/TraceClassVisitor.java | 26 +- .../asm/util/TraceSignatureVisitor.java | 14 +- .../internal/org/objectweb/asm/version.txt | 8 +- 35 files changed, 1773 insertions(+), 210 deletions(-) create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java index c9bf9d30225..523851fd70a 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java @@ -1199,7 +1199,14 @@ public class ClassReader { if (labels[label] == null) { readLabel(label, labels).status |= Label.DEBUG; } - labels[label].line = readUnsignedShort(v + 12); + Label l = labels[label]; + while (l.line > 0) { + if (l.next == null) { + l.next = new Label(); + } + l = l.next; + } + l.line = readUnsignedShort(v + 12); v += 4; } } @@ -1314,9 +1321,15 @@ public class ClassReader { // visits the label and line number for this offset, if any Label l = labels[offset]; if (l != null) { + Label next = l.next; + l.next = null; mv.visitLabel(l); if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) { mv.visitLineNumber(l.line, l); + while (next != null) { + mv.visitLineNumber(next.line, l); + next = next.next; + } } } @@ -1857,8 +1870,7 @@ public class ClassReader { v += 2; break; case 'B': // pointer to CONSTANT_Byte - av.visit(name, - (byte) readInt(items[readUnsignedShort(v)])); + av.visit(name, (byte) readInt(items[readUnsignedShort(v)])); v += 2; break; case 'Z': // pointer to CONSTANT_Boolean @@ -1868,13 +1880,11 @@ public class ClassReader { v += 2; break; case 'S': // pointer to CONSTANT_Short - av.visit(name, - (short) readInt(items[readUnsignedShort(v)])); + av.visit(name, (short) readInt(items[readUnsignedShort(v)])); v += 2; break; case 'C': // pointer to CONSTANT_Char - av.visit(name, - (char) readInt(items[readUnsignedShort(v)])); + av.visit(name, (char) readInt(items[readUnsignedShort(v)])); v += 2; break; case 's': // pointer to CONSTANT_Utf8 @@ -2515,11 +2525,12 @@ public class ClassReader { int tag = readByte(index); int[] items = this.items; int cpIndex = items[readUnsignedShort(index + 1)]; + boolean itf = b[cpIndex - 1] == ClassWriter.IMETH; String owner = readClass(cpIndex, buf); cpIndex = items[readUnsignedShort(cpIndex + 2)]; String name = readUTF8(cpIndex, buf); String desc = readUTF8(cpIndex + 2, buf); - return new Handle(tag, owner, name, desc); + return new Handle(tag, owner, name, desc, itf); } } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java index f5b24254ece..2e3d62b0369 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java @@ -1081,7 +1081,7 @@ public class ClassWriter extends ClassVisitor { } } else if (cst instanceof Handle) { Handle h = (Handle) cst; - return newHandleItem(h.tag, h.owner, h.name, h.desc); + return newHandleItem(h.tag, h.owner, h.name, h.desc, h.itf); } else { throw new IllegalArgumentException("value " + cst); } @@ -1216,10 +1216,12 @@ public class ClassWriter extends ClassVisitor { * the name of the field or method. * @param desc * the descriptor of the field or method. + * @param itf + * true if the owner is an interface. * @return a new or an already existing method type reference item. */ Item newHandleItem(final int tag, final String owner, final String name, - final String desc) { + final String desc, final boolean itf) { key4.set(HANDLE_BASE + tag, owner, name, desc); Item result = get(key4); if (result == null) { @@ -1228,8 +1230,7 @@ public class ClassWriter extends ClassVisitor { } else { put112(HANDLE, tag, - newMethod(owner, name, desc, - tag == Opcodes.H_INVOKEINTERFACE)); + newMethod(owner, name, desc, itf)); } result = new Item(index++, key4); put(result); @@ -1259,10 +1260,44 @@ public class ClassWriter extends ClassVisitor { * the descriptor of the field or method. * @return the index of a new or already existing method type reference * item. + * + * @deprecated this method is superseded by + * {@link #newHandle(int, String, String, String, boolean)}. */ + @Deprecated public int newHandle(final int tag, final String owner, final String name, final String desc) { - return newHandleItem(tag, owner, name, desc).index; + return newHandle(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE); + } + + /** + * Adds a handle to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters. + * + * @param tag + * the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, + * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, + * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, + * {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner + * the internal name of the field or method owner class. + * @param name + * the name of the field or method. + * @param desc + * the descriptor of the field or method. + * @param itf + * true if the owner is an interface. + * @return the index of a new or already existing method type reference + * item. + */ + public int newHandle(final int tag, final String owner, final String name, + final String desc, final boolean itf) { + return newHandleItem(tag, owner, name, desc, itf).index; } /** @@ -1294,7 +1329,7 @@ public class ClassWriter extends ClassVisitor { int hashCode = bsm.hashCode(); bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, - bsm.desc)); + bsm.desc, bsm.isInterface())); int argsLength = bsmArgs.length; bootstrapMethods.putShort(argsLength); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java index bb7ff8f5147..811b74c7242 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java @@ -192,7 +192,7 @@ final class Frame { private static final int LOCAL = 0x2000000; /** - * Kind of the types that are relative to the stack of an input stack + * Kind of the the types that are relative to the stack of an input stack * map frame. The value of such types is a position relatively to the top of * this stack. */ diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java index e8b2859b05d..407c1d99774 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java @@ -93,6 +93,12 @@ public final class Handle { */ final String desc; + + /** + * Indicate if the owner is an interface or not. + */ + final boolean itf; + /** * Constructs a new field or method handle. * @@ -113,12 +119,44 @@ public final class Handle { * @param desc * the descriptor of the field or method designated by this * handle. + * + * @deprecated this constructor has been superseded + * by {@link #Handle(int, String, String, String, boolean)}. */ + @Deprecated public Handle(int tag, String owner, String name, String desc) { + this(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE); + } + + /** + * Constructs a new field or method handle. + * + * @param tag + * the kind of field or method designated by this Handle. Must be + * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, + * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, + * {@link Opcodes#H_INVOKEVIRTUAL}, + * {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner + * the internal name of the class that owns the field or method + * designated by this handle. + * @param name + * the name of the field or method designated by this handle. + * @param desc + * the descriptor of the field or method designated by this + * handle. + * @param itf + * true if the owner is an interface. + */ + public Handle(int tag, String owner, String name, String desc, boolean itf) { this.tag = tag; this.owner = owner; this.name = name; this.desc = desc; + this.itf = itf; } /** @@ -164,6 +202,17 @@ public final class Handle { return desc; } + /** + * Returns true if the owner of the field or method designated + * by this handle is an interface. + * + * @return true if the owner of the field or method designated + * by this handle is an interface. + */ + public boolean isInterface() { + return itf; + } + @Override public boolean equals(Object obj) { if (obj == this) { @@ -173,13 +222,13 @@ public final class Handle { return false; } Handle h = (Handle) obj; - return tag == h.tag && owner.equals(h.owner) && name.equals(h.name) - && desc.equals(h.desc); + return tag == h.tag && itf == h.itf && owner.equals(h.owner) + && name.equals(h.name) && desc.equals(h.desc); } @Override public int hashCode() { - return tag + owner.hashCode() * name.hashCode() * desc.hashCode(); + return tag + (itf? 64: 0) + owner.hashCode() * name.hashCode() * desc.hashCode(); } /** @@ -187,13 +236,16 @@ public final class Handle { * representation is: * *
+     * for a reference to a class:
      * owner '.' name desc ' ' '(' tag ')'
+     * for a reference to an interface:
+     * owner '.' name desc ' ' '(' tag ' ' itf ')'
      * 
* * . As this format is unambiguous, it can be parsed if necessary. */ @Override public String toString() { - return owner + '.' + name + desc + " (" + tag + ')'; + return owner + '.' + name + desc + " (" + tag + (itf? " itf": "") + ')'; } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java index bbea0001235..63e42a020bc 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java @@ -160,7 +160,11 @@ public class Label { int status; /** - * The line number corresponding to this label, if known. + * The line number corresponding to this label, if known. If there are + * several lines, each line is stored in a separate label, all linked via + * their next field (these links are created in ClassReader and removed just + * before visitLabel is called, so that this does not impact the rest of the + * code). */ int line; @@ -268,7 +272,8 @@ public class Label { * The next basic block in the basic block stack. This stack is used in the * main loop of the fix point algorithm used in the second step of the * control flow analysis algorithms. It is also used in - * {@link #visitSubroutine} to avoid using a recursive method. + * {@link #visitSubroutine} to avoid using a recursive method, and in + * ClassReader to temporarily store multiple source lines for a label. * * @see MethodWriter#visitMaxs */ diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java index 0bb1a05b805..1448067a467 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java @@ -62,15 +62,16 @@ package jdk.internal.org.objectweb.asm; * A visitor to visit a Java method. The methods of this class must be called in * the following order: ( visitParameter )* [ * visitAnnotationDefault ] ( visitAnnotation | - * visitTypeAnnotation | visitAttribute )* [ - * visitCode ( visitFrame | visitXInsn | - * visitLabel | visitInsnAnnotation | - * visitTryCatchBlock | visitTryCatchBlockAnnotation | - * visitLocalVariable | visitLocalVariableAnnotation | - * visitLineNumber )* visitMaxs ] visitEnd. In - * addition, the visitXInsn and visitLabel methods must - * be called in the sequential order of the bytecode instructions of the visited - * code, visitInsnAnnotation must be called after the annotated + * visitParameterAnnotation visitTypeAnnotation | + * visitAttribute )* [ visitCode ( visitFrame | + * visitXInsn | visitLabel | + * visitInsnAnnotation | visitTryCatchBlock | + * visitTryCatchAnnotation | visitLocalVariable | + * visitLocalVariableAnnotation | visitLineNumber )* + * visitMaxs ] visitEnd. In addition, the + * visitXInsn and visitLabel methods must be called in + * the sequential order of the bytecode instructions of the visited code, + * visitInsnAnnotation must be called after the annotated * instruction, visitTryCatchBlock must be called before the * labels passed as arguments have been visited, * visitTryCatchBlockAnnotation must be called after the diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java index e02fad465d9..c2e4031e304 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java @@ -2061,7 +2061,7 @@ class MethodWriter extends MethodVisitor { } int size = 8; if (code.length > 0) { - if (code.length > 65536) { + if (code.length > 65535) { throw new RuntimeException("Method code too large!"); } cw.newUTF8("Code"); @@ -2735,11 +2735,13 @@ class MethodWriter extends MethodVisitor { l = l.successor; } // Update the offsets in the uninitialized types - for (i = 0; i < cw.typeTable.length; ++i) { - Item item = cw.typeTable[i]; - if (item != null && item.type == ClassWriter.TYPE_UNINIT) { - item.intVal = getNewOffset(allIndexes, allSizes, 0, - item.intVal); + if (cw.typeTable != null) { + for (i = 0; i < cw.typeTable.length; ++i) { + Item item = cw.typeTable[i]; + if (item != null && item.type == ClassWriter.TYPE_UNINIT) { + item.intVal = getNewOffset(allIndexes, allSizes, 0, + item.intVal); + } } } // The stack map frames are not serialized yet, so we don't need diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java index 633a4a024ea..056ace15fa8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java @@ -654,7 +654,7 @@ public class Type { * @return the descriptor corresponding to this Java type. */ public String getDescriptor() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); getDescriptor(buf); return buf.toString(); } @@ -672,7 +672,7 @@ public class Type { */ public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append('('); for (int i = 0; i < argumentTypes.length; ++i) { argumentTypes[i].getDescriptor(buf); @@ -689,7 +689,7 @@ public class Type { * @param buf * the string buffer to which the descriptor must be appended. */ - private void getDescriptor(final StringBuffer buf) { + private void getDescriptor(final StringBuilder buf) { if (this.buf == null) { // descriptor is in byte 3 of 'off' for primitive types (buf == // null) @@ -729,7 +729,7 @@ public class Type { * @return the descriptor corresponding to the given class. */ public static String getDescriptor(final Class c) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); getDescriptor(buf, c); return buf.toString(); } @@ -743,7 +743,7 @@ public class Type { */ public static String getConstructorDescriptor(final Constructor c) { Class[] parameters = c.getParameterTypes(); - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append('('); for (int i = 0; i < parameters.length; ++i) { getDescriptor(buf, parameters[i]); @@ -760,7 +760,7 @@ public class Type { */ public static String getMethodDescriptor(final Method m) { Class[] parameters = m.getParameterTypes(); - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append('('); for (int i = 0; i < parameters.length; ++i) { getDescriptor(buf, parameters[i]); @@ -778,7 +778,7 @@ public class Type { * @param c * the class whose descriptor must be computed. */ - private static void getDescriptor(final StringBuffer buf, final Class c) { + private static void getDescriptor(final StringBuilder buf, final Class c) { Class d = c; while (true) { if (d.isPrimitive()) { diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java index a48a39d8b46..31fe2bc6826 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java @@ -71,25 +71,25 @@ public class TypePath { * A type path step that steps into the element type of an array type. See * {@link #getStep getStep}. */ - public static final int ARRAY_ELEMENT = 0; + public final static int ARRAY_ELEMENT = 0; /** * A type path step that steps into the nested type of a class type. See * {@link #getStep getStep}. */ - public static final int INNER_TYPE = 1; + public final static int INNER_TYPE = 1; /** * A type path step that steps into the bound of a wildcard type. See * {@link #getStep getStep}. */ - public static final int WILDCARD_BOUND = 2; + public final static int WILDCARD_BOUND = 2; /** * A type path step that steps into a type argument of a generic type. See * {@link #getStep getStep}. */ - public static final int TYPE_ARGUMENT = 3; + public final static int TYPE_ARGUMENT = 3; /** * The byte array where the path is stored, in Java class file format. diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java index b366df0afb7..4caf8f10db0 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java @@ -74,133 +74,133 @@ public class TypeReference { * The sort of type references that target a type parameter of a generic * class. See {@link #getSort getSort}. */ - public static final int CLASS_TYPE_PARAMETER = 0x00; + public final static int CLASS_TYPE_PARAMETER = 0x00; /** * The sort of type references that target a type parameter of a generic * method. See {@link #getSort getSort}. */ - public static final int METHOD_TYPE_PARAMETER = 0x01; + public final static int METHOD_TYPE_PARAMETER = 0x01; /** * The sort of type references that target the super class of a class or one * of the interfaces it implements. See {@link #getSort getSort}. */ - public static final int CLASS_EXTENDS = 0x10; + public final static int CLASS_EXTENDS = 0x10; /** * The sort of type references that target a bound of a type parameter of a * generic class. See {@link #getSort getSort}. */ - public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11; + public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11; /** * The sort of type references that target a bound of a type parameter of a * generic method. See {@link #getSort getSort}. */ - public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12; + public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12; /** * The sort of type references that target the type of a field. See * {@link #getSort getSort}. */ - public static final int FIELD = 0x13; + public final static int FIELD = 0x13; /** * The sort of type references that target the return type of a method. See * {@link #getSort getSort}. */ - public static final int METHOD_RETURN = 0x14; + public final static int METHOD_RETURN = 0x14; /** * The sort of type references that target the receiver type of a method. * See {@link #getSort getSort}. */ - public static final int METHOD_RECEIVER = 0x15; + public final static int METHOD_RECEIVER = 0x15; /** * The sort of type references that target the type of a formal parameter of * a method. See {@link #getSort getSort}. */ - public static final int METHOD_FORMAL_PARAMETER = 0x16; + public final static int METHOD_FORMAL_PARAMETER = 0x16; /** * The sort of type references that target the type of an exception declared * in the throws clause of a method. See {@link #getSort getSort}. */ - public static final int THROWS = 0x17; + public final static int THROWS = 0x17; /** * The sort of type references that target the type of a local variable in a * method. See {@link #getSort getSort}. */ - public static final int LOCAL_VARIABLE = 0x40; + public final static int LOCAL_VARIABLE = 0x40; /** * The sort of type references that target the type of a resource variable * in a method. See {@link #getSort getSort}. */ - public static final int RESOURCE_VARIABLE = 0x41; + public final static int RESOURCE_VARIABLE = 0x41; /** * The sort of type references that target the type of the exception of a * 'catch' clause in a method. See {@link #getSort getSort}. */ - public static final int EXCEPTION_PARAMETER = 0x42; + public final static int EXCEPTION_PARAMETER = 0x42; /** * The sort of type references that target the type declared in an * 'instanceof' instruction. See {@link #getSort getSort}. */ - public static final int INSTANCEOF = 0x43; + public final static int INSTANCEOF = 0x43; /** * The sort of type references that target the type of the object created by * a 'new' instruction. See {@link #getSort getSort}. */ - public static final int NEW = 0x44; + public final static int NEW = 0x44; /** * The sort of type references that target the receiver type of a * constructor reference. See {@link #getSort getSort}. */ - public static final int CONSTRUCTOR_REFERENCE = 0x45; + public final static int CONSTRUCTOR_REFERENCE = 0x45; /** * The sort of type references that target the receiver type of a method * reference. See {@link #getSort getSort}. */ - public static final int METHOD_REFERENCE = 0x46; + public final static int METHOD_REFERENCE = 0x46; /** * The sort of type references that target the type declared in an explicit * or implicit cast instruction. See {@link #getSort getSort}. */ - public static final int CAST = 0x47; + public final static int CAST = 0x47; /** * The sort of type references that target a type parameter of a generic * constructor in a constructor call. See {@link #getSort getSort}. */ - public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; + public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; /** * The sort of type references that target a type parameter of a generic * method in a method call. See {@link #getSort getSort}. */ - public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; + public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; /** * The sort of type references that target a type parameter of a generic * constructor in a constructor reference. See {@link #getSort getSort}. */ - public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; + public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; /** * The sort of type references that target a type parameter of a generic * method in a method reference. See {@link #getSort getSort}. */ - public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; + public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; /** * The type reference value in Java class file format. diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java index c07917784df..00dccd549f0 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java @@ -388,10 +388,10 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } break; case PUTFIELD: + popValue(); popValue(); if (longOrDouble) { popValue(); - popValue(); } break; // case GETFIELD: @@ -619,7 +619,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } /** - * Called at the beginning of the method or after super class class call in + * Called at the beginning of the method or after super class call in * the constructor.
*
* diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java new file mode 100644 index 00000000000..3482ac95f6c --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java @@ -0,0 +1,108 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/** + * An {@link AnnotationVisitor} adapter for type remapping. + * + * @author Eugene Kuleshov + */ +public class AnnotationRemapper extends AnnotationVisitor { + + protected final Remapper remapper; + + public AnnotationRemapper(final AnnotationVisitor av, + final Remapper remapper) { + this(Opcodes.ASM5, av, remapper); + } + + protected AnnotationRemapper(final int api, final AnnotationVisitor av, + final Remapper remapper) { + super(api, av); + this.remapper = remapper; + } + + @Override + public void visit(String name, Object value) { + av.visit(name, remapper.mapValue(value)); + } + + @Override + public void visitEnum(String name, String desc, String value) { + av.visitEnum(name, remapper.mapDesc(desc), value); + } + + @Override + public AnnotationVisitor visitAnnotation(String name, String desc) { + AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc)); + return v == null ? null : (v == av ? this : new AnnotationRemapper(v, + remapper)); + } + + @Override + public AnnotationVisitor visitArray(String name) { + AnnotationVisitor v = av.visitArray(name); + return v == null ? null : (v == av ? this : new AnnotationRemapper(v, + remapper)); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java new file mode 100644 index 00000000000..8a8ea738ae9 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java @@ -0,0 +1,161 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.TypePath; + +/** + * A {@link ClassVisitor} for type remapping. + * + * @author Eugene Kuleshov + */ +public class ClassRemapper extends ClassVisitor { + + protected final Remapper remapper; + + protected String className; + + public ClassRemapper(final ClassVisitor cv, final Remapper remapper) { + this(Opcodes.ASM5, cv, remapper); + } + + protected ClassRemapper(final int api, final ClassVisitor cv, + final Remapper remapper) { + super(api, cv); + this.remapper = remapper; + } + + @Override + public void visit(int version, int access, String name, String signature, + String superName, String[] interfaces) { + this.className = name; + super.visit(version, access, remapper.mapType(name), remapper + .mapSignature(signature, false), remapper.mapType(superName), + interfaces == null ? null : remapper.mapTypes(interfaces)); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), + visible); + return av == null ? null : createAnnotationRemapper(av); + } + + @Override + public AnnotationVisitor visitTypeAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? null : createAnnotationRemapper(av); + } + + @Override + public FieldVisitor visitField(int access, String name, String desc, + String signature, Object value) { + FieldVisitor fv = super.visitField(access, + remapper.mapFieldName(className, name, desc), + remapper.mapDesc(desc), remapper.mapSignature(signature, true), + remapper.mapValue(value)); + return fv == null ? null : createFieldRemapper(fv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { + String newDesc = remapper.mapMethodDesc(desc); + MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName( + className, name, desc), newDesc, remapper.mapSignature( + signature, false), + exceptions == null ? null : remapper.mapTypes(exceptions)); + return mv == null ? null : createMethodRemapper(mv); + } + + @Override + public void visitInnerClass(String name, String outerName, + String innerName, int access) { + // TODO should innerName be changed? + super.visitInnerClass(remapper.mapType(name), outerName == null ? null + : remapper.mapType(outerName), innerName, access); + } + + @Override + public void visitOuterClass(String owner, String name, String desc) { + super.visitOuterClass(remapper.mapType(owner), name == null ? null + : remapper.mapMethodName(owner, name, desc), + desc == null ? null : remapper.mapMethodDesc(desc)); + } + + protected FieldVisitor createFieldRemapper(FieldVisitor fv) { + return new FieldRemapper(fv, remapper); + } + + protected MethodVisitor createMethodRemapper(MethodVisitor mv) { + return new MethodRemapper(mv, remapper); + } + + protected AnnotationVisitor createAnnotationRemapper(AnnotationVisitor av) { + return new AnnotationRemapper(av, remapper); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java new file mode 100644 index 00000000000..13f8b7fd154 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java @@ -0,0 +1,100 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.TypePath; + +/** + * A {@link FieldVisitor} adapter for type remapping. + * + * @author Eugene Kuleshov + */ +public class FieldRemapper extends FieldVisitor { + + private final Remapper remapper; + + public FieldRemapper(final FieldVisitor fv, final Remapper remapper) { + this(Opcodes.ASM5, fv, remapper); + } + + protected FieldRemapper(final int api, final FieldVisitor fv, + final Remapper remapper) { + super(api, fv); + this.remapper = remapper; + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc), + visible); + return av == null ? null : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitTypeAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? null : new AnnotationRemapper(av, remapper); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java index 8ecb1c9c4b1..2df144ef70c 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java @@ -73,7 +73,7 @@ import jdk.internal.org.objectweb.asm.Type; */ public class InstructionAdapter extends MethodVisitor { - public static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); + public final static Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); /** * Creates a new {@link InstructionAdapter}. Subclasses must not use this diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java index 5d02c53768d..7aad39658e8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java @@ -104,11 +104,6 @@ public class LocalVariablesSorter extends MethodVisitor { */ protected int nextLocal; - /** - * Indicates if at least one local variable has moved due to remapping. - */ - private boolean changed; - /** * Creates a new {@link LocalVariablesSorter}. Subclasses must not use * this constructor. Instead, they must use the @@ -228,11 +223,6 @@ public class LocalVariablesSorter extends MethodVisitor { "ClassReader.accept() should be called with EXPAND_FRAMES flag"); } - if (!changed) { // optimization for the case where mapping = identity - mv.visitFrame(type, nLocal, local, nStack, stack); - return; - } - // creates a copy of newLocals Object[] oldLocals = new Object[newLocals.length]; System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length); @@ -328,7 +318,6 @@ public class LocalVariablesSorter extends MethodVisitor { int local = newLocalMapping(type); setLocalType(local, type); setFrameLocal(local, t); - changed = true; return local; } @@ -396,9 +385,6 @@ public class LocalVariablesSorter extends MethodVisitor { } else { value--; } - if (value != var) { - changed = true; - } return value; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java new file mode 100644 index 00000000000..486cc6b7c57 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java @@ -0,0 +1,252 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.TypePath; + +/** + * A {@link LocalVariablesSorter} for type mapping. + * + * @author Eugene Kuleshov + */ +public class MethodRemapper extends MethodVisitor { + + protected final Remapper remapper; + + public MethodRemapper(final MethodVisitor mv, final Remapper remapper) { + this(Opcodes.ASM5, mv, remapper); + } + + protected MethodRemapper(final int api, final MethodVisitor mv, + final Remapper remapper) { + super(api, mv); + this.remapper = remapper; + } + + @Override + public AnnotationVisitor visitAnnotationDefault() { + AnnotationVisitor av = super.visitAnnotationDefault(); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), + visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitTypeAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitParameterAnnotation(int parameter, + String desc, boolean visible) { + AnnotationVisitor av = super.visitParameterAnnotation(parameter, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public void visitFrame(int type, int nLocal, Object[] local, int nStack, + Object[] stack) { + super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack, + remapEntries(nStack, stack)); + } + + private Object[] remapEntries(int n, Object[] entries) { + for (int i = 0; i < n; i++) { + if (entries[i] instanceof String) { + Object[] newEntries = new Object[n]; + if (i > 0) { + System.arraycopy(entries, 0, newEntries, 0, i); + } + do { + Object t = entries[i]; + newEntries[i++] = t instanceof String ? remapper + .mapType((String) t) : t; + } while (i < n); + return newEntries; + } + } + return entries; + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, + String desc) { + super.visitFieldInsn(opcode, remapper.mapType(owner), + remapper.mapFieldName(owner, name, desc), + remapper.mapDesc(desc)); + } + + @Deprecated + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, String owner, String name, + String desc, boolean itf) { + // Calling super.visitMethodInsn requires to call the correct version + // depending on this.api (otherwise infinite loops can occur). To + // simplify and to make it easier to automatically remove the backward + // compatibility code, we inline the code of the overridden method here. + // IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN + // LocalVariableSorter. + if (mv != null) { + mv.visitMethodInsn(opcode, remapper.mapType(owner), + remapper.mapMethodName(owner, name, desc), + remapper.mapMethodDesc(desc), itf); + } + } + + @Override + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { + for (int i = 0; i < bsmArgs.length; i++) { + bsmArgs[i] = remapper.mapValue(bsmArgs[i]); + } + super.visitInvokeDynamicInsn( + remapper.mapInvokeDynamicMethodName(name, desc), + remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm), + bsmArgs); + } + + @Override + public void visitTypeInsn(int opcode, String type) { + super.visitTypeInsn(opcode, remapper.mapType(type)); + } + + @Override + public void visitLdcInsn(Object cst) { + super.visitLdcInsn(remapper.mapValue(cst)); + } + + @Override + public void visitMultiANewArrayInsn(String desc, int dims) { + super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims); + } + + @Override + public AnnotationVisitor visitInsnAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitInsnAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public void visitTryCatchBlock(Label start, Label end, Label handler, + String type) { + super.visitTryCatchBlock(start, end, handler, type == null ? null + : remapper.mapType(type)); + } + + @Override + public AnnotationVisitor visitTryCatchAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTryCatchAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public void visitLocalVariable(String name, String desc, String signature, + Label start, Label end, int index) { + super.visitLocalVariable(name, remapper.mapDesc(desc), + remapper.mapSignature(signature, true), start, end, index); + } + + @Override + public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, + TypePath typePath, Label[] start, Label[] end, int[] index, + String desc, boolean visible) { + AnnotationVisitor av = super.visitLocalVariableAnnotation(typeRef, + typePath, start, end, index, remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java index d5edd06363f..b90aee05590 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java @@ -168,17 +168,19 @@ public abstract class Remapper { Handle h = (Handle) value; return new Handle(h.getTag(), mapType(h.getOwner()), mapMethodName( h.getOwner(), h.getName(), h.getDesc()), - mapMethodDesc(h.getDesc())); + mapMethodDesc(h.getDesc()), h.isInterface()); } return value; } /** - * + * @param signature + * signature for mapper * @param typeSignature * true if signature is a FieldTypeSignature, such as the * signature parameter of the ClassVisitor.visitField or * MethodVisitor.visitLocalVariable methods + * @return signature rewritten as a string */ public String mapSignature(String signature, boolean typeSignature) { if (signature == null) { @@ -186,7 +188,7 @@ public abstract class Remapper { } SignatureReader r = new SignatureReader(signature); SignatureWriter w = new SignatureWriter(); - SignatureVisitor a = createRemappingSignatureAdapter(w); + SignatureVisitor a = createSignatureRemapper(w); if (typeSignature) { r.acceptType(a); } else { @@ -195,9 +197,18 @@ public abstract class Remapper { return w.toString(); } + /** + * @deprecated use {@link #createSignatureRemapper} instead. + */ + @Deprecated protected SignatureVisitor createRemappingSignatureAdapter( SignatureVisitor v) { - return new RemappingSignatureAdapter(v, this); + return new SignatureRemapper(v, this); + } + + protected SignatureVisitor createSignatureRemapper( + SignatureVisitor v) { + return createRemappingSignatureAdapter(v); } /** @@ -245,6 +256,10 @@ public abstract class Remapper { /** * Map type name to the new name. Subclasses can override. + * + * @param typeName + * the type name + * @return new name, default implementation is the identity. */ public String map(String typeName) { return typeName; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java index b9a1bc874aa..af0fe2b4fb4 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java @@ -65,8 +65,10 @@ import jdk.internal.org.objectweb.asm.Opcodes; /** * An {@link AnnotationVisitor} adapter for type remapping. * + * //@deprecated use {@link AnnotationRemapper} instead. * @author Eugene Kuleshov */ +//@Deprecated public class RemappingAnnotationAdapter extends AnnotationVisitor { protected final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java index 28b736be7a4..e36d79e931d 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java @@ -69,8 +69,10 @@ import jdk.internal.org.objectweb.asm.TypePath; /** * A {@link ClassVisitor} for type remapping. * + * @deprecated use {@link ClassRemapper} instead. * @author Eugene Kuleshov */ +@Deprecated public class RemappingClassAdapter extends ClassVisitor { protected final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java index 9d94e5ee327..8bafee1bf4a 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java @@ -67,8 +67,10 @@ import jdk.internal.org.objectweb.asm.TypePath; /** * A {@link FieldVisitor} adapter for type remapping. * + * @deprecated use {@link FieldRemapper} instead. * @author Eugene Kuleshov */ +@Deprecated public class RemappingFieldAdapter extends FieldVisitor { private final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java index d5493a1b1b5..f58963db6ef 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java @@ -69,8 +69,10 @@ import jdk.internal.org.objectweb.asm.TypePath; /** * A {@link LocalVariablesSorter} for type mapping. * + * //@deprecated use {@link MethodRemapper} instead. * @author Eugene Kuleshov */ +//@Deprecated public class RemappingMethodAdapter extends LocalVariablesSorter { protected final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java index 3b8ab02a3f1..4aa8428f344 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java @@ -65,8 +65,10 @@ import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; /** * A {@link SignatureVisitor} adapter for type mapping. * + * @deprecated use {@link SignatureRemapper} instead. * @author Eugene Kuleshov */ +@Deprecated public class RemappingSignatureAdapter extends SignatureVisitor { private final SignatureVisitor v; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java index cd407fd8063..0486710dd47 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java @@ -234,7 +234,7 @@ public class SerialVersionUIDAdder extends ClassVisitor { public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { - computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0; + computeSVUID = (access & Opcodes.ACC_ENUM) == 0; if (computeSVUID) { this.name = name; @@ -396,6 +396,11 @@ public class SerialVersionUIDAdder extends ClassVisitor { /* * 2. The class modifiers written as a 32-bit integer. */ + int access = this.access; + if ((access & Opcodes.ACC_INTERFACE) != 0) { + access = (svuidMethods.size() > 0) ? (access | Opcodes.ACC_ABSTRACT) + : (access & ~Opcodes.ACC_ABSTRACT); + } dos.writeInt(access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT)); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java new file mode 100644 index 00000000000..cf18f2bbb58 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java @@ -0,0 +1,188 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import java.util.Stack; + +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; + +/** + * A {@link SignatureVisitor} adapter for type mapping. + * + * @author Eugene Kuleshov + */ +public class SignatureRemapper extends SignatureVisitor { + + private final SignatureVisitor v; + + private final Remapper remapper; + + private Stack classNames = new Stack(); + + public SignatureRemapper(final SignatureVisitor v, final Remapper remapper) { + this(Opcodes.ASM5, v, remapper); + } + + protected SignatureRemapper(final int api, final SignatureVisitor v, + final Remapper remapper) { + super(api); + this.v = v; + this.remapper = remapper; + } + + @Override + public void visitClassType(String name) { + classNames.push(name); + v.visitClassType(remapper.mapType(name)); + } + + @Override + public void visitInnerClassType(String name) { + String outerClassName = classNames.pop(); + String className = outerClassName + '$' + name; + classNames.push(className); + String remappedOuter = remapper.mapType(outerClassName) + '$'; + String remappedName = remapper.mapType(className); + int index = remappedName.startsWith(remappedOuter) ? remappedOuter + .length() : remappedName.lastIndexOf('$') + 1; + v.visitInnerClassType(remappedName.substring(index)); + } + + @Override + public void visitFormalTypeParameter(String name) { + v.visitFormalTypeParameter(name); + } + + @Override + public void visitTypeVariable(String name) { + v.visitTypeVariable(name); + } + + @Override + public SignatureVisitor visitArrayType() { + v.visitArrayType(); + return this; + } + + @Override + public void visitBaseType(char descriptor) { + v.visitBaseType(descriptor); + } + + @Override + public SignatureVisitor visitClassBound() { + v.visitClassBound(); + return this; + } + + @Override + public SignatureVisitor visitExceptionType() { + v.visitExceptionType(); + return this; + } + + @Override + public SignatureVisitor visitInterface() { + v.visitInterface(); + return this; + } + + @Override + public SignatureVisitor visitInterfaceBound() { + v.visitInterfaceBound(); + return this; + } + + @Override + public SignatureVisitor visitParameterType() { + v.visitParameterType(); + return this; + } + + @Override + public SignatureVisitor visitReturnType() { + v.visitReturnType(); + return this; + } + + @Override + public SignatureVisitor visitSuperclass() { + v.visitSuperclass(); + return this; + } + + @Override + public void visitTypeArgument() { + v.visitTypeArgument(); + } + + @Override + public SignatureVisitor visitTypeArgument(char wildcard) { + v.visitTypeArgument(wildcard); + return this; + } + + @Override + public void visitEnd() { + v.visitEnd(); + classNames.pop(); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java index 56b9bb57dcf..ebf59f4bf53 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java @@ -85,6 +85,12 @@ public class SimpleRemapper extends Remapper { return s == null ? name : s; } + @Override + public String mapInvokeDynamicMethodName(String name, String desc) { + String s = map('.' + name + desc); + return s == null ? name : s; + } + @Override public String mapFieldName(String owner, String name, String desc) { String s = map(owner + '.' + name); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java index 9114bcd348e..8ad2de61230 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java @@ -68,7 +68,7 @@ import jdk.internal.org.objectweb.asm.Opcodes; *
    *
  • ClassSignature = ( visitFormalTypeParameter * visitClassBound? visitInterfaceBound* )* ( - * visitSuperClass visitInterface* )
  • + * visitSuperclass visitInterface* ) *
  • MethodSignature = ( visitFormalTypeParameter * visitClassBound? visitInterfaceBound* )* ( * visitParameterType* visitReturnType @@ -88,17 +88,17 @@ public abstract class SignatureVisitor { /** * Wildcard for an "extends" type argument. */ - public static final char EXTENDS = '+'; + public final static char EXTENDS = '+'; /** * Wildcard for a "super" type argument. */ - public static final char SUPER = '-'; + public final static char SUPER = '-'; /** * Wildcard for a normal type argument. */ - public static final char INSTANCEOF = '='; + public final static char INSTANCEOF = '='; /** * The ASM API version implemented by this visitor. The value of this field diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java index 0d761663ea0..a1eceb8d5c9 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java @@ -69,9 +69,9 @@ import jdk.internal.org.objectweb.asm.Opcodes; public class SignatureWriter extends SignatureVisitor { /** - * Buffer used to construct the signature. + * Builder used to construct the signature. */ - private final StringBuffer buf = new StringBuffer(); + private final StringBuilder buf = new StringBuilder(); /** * Indicates if the signature contains formal type parameters. diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/InsnList.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/InsnList.java index 8dec6eda0bd..768130c94c1 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/InsnList.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/InsnList.java @@ -205,6 +205,9 @@ public class InsnList { /** * Returns an iterator over the instructions in this list. * + * @param index + * index of instruction for the iterator to start at + * * @return an iterator over the instructions in this list. */ @SuppressWarnings("unchecked") diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java index 26e208a4cef..d7c1becfe46 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java @@ -856,7 +856,11 @@ public class ASMifier extends Printer { buf.append("{\n").append("av0 = ").append(name) .append(".visitLocalVariableAnnotation("); buf.append(typeRef); - buf.append(", TypePath.fromString(\"").append(typePath).append("\"), "); + if (typePath == null) { + buf.append(", null, "); + } else { + buf.append(", TypePath.fromString(\"").append(typePath).append("\"), "); + } buf.append("new Label[] {"); for (int i = 0; i < start.length; ++i) { buf.append(i == 0 ? " " : ", "); @@ -934,7 +938,11 @@ public class ASMifier extends Printer { buf.append("{\n").append("av0 = ").append(name).append(".") .append(method).append("("); buf.append(typeRef); - buf.append(", TypePath.fromString(\"").append(typePath).append("\"), "); + if (typePath == null) { + buf.append(", null, "); + } else { + buf.append(", TypePath.fromString(\"").append(typePath).append("\"), "); + } appendConstant(desc); buf.append(", ").append(visible).append(");\n"); text.add(buf.toString()); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java index 25673195f1c..a0afdc650a8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java @@ -437,6 +437,9 @@ public class CheckMethodAdapter extends MethodVisitor { * will not perform any data flow check (see * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}). * + * @param api + * the ASM API version implemented by this CheckMethodAdapter. + * Must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * @param mv * the method visitor to which this adapter must delegate calls. * @param labels diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java index 87e79f47e14..650e1f0b878 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java @@ -171,6 +171,10 @@ public abstract class Printer { /** * Constructs a new {@link Printer}. + * + * @param api + * the ASM API version implemented by this printer. Must be one + * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. */ protected Printer(final int api) { this.api = api; @@ -179,34 +183,103 @@ public abstract class Printer { } /** - * Class header. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visit}. + * Class header. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visit}. + * + * @param version + * the class version. + * @param access + * the class's access flags (see {@link Opcodes}). This parameter + * also indicates if the class is deprecated. + * @param name + * the internal name of the class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param signature + * the signature of this class. May be null if the class + * is not a generic one, and does not extend or implement generic + * classes or interfaces. + * @param superName + * the internal of name of the super class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * For interfaces, the super class is {@link Object}. May be + * null, but only for the {@link Object} class. + * @param interfaces + * the internal names of the class's interfaces (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * May be null. */ public abstract void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces); /** - * Class source. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitSource}. + * Class source. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitSource}. + * + * @param source + * the name of the source file from which the class was compiled. + * May be null. + * @param debug + * additional debug information to compute the correspondance + * between source and compiled elements of the class. May be + * null. */ - public abstract void visitSource(final String file, final String debug); + public abstract void visitSource(final String source, final String debug); /** - * Class outer class. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitOuterClass}. + * Class outer class. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitOuterClass}. + * + * Visits the enclosing class of the class. This method must be called only + * if the class has an enclosing class. + * + * @param owner + * internal name of the enclosing class of the class. + * @param name + * the name of the method that contains the class, or + * null if the class is not enclosed in a method of its + * enclosing class. + * @param desc + * the descriptor of the method that contains the class, or + * null if the class is not enclosed in a method of its + * enclosing class. */ public abstract void visitOuterClass(final String owner, final String name, final String desc); /** - * Class annotation. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitAnnotation}. + * Class annotation. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitAnnotation}. + * + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public abstract Printer visitClassAnnotation(final String desc, final boolean visible); /** - * Class type annotation. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitTypeAnnotation}. + * Class type annotation. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitTypeAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be + * {@link jdk.internal.org.objectweb.asm.TypeReference#CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} + * or {@link jdk.internal.org.objectweb.asm.TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitClassTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -214,26 +287,85 @@ public abstract class Printer { } /** - * Class attribute. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitAttribute}. + * Class attribute. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitAttribute}. + * + * @param attr + * an attribute. */ public abstract void visitClassAttribute(final Attribute attr); /** - * Class inner name. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitInnerClass}. + * Class inner name. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitInnerClass}. + * + * @param name + * the internal name of an inner class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param outerName + * the internal name of the class to which the inner class + * belongs (see {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * May be null for not member classes. + * @param innerName + * the (simple) name of the inner class inside its enclosing + * class. May be null for anonymous inner classes. + * @param access + * the access flags of the inner class as originally declared in + * the enclosing class. */ public abstract void visitInnerClass(final String name, final String outerName, final String innerName, final int access); /** - * Class field. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitField}. + * Class field. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitField}. + * + * @param access + * the field's access flags (see {@link Opcodes}). This parameter + * also indicates if the field is synthetic and/or deprecated. + * @param name + * the field's name. + * @param desc + * the field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param signature + * the field's signature. May be null if the field's + * type does not use generic types. + * @param value + * the field's initial value. This parameter, which may be + * null if the field does not have an initial value, + * must be an {@link Integer}, a {@link Float}, a {@link Long}, a + * {@link Double} or a {@link String} (for int, + * float, long or String fields + * respectively). This parameter is only used for static + * fields. Its value is ignored for non static fields, which + * must be initialized through bytecode instructions in + * constructors or methods. + * @return the printer */ public abstract Printer visitField(final int access, final String name, final String desc, final String signature, final Object value); /** - * Class method. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitMethod}. + * Class method. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitMethod}. + * + * @param access + * the method's access flags (see {@link Opcodes}). This + * parameter also indicates if the method is synthetic and/or + * deprecated. + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param signature + * the method's signature. May be null if the method + * parameters, return type and exceptions do not use generic + * types. + * @param exceptions + * the internal names of the method's exception classes (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). May be + * null. + * @return the printer */ public abstract Printer visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions); @@ -248,26 +380,64 @@ public abstract class Printer { // ------------------------------------------------------------------------ /** - * Annotation value. See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visit}. + * Annotation value. + * See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visit}. + * + * @param name + * the value name. + * @param value + * the actual value, whose type must be {@link Byte}, + * {@link Boolean}, {@link Character}, {@link Short}, + * {@link Integer} , {@link Long}, {@link Float}, {@link Double}, + * {@link String} or {@link jdk.internal.org.objectweb.asm.Type} + * or OBJECT or ARRAY sort. + * This value can also be an array of byte, boolean, short, char, int, + * long, float or double values (this is equivalent to using + * {@link #visitArray visitArray} and visiting each array element + * in turn, but is more convenient). */ public abstract void visit(final String name, final Object value); /** - * Annotation enum value. See - * {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitEnum}. + * Annotation enum value. + * See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitEnum}. + * + * Visits an enumeration value of the annotation. + * + * @param name + * the value name. + * @param desc + * the class descriptor of the enumeration class. + * @param value + * the actual enumeration value. */ public abstract void visitEnum(final String name, final String desc, final String value); /** - * Nested annotation value. See - * {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitAnnotation}. + * Nested annotation value. + * See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitAnnotation}. + * + * @param name + * the value name. + * @param desc + * the class descriptor of the nested annotation class. + * @return the printer */ public abstract Printer visitAnnotation(final String name, final String desc); /** - * Annotation array value. See - * {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitArray}. + * Annotation array value. + * See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitArray}. + * + * Visits an array value of the annotation. Note that arrays of primitive + * types (such as byte, boolean, short, char, int, long, float or double) + * can be passed as value to {@link #visit visit}. This is what + * {@link jdk.internal.org.objectweb.asm.ClassReader} does. + * + * @param name + * the value name. + * @return the printer */ public abstract Printer visitArray(final String name); @@ -281,15 +451,35 @@ public abstract class Printer { // ------------------------------------------------------------------------ /** - * Field annotation. See - * {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitAnnotation}. + * Field annotation. + * See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitAnnotation}. + * + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public abstract Printer visitFieldAnnotation(final String desc, final boolean visible); /** - * Field type annotation. See - * {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitTypeAnnotation}. + * Field type annotation. + * See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitTypeAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#FIELD FIELD}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitFieldTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -297,13 +487,17 @@ public abstract class Printer { } /** - * Field attribute. See - * {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitAttribute}. + * Field attribute. + * See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitAttribute}. + * + * @param attr + * an attribute. */ public abstract void visitFieldAttribute(final Attribute attr); /** - * Field end. See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitEnd}. + * Field end. + * See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitEnd}. */ public abstract void visitFieldEnd(); @@ -312,29 +506,58 @@ public abstract class Printer { // ------------------------------------------------------------------------ /** - * Method parameter. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameter(String, int)}. + * Method parameter. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameter(String, int)}. + * + * @param name + * parameter name or null if none is provided. + * @param access + * the parameter's access flags, only ACC_FINAL, + * ACC_SYNTHETIC or/and ACC_MANDATED are + * allowed (see {@link Opcodes}). */ public void visitParameter(String name, int access) { throw new RuntimeException("Must be overriden"); } /** - * Method default annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAnnotationDefault}. + * Method default annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAnnotationDefault}. + * + * @return the printer */ public abstract Printer visitAnnotationDefault(); /** - * Method annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAnnotation}. + * Method annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAnnotation}. + * + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public abstract Printer visitMethodAnnotation(final String desc, final boolean visible); /** - * Method type annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTypeAnnotation}. + * Method type annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTypeAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#FIELD FIELD}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitMethodTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -342,64 +565,225 @@ public abstract class Printer { } /** - * Method parameter annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameterAnnotation}. + * Method parameter annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameterAnnotation}. + * + * @param parameter + * the parameter index. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public abstract Printer visitParameterAnnotation(final int parameter, final String desc, final boolean visible); /** - * Method attribute. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAttribute}. + * Method attribute. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAttribute}. + * + * @param attr + * an attribute. */ public abstract void visitMethodAttribute(final Attribute attr); /** - * Method start. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitCode}. + * Method start. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitCode}. */ public abstract void visitCode(); /** - * Method stack frame. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitFrame}. + * Method stack frame. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitFrame}. + * + * Visits the current state of the local variables and operand stack + * elements. This method must(*) be called just before any + * instruction i that follows an unconditional branch instruction + * such as GOTO or THROW, that is the target of a jump instruction, or that + * starts an exception handler block. The visited types must describe the + * values of the local variables and of the operand stack elements just + * before i is executed.
    + *
    + * (*) this is mandatory only for classes whose version is greater than or + * equal to {@link Opcodes#V1_6 V1_6}.
    + *
    + * The frames of a method must be given either in expanded form, or in + * compressed form (all frames must use the same format, i.e. you must not + * mix expanded and compressed frames within a single method): + *
      + *
    • In expanded form, all frames must have the F_NEW type.
    • + *
    • In compressed form, frames are basically "deltas" from the state of + * the previous frame: + *
        + *
      • {@link Opcodes#F_SAME} representing frame with exactly the same + * locals as the previous frame and with the empty stack.
      • + *
      • {@link Opcodes#F_SAME1} representing frame with exactly the same + * locals as the previous frame and with single value on the stack ( + * nStack is 1 and stack[0] contains value for the + * type of the stack item).
      • + *
      • {@link Opcodes#F_APPEND} representing frame with current locals are + * the same as the locals in the previous frame, except that additional + * locals are defined (nLocal is 1, 2 or 3 and + * local elements contains values representing added types).
      • + *
      • {@link Opcodes#F_CHOP} representing frame with current locals are the + * same as the locals in the previous frame, except that the last 1-3 locals + * are absent and with the empty stack (nLocals is 1, 2 or 3).
      • + *
      • {@link Opcodes#F_FULL} representing complete frame data.
      • + *
      + *
    • + *
    + *
    + * In both cases the first frame, corresponding to the method's parameters + * and access flags, is implicit and must not be visited. Also, it is + * illegal to visit two or more frames for the same code location (i.e., at + * least one instruction must be visited between two calls to visitFrame). + * + * @param type + * the type of this stack map frame. Must be + * {@link Opcodes#F_NEW} for expanded frames, or + * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, + * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or + * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for + * compressed frames. + * @param nLocal + * the number of local variables in the visited frame. + * @param local + * the local variable types in this frame. This array must not be + * modified. Primitive types are represented by + * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, + * {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, + * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or + * {@link Opcodes#UNINITIALIZED_THIS} (long and double are + * represented by a single element). Reference types are + * represented by String objects (representing internal names), + * and uninitialized types by Label objects (this label + * designates the NEW instruction that created this uninitialized + * value). + * @param nStack + * the number of operand stack elements in the visited frame. + * @param stack + * the operand stack types in this frame. This array must not be + * modified. Its content has the same format as the "local" + * array. + * @throws IllegalStateException + * if a frame is visited just after another one, without any + * instruction between the two (unless this frame is a + * Opcodes#F_SAME frame, in which case it is silently ignored). */ public abstract void visitFrame(final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack); /** - * Method instruction. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInsn} - * . + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInsn} + * + * @param opcode + * the opcode of the instruction to be visited. This opcode is + * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, + * ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, + * FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, + * LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, + * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, + * SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, + * DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, + * IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, + * FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, + * IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, + * L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S, + * LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN, + * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, + * or MONITOREXIT. */ public abstract void visitInsn(final int opcode); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitIntInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitIntInsn}. + * + * @param opcode + * the opcode of the instruction to be visited. This opcode is + * either BIPUSH, SIPUSH or NEWARRAY. + * @param operand + * the operand of the instruction to be visited.
    + * When opcode is BIPUSH, operand value should be between + * Byte.MIN_VALUE and Byte.MAX_VALUE.
    + * When opcode is SIPUSH, operand value should be between + * Short.MIN_VALUE and Short.MAX_VALUE.
    + * When opcode is NEWARRAY, operand value should be one of + * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR}, + * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, + * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT}, + * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. */ public abstract void visitIntInsn(final int opcode, final int operand); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitVarInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitVarInsn}. + * + * @param opcode + * the opcode of the local variable instruction to be visited. + * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, + * ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. + * @param var + * the operand of the instruction to be visited. This operand is + * the index of a local variable. */ public abstract void visitVarInsn(final int opcode, final int var); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTypeInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTypeInsn}. + * + /** + * Visits a type instruction. A type instruction is an instruction that + * takes the internal name of a class as parameter. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. + * @param type + * the operand of the instruction to be visited. This operand + * must be the internal name of an object or array class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). */ public abstract void visitTypeInsn(final int opcode, final String type); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitFieldInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitFieldInsn}. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. + * @param owner + * the internal name of the field's owner class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param name + * the field's name. + * @param desc + * the field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). */ public abstract void visitFieldInsn(final int opcode, final String owner, final String name, final String desc); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or + * INVOKEINTERFACE. + * @param owner + * the internal name of the method's owner class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). */ @Deprecated public void visitMethodInsn(final int opcode, final String owner, @@ -413,8 +797,22 @@ public abstract class Printer { } /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or + * INVOKEINTERFACE. + * @param owner + * the internal name of the method's owner class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param itf + * if the method's owner class is an interface. */ public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc, final boolean itf) { @@ -430,59 +828,181 @@ public abstract class Printer { } /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInvokeDynamicInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInvokeDynamicInsn}. + * + * Visits an invokedynamic instruction. + * + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param bsm + * the bootstrap method. + * @param bsmArgs + * the bootstrap method constant arguments. Each argument must be + * an {@link Integer}, {@link Float}, {@link Long}, + * {@link Double}, {@link String}, {@link jdk.internal.org.objectweb.asm.Type} or {@link Handle} + * value. This method is allowed to modify the content of the + * array so a caller should expect that this array may change. */ public abstract void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitJumpInsn}. + * Method jump instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitJumpInsn}. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, + * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, + * IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. + * @param label + * the operand of the instruction to be visited. This operand is + * a label that designates the instruction to which the jump + * instruction may jump. */ public abstract void visitJumpInsn(final int opcode, final Label label); /** - * Method label. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLabel}. + * Method label. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLabel}. + * + * @param label + * a {@link Label Label} object. */ public abstract void visitLabel(final Label label); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLdcInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLdcInsn}. + * + * Visits a LDC instruction. Note that new constant types may be added in + * future versions of the Java Virtual Machine. To easily detect new + * constant types, implementations of this method should check for + * unexpected constant types, like this: + * + *
    +     * if (cst instanceof Integer) {
    +     *     // ...
    +     * } else if (cst instanceof Float) {
    +     *     // ...
    +     * } else if (cst instanceof Long) {
    +     *     // ...
    +     * } else if (cst instanceof Double) {
    +     *     // ...
    +     * } else if (cst instanceof String) {
    +     *     // ...
    +     * } else if (cst instanceof Type) {
    +     *     int sort = ((Type) cst).getSort();
    +     *     if (sort == Type.OBJECT) {
    +     *         // ...
    +     *     } else if (sort == Type.ARRAY) {
    +     *         // ...
    +     *     } else if (sort == Type.METHOD) {
    +     *         // ...
    +     *     } else {
    +     *         // throw an exception
    +     *     }
    +     * } else if (cst instanceof Handle) {
    +     *     // ...
    +     * } else {
    +     *     // throw an exception
    +     * }
    +     * 
    + * + * @param cst + * the constant to be loaded on the stack. This parameter must be + * a non null {@link Integer}, a {@link Float}, a {@link Long}, a + * {@link Double}, a {@link String}, a {@link jdk.internal.org.objectweb.asm.Type} + * of OBJECT or ARRAY sort for .class constants, for classes whose + * version is 49.0, a {@link jdk.internal.org.objectweb.asm.Type} of METHOD sort or a + * {@link Handle} for MethodType and MethodHandle constants, for + * classes whose version is 51.0. */ public abstract void visitLdcInsn(final Object cst); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitIincInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitIincInsn}. + * + * @param var + * index of the local variable to be incremented. + * @param increment + * amount to increment the local variable by. */ public abstract void visitIincInsn(final int var, final int increment); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTableSwitchInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTableSwitchInsn}. + * + * @param min + * the minimum key value. + * @param max + * the maximum key value. + * @param dflt + * beginning of the default handler block. + * @param labels + * beginnings of the handler blocks. labels[i] is the + * beginning of the handler block for the min + i key. */ public abstract void visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLookupSwitchInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLookupSwitchInsn}. + * + * @param dflt + * beginning of the default handler block. + * @param keys + * the values of the keys. + * @param labels + * beginnings of the handler blocks. labels[i] is the + * beginning of the handler block for the keys[i] key. */ public abstract void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMultiANewArrayInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMultiANewArrayInsn}. + * + * @param desc + * an array type descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param dims + * number of dimensions of the array to allocate. */ public abstract void visitMultiANewArrayInsn(final String desc, final int dims); /** - * Instruction type annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInsnAnnotation}. + * Instruction type annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInsnAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#INSTANCEOF INSTANCEOF}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#NEW NEW}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#METHOD_REFERENCE METHOD_REFERENCE}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CAST CAST}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, + * or {@link jdk.internal.org.objectweb.asm.TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitInsnAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -490,15 +1010,44 @@ public abstract class Printer { } /** - * Method exception handler. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchBlock}. + * Method exception handler. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchBlock}. + * + * @param start + * beginning of the exception handler's scope (inclusive). + * @param end + * end of the exception handler's scope (exclusive). + * @param handler + * beginning of the exception handler's code. + * @param type + * internal name of the type of exceptions handled by the + * handler, or null to catch any exceptions (for + * "finally" blocks). + * @throws IllegalArgumentException + * if one of the labels has already been visited by this visitor + * (by the {@link #visitLabel visitLabel} method). */ public abstract void visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type); /** - * Try catch block type annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation}. + * Try catch block type annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#EXCEPTION_PARAMETER + * EXCEPTION_PARAMETER}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitTryCatchAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -506,16 +1055,62 @@ public abstract class Printer { } /** - * Method debug info. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLocalVariable}. + * Method debug info. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLocalVariable}. + * + * @param name + * the name of a local variable. + * @param desc + * the type descriptor of this local variable. + * @param signature + * the type signature of this local variable. May be + * null if the local variable type does not use generic + * types. + * @param start + * the first instruction corresponding to the scope of this local + * variable (inclusive). + * @param end + * the last instruction corresponding to the scope of this local + * variable (exclusive). + * @param index + * the local variable's index. + * @throws IllegalArgumentException + * if one of the labels has not already been visited by this + * visitor (by the {@link #visitLabel visitLabel} method). */ public abstract void visitLocalVariable(final String name, final String desc, final String signature, final Label start, final Label end, final int index); /** - * Local variable type annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation}. + * Local variable type annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#LOCAL_VARIABLE + * LOCAL_VARIABLE} or {@link jdk.internal.org.objectweb.asm.TypeReference#RESOURCE_VARIABLE + * RESOURCE_VARIABLE}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param start + * the fist instructions corresponding to the continuous ranges + * that make the scope of this local variable (inclusive). + * @param end + * the last instructions corresponding to the continuous ranges + * that make the scope of this local variable (exclusive). This + * array must have the same size as the 'start' array. + * @param index + * the local variable's index in each range. This array must have + * the same size as the 'start' array. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitLocalVariableAnnotation(final int typeRef, final TypePath typePath, final Label[] start, final Label[] end, @@ -524,19 +1119,34 @@ public abstract class Printer { } /** - * Method debug info. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLineNumber}. + * Method debug info. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLineNumber}. + * + * @param line + * a line number. This number refers to the source file from + * which the class was compiled. + * @param start + * the first instruction corresponding to this line number. + * @throws IllegalArgumentException + * if start has not already been visited by this + * visitor (by the {@link #visitLabel visitLabel} method). */ public abstract void visitLineNumber(final int line, final Label start); /** - * Method max stack and max locals. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMaxs}. + * Method max stack and max locals. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMaxs}. + * + * @param maxStack + * maximum stack size of the method. + * @param maxLocals + * maximum number of local variables for the method. */ public abstract void visitMaxs(final int maxStack, final int maxLocals); /** - * Method end. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitEnd}. + * Method end. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitEnd}. */ public abstract void visitMethodEnd(); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java index 97163ce47f1..e927bff9ea5 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java @@ -74,34 +74,36 @@ import jdk.internal.org.objectweb.asm.TypePath; * visitor chain to trace the class that is visited at a given point in this * chain. This may be useful for debugging purposes. *

    - * The trace printed when visiting the {@code Hello} class is the following: + * The trace printed when visiting the Hello class is the following: + *

    *

    * - *
    {@code
    + * 
      * // class version 49.0 (49) // access flags 0x21 public class Hello {
      *
      * // compiled from: Hello.java
      *
    - * // access flags 0x1 public  ()V ALOAD 0 INVOKESPECIAL
    - * java/lang/Object  ()V RETURN MAXSTACK = 1 MAXLOCALS = 1
    + * // access flags 0x1 public <init> ()V ALOAD 0 INVOKESPECIAL
    + * java/lang/Object <init> ()V RETURN MAXSTACK = 1 MAXLOCALS = 1
      *
      * // access flags 0x9 public static main ([Ljava/lang/String;)V GETSTATIC
    - * java/lang/System out Ljava/io/PrintStream; LDC "hello"
    + * java/lang/System out Ljava/io/PrintStream; LDC "hello"
      * INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V RETURN
      * MAXSTACK = 2 MAXLOCALS = 1 }
    - * }
    + *
    * - *
    where {@code Hello} is defined by: + * where Hello is defined by: + *

    *

    * - *
    {@code
    + * 
      * public class Hello {
      *
      *     public static void main(String[] args) {
    - *         System.out.println("hello");
    + *         System.out.println("hello");
      *     }
      * }
    - * }
    + *
    * *
    * @@ -135,7 +137,7 @@ public final class TraceClassVisitor extends ClassVisitor { * * @param cv * the {@link ClassVisitor} to which this visitor delegates - * calls. May be {@code null}. + * calls. May be null. * @param pw * the print writer to be used to print the class. */ @@ -148,7 +150,7 @@ public final class TraceClassVisitor extends ClassVisitor { * * @param cv * the {@link ClassVisitor} to which this visitor delegates - * calls. May be {@code null}. + * calls. May be null. * @param p * the object that actually converts visit events into text. * @param pw diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java index f4925846c59..ef78b14b8a2 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java @@ -70,7 +70,7 @@ import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; */ public final class TraceSignatureVisitor extends SignatureVisitor { - private final StringBuffer declaration; + private final StringBuilder declaration; private boolean isInterface; @@ -82,9 +82,9 @@ public final class TraceSignatureVisitor extends SignatureVisitor { private boolean seenInterface; - private StringBuffer returnType; + private StringBuilder returnType; - private StringBuffer exceptions; + private StringBuilder exceptions; /** * Stack used to keep track of class types that have arguments. Each element @@ -106,10 +106,10 @@ public final class TraceSignatureVisitor extends SignatureVisitor { public TraceSignatureVisitor(final int access) { super(Opcodes.ASM5); isInterface = (access & Opcodes.ACC_INTERFACE) != 0; - this.declaration = new StringBuffer(); + this.declaration = new StringBuilder(); } - private TraceSignatureVisitor(final StringBuffer buf) { + private TraceSignatureVisitor(final StringBuilder buf) { super(Opcodes.ASM5); this.declaration = buf; } @@ -175,14 +175,14 @@ public final class TraceSignatureVisitor extends SignatureVisitor { declaration.append('('); } declaration.append(')'); - returnType = new StringBuffer(); + returnType = new StringBuilder(); return new TraceSignatureVisitor(returnType); } @Override public SignatureVisitor visitExceptionType() { if (exceptions == null) { - exceptions = new StringBuffer(); + exceptions = new StringBuilder(); } else { exceptions.append(", "); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/version.txt b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/version.txt index 5ba3a332b48..5c62bb6faf9 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/version.txt +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/version.txt @@ -1,12 +1,12 @@ Path: . -Working Copy Root Path: /hudson/jobs/objectweb-init/workspace/asm-svn-2014-10-15 +Working Copy Root Path: /hudson/jobs/objectweb-init/workspace/asm-svn-2016-01-25 URL: file:///svnroot/asm/trunk/asm Repository Root: file:///svnroot/asm Repository UUID: 271bd773-ee82-43a6-9b2b-1890ed8ce7f9 -Revision: 1772 +Revision: 1795 Node Kind: directory Schedule: normal Last Changed Author: ebruneton -Last Changed Rev: 1772 -Last Changed Date: 2014-09-06 09:13:07 +0200 (Sat, 06 Sep 2014) +Last Changed Rev: 1795 +Last Changed Date: 2016-01-24 14:17:10 +0100 (Sun, 24 Jan 2016) From fbca99beb2de1e73e3ce26c60170293e98071060 Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Tue, 1 Mar 2016 12:35:21 -0800 Subject: [PATCH 088/129] 8134119: Use new API to get cache line sizes Using new sysconf and sysinfo API on Solaris 12, avoid using libpicl and libkstat. Reviewed-by: kvn --- hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp | 34 ++++ hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp | 2 +- .../vm/vm_version_solaris_sparc.cpp | 162 ++++++++++++------ 3 files changed, 140 insertions(+), 58 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index 9a6679d17ab..34041ed9943 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -463,3 +463,37 @@ unsigned int VM_Version::calc_parallel_worker_threads() { } return result; } + + +int VM_Version::parse_features(const char* implementation) { + int features = unknown_m; + // Convert to UPPER case before compare. + char* impl = os::strdup_check_oom(implementation); + + for (int i = 0; impl[i] != 0; i++) + impl[i] = (char)toupper((uint)impl[i]); + + if (strstr(impl, "SPARC64") != NULL) { + features |= sparc64_family_m; + } else if (strstr(impl, "SPARC-M") != NULL) { + // M-series SPARC is based on T-series. + features |= (M_family_m | T_family_m); + } else if (strstr(impl, "SPARC-T") != NULL) { + features |= T_family_m; + if (strstr(impl, "SPARC-T1") != NULL) { + features |= T1_model_m; + } + } else { + if (strstr(impl, "SPARC") == NULL) { +#ifndef PRODUCT + // kstat on Solaris 8 virtual machines (branded zones) + // returns "(unsupported)" implementation. Solaris 8 is not + // supported anymore, but include this check to be on the + // safe side. + warning("Can't parse CPU implementation = '%s', assume generic SPARC", impl); +#endif + } + } + os::free((void*)impl); + return features; +} diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp index 0609fa8b9a0..f2c5955905e 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp @@ -121,7 +121,7 @@ protected: static bool is_T1_model(int features) { return is_T_family(features) && ((features & T1_model_m) != 0); } static int maximum_niagara1_processor_count() { return 32; } - + static int parse_features(const char* implementation); public: // Initialization static void initialize(); diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp index 971fa84fc64..837607e6781 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp @@ -264,6 +264,7 @@ void PICL::close_library() { // We need to keep these here as long as we have to build on Solaris // versions before 10. + #ifndef SI_ARCHITECTURE_32 #define SI_ARCHITECTURE_32 516 /* basic 32-bit SI_ARCHITECTURE */ #endif @@ -272,36 +273,87 @@ void PICL::close_library() { #define SI_ARCHITECTURE_64 517 /* basic 64-bit SI_ARCHITECTURE */ #endif -static void do_sysinfo(int si, const char* string, int* features, int mask) { - char tmp; - size_t bufsize = sysinfo(si, &tmp, 1); +#ifndef SI_CPUBRAND +#define SI_CPUBRAND 523 /* return cpu brand string */ +#endif - // All SI defines used below must be supported. - guarantee(bufsize != -1, "must be supported"); +class Sysinfo { + char* _string; +public: + Sysinfo(int si) : _string(NULL) { + char tmp; + size_t bufsize = sysinfo(si, &tmp, 1); - char* buf = (char*) os::malloc(bufsize, mtInternal); - - if (buf == NULL) - return; - - if (sysinfo(si, buf, bufsize) == bufsize) { - // Compare the string. - if (strcmp(buf, string) == 0) { - *features |= mask; + if (bufsize != -1) { + char* buf = (char*) os::malloc(bufsize, mtInternal); + if (buf != NULL) { + if (sysinfo(si, buf, bufsize) == bufsize) { + _string = buf; + } else { + os::free(buf); + } + } } } - os::free(buf); -} + ~Sysinfo() { + if (_string != NULL) { + os::free(_string); + } + } + + const char* value() const { + return _string; + } + + bool valid() const { + return _string != NULL; + } + + bool match(const char* s) const { + return valid() ? strcmp(_string, s) == 0 : false; + } + + bool match_substring(const char* s) const { + return valid() ? strstr(_string, s) != NULL : false; + } +}; + +class Sysconf { + int _value; +public: + Sysconf(int sc) : _value(-1) { + _value = sysconf(sc); + } + bool valid() const { + return _value != -1; + } + int value() const { + return _value; + } +}; + + +#ifndef _SC_DCACHE_LINESZ +#define _SC_DCACHE_LINESZ 508 /* Data cache line size */ +#endif + +#ifndef _SC_L2CACHE_LINESZ +#define _SC_L2CACHE_LINESZ 527 /* Size of L2 cache line */ +#endif int VM_Version::platform_features(int features) { assert(os::Solaris::supports_getisax(), "getisax() must be available"); // Check 32-bit architecture. - do_sysinfo(SI_ARCHITECTURE_32, "sparc", &features, v8_instructions_m); + if (Sysinfo(SI_ARCHITECTURE_32).match("sparc")) { + features |= v8_instructions_m; + } // Check 64-bit architecture. - do_sysinfo(SI_ARCHITECTURE_64, "sparcv9", &features, generic_v9_m); + if (Sysinfo(SI_ARCHITECTURE_64).match("sparcv9")) { + features |= generic_v9_m; + } // Extract valid instruction set extensions. uint_t avs[2]; @@ -388,67 +440,63 @@ int VM_Version::platform_features(int features) { if (av & AV_SPARC_SHA512) features |= sha512_instruction_m; // Determine the machine type. - do_sysinfo(SI_MACHINE, "sun4v", &features, sun4v_m); + if (Sysinfo(SI_MACHINE).match("sun4v")) { + features |= sun4v_m; + } - { - // Using kstat to determine the machine type. + bool use_solaris_12_api = false; + Sysinfo impl(SI_CPUBRAND); + if (impl.valid()) { + // If SI_CPUBRAND works, that means Solaris 12 API to get the cache line sizes + // is available to us as well + use_solaris_12_api = true; + features |= parse_features(impl.value()); + } else { + // Otherwise use kstat to determine the machine type. kstat_ctl_t* kc = kstat_open(); kstat_t* ksp = kstat_lookup(kc, (char*)"cpu_info", -1, NULL); - const char* implementation = "UNKNOWN"; + const char* implementation; + bool has_implementation = false; if (ksp != NULL) { if (kstat_read(kc, ksp, NULL) != -1 && ksp->ks_data != NULL) { kstat_named_t* knm = (kstat_named_t *)ksp->ks_data; for (int i = 0; i < ksp->ks_ndata; i++) { if (strcmp((const char*)&(knm[i].name),"implementation") == 0) { implementation = KSTAT_NAMED_STR_PTR(&knm[i]); + has_implementation = true; #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { tty->print_cr("cpu_info.implementation: %s", implementation); } #endif - // Convert to UPPER case before compare. - char* impl = os::strdup_check_oom(implementation); - - for (int i = 0; impl[i] != 0; i++) - impl[i] = (char)toupper((uint)impl[i]); - - if (strstr(impl, "SPARC64") != NULL) { - features |= sparc64_family_m; - } else if (strstr(impl, "SPARC-M") != NULL) { - // M-series SPARC is based on T-series. - features |= (M_family_m | T_family_m); - } else if (strstr(impl, "SPARC-T") != NULL) { - features |= T_family_m; - if (strstr(impl, "SPARC-T1") != NULL) { - features |= T1_model_m; - } - } else { - if (strstr(impl, "SPARC") == NULL) { -#ifndef PRODUCT - // kstat on Solaris 8 virtual machines (branded zones) - // returns "(unsupported)" implementation. Solaris 8 is not - // supported anymore, but include this check to be on the - // safe side. - warning("kstat cpu_info implementation = '%s', assume generic SPARC", impl); -#endif - implementation = "SPARC"; - } - } - os::free((void*)impl); + features |= parse_features(implementation); break; } } // for( } } - assert(strcmp(implementation, "UNKNOWN") != 0, - "unknown cpu info (changed kstat interface?)"); + assert(has_implementation, "unknown cpu info (changed kstat interface?)"); kstat_close(kc); } - // Figure out cache line sizes using PICL - PICL picl((features & sparc64_family_m) != 0, (features & sun4v_m) != 0); - _L1_data_cache_line_size = picl.L1_data_cache_line_size(); - _L2_data_cache_line_size = picl.L2_data_cache_line_size(); + bool is_sun4v = (features & sun4v_m) != 0; + if (use_solaris_12_api && is_sun4v) { + // If Solaris 12 API is supported and it's sun4v use sysconf() to get the cache line sizes + Sysconf l1_dcache_line_size(_SC_DCACHE_LINESZ); + if (l1_dcache_line_size.valid()) { + _L1_data_cache_line_size = l1_dcache_line_size.value(); + } + Sysconf l2_dcache_line_size(_SC_L2CACHE_LINESZ); + if (l2_dcache_line_size.valid()) { + _L2_data_cache_line_size = l2_dcache_line_size.value(); + } + } else { + // Otherwise figure out the cache line sizes using PICL + bool is_fujitsu = (features & sparc64_family_m) != 0; + PICL picl(is_fujitsu, is_sun4v); + _L1_data_cache_line_size = picl.L1_data_cache_line_size(); + _L2_data_cache_line_size = picl.L2_data_cache_line_size(); + } return features; } From 0e44e963d234ef483085d4ca1eac0279f455a63c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Tue, 1 Mar 2016 23:46:09 +0100 Subject: [PATCH 089/129] 8143226: Minor updates to Event Based tracing Reviewed-by: jbachorik, egahlin --- hotspot/make/aix/makefiles/trace.make | 10 +- hotspot/make/bsd/makefiles/trace.make | 10 +- hotspot/make/linux/makefiles/trace.make | 10 +- hotspot/make/solaris/makefiles/trace.make | 8 +- hotspot/make/windows/makefiles/trace.make | 12 +- hotspot/src/share/vm/c1/c1_Compiler.cpp | 2 - hotspot/src/share/vm/c1/c1_LIRGenerator.cpp | 40 +---- hotspot/src/share/vm/c1/c1_LIRGenerator.hpp | 5 +- .../share/vm/classfile/classFileParser.cpp | 2 +- hotspot/src/share/vm/classfile/vmSymbols.cpp | 2 - .../src/share/vm/gc/shared/copyFailedInfo.hpp | 19 +- .../src/share/vm/gc/shared/gcTraceSend.cpp | 4 +- hotspot/src/share/vm/oops/arrayKlass.cpp | 2 +- hotspot/src/share/vm/oops/instanceKlass.hpp | 4 +- hotspot/src/share/vm/oops/klass.cpp | 4 +- hotspot/src/share/vm/oops/klass.hpp | 4 +- hotspot/src/share/vm/opto/c2compiler.cpp | 2 - hotspot/src/share/vm/opto/library_call.cpp | 55 +----- hotspot/src/share/vm/prims/jni.cpp | 5 +- hotspot/src/share/vm/runtime/java.cpp | 3 +- .../src/share/vm/runtime/objectMonitor.cpp | 17 +- hotspot/src/share/vm/runtime/thread.cpp | 13 +- hotspot/src/share/vm/runtime/thread.hpp | 5 +- hotspot/src/share/vm/runtime/vmThread.cpp | 4 +- hotspot/src/share/vm/trace/trace.xml | 19 +- hotspot/src/share/vm/trace/traceBackend.hpp | 6 +- hotspot/src/share/vm/trace/traceDataTypes.hpp | 41 ++--- hotspot/src/share/vm/trace/traceEvent.hpp | 9 +- .../src/share/vm/trace/traceEventClasses.xsl | 6 +- hotspot/src/share/vm/trace/traceEventIds.xsl | 2 +- hotspot/src/share/vm/trace/traceMacros.hpp | 21 ++- hotspot/src/share/vm/trace/tracetypes.xml | 168 ++++++++---------- hotspot/src/share/vm/utilities/debug.cpp | 13 ++ hotspot/src/share/vm/utilities/hashtable.cpp | 5 + 34 files changed, 211 insertions(+), 321 deletions(-) diff --git a/hotspot/make/aix/makefiles/trace.make b/hotspot/make/aix/makefiles/trace.make index c00b0e3383a..549acb21190 100644 --- a/hotspot/make/aix/makefiles/trace.make +++ b/hotspot/make/aix/makefiles/trace.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -57,11 +57,6 @@ ifeq ($(HAS_ALT_SRC), true) TraceGeneratedNames += \ traceRequestables.hpp \ traceEventControl.hpp - -ifneq ($(INCLUDE_TRACE), false) -TraceGeneratedNames += traceProducer.cpp -endif - endif TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) @@ -100,9 +95,6 @@ else $(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS) - $(GENERATE_CODE) - $(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) $(GENERATE_CODE) diff --git a/hotspot/make/bsd/makefiles/trace.make b/hotspot/make/bsd/makefiles/trace.make index c7ef3d8ea01..88f17a7326e 100644 --- a/hotspot/make/bsd/makefiles/trace.make +++ b/hotspot/make/bsd/makefiles/trace.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -57,11 +57,6 @@ ifeq ($(HAS_ALT_SRC), true) TraceGeneratedNames += \ traceRequestables.hpp \ traceEventControl.hpp - -ifneq ($(INCLUDE_TRACE), false) -TraceGeneratedNames += traceProducer.cpp -endif - endif @@ -101,9 +96,6 @@ else $(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS) - $(GENERATE_CODE) - $(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) $(GENERATE_CODE) diff --git a/hotspot/make/linux/makefiles/trace.make b/hotspot/make/linux/makefiles/trace.make index 7218adc27b3..229b68c434b 100644 --- a/hotspot/make/linux/makefiles/trace.make +++ b/hotspot/make/linux/makefiles/trace.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -57,11 +57,6 @@ ifeq ($(HAS_ALT_SRC), true) TraceGeneratedNames += \ traceRequestables.hpp \ traceEventControl.hpp - -ifneq ($(INCLUDE_TRACE), false) -TraceGeneratedNames += traceProducer.cpp -endif - endif TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) @@ -100,9 +95,6 @@ else $(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS) - $(GENERATE_CODE) - $(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) $(GENERATE_CODE) diff --git a/hotspot/make/solaris/makefiles/trace.make b/hotspot/make/solaris/makefiles/trace.make index ab96c7ffd65..09979558ea7 100644 --- a/hotspot/make/solaris/makefiles/trace.make +++ b/hotspot/make/solaris/makefiles/trace.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -56,8 +56,7 @@ TraceGeneratedNames = \ ifeq ($(HAS_ALT_SRC), true) TraceGeneratedNames += \ traceRequestables.hpp \ - traceEventControl.hpp \ - traceProducer.cpp + traceEventControl.hpp endif TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) @@ -96,9 +95,6 @@ else $(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS) - $(GENERATE_CODE) - $(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) $(GENERATE_CODE) diff --git a/hotspot/make/windows/makefiles/trace.make b/hotspot/make/windows/makefiles/trace.make index 58fee24653c..b32646e3310 100644 --- a/hotspot/make/windows/makefiles/trace.make +++ b/hotspot/make/windows/makefiles/trace.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -43,8 +43,7 @@ TraceGeneratedNames = \ !if EXISTS($(TraceAltSrcDir)) TraceGeneratedNames = $(TraceGeneratedNames) \ traceRequestables.hpp \ - traceEventControl.hpp \ - traceProducer.cpp + traceEventControl.hpp !endif @@ -58,8 +57,7 @@ TraceGeneratedFiles = \ !if EXISTS($(TraceAltSrcDir)) TraceGeneratedFiles = $(TraceGeneratedFiles) \ $(TraceOutDir)/traceRequestables.hpp \ - $(TraceOutDir)/traceEventControl.hpp \ - $(TraceOutDir)/traceProducer.cpp + $(TraceOutDir)/traceEventControl.hpp !endif XSLT = $(QUIETLY) $(REMOTE) $(RUN_JAVA) -classpath $(JvmtiOutDir) jvmtiGen @@ -98,10 +96,6 @@ $(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir) @echo Generating AltSrc $@ @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceEventClasses.xsl -OUT $(TraceOutDir)/traceEventClasses.hpp -$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS) - @echo Generating AltSrc $@ - @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceProducer.xsl -OUT $(TraceOutDir)/traceProducer.cpp - $(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) @echo Generating AltSrc $@ @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceRequestables.xsl -OUT $(TraceOutDir)/traceRequestables.hpp diff --git a/hotspot/src/share/vm/c1/c1_Compiler.cpp b/hotspot/src/share/vm/c1/c1_Compiler.cpp index 5dbe6c209f3..78d71b89444 100644 --- a/hotspot/src/share/vm/c1/c1_Compiler.cpp +++ b/hotspot/src/share/vm/c1/c1_Compiler.cpp @@ -228,8 +228,6 @@ bool Compiler::is_intrinsic_supported(const methodHandle& method) { case vmIntrinsics::_getCharStringU: case vmIntrinsics::_putCharStringU: #ifdef TRACE_HAVE_INTRINSICS - case vmIntrinsics::_classID: - case vmIntrinsics::_threadID: case vmIntrinsics::_counterTime: #endif break; diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 30ae8f86e9f..a3a2ce52f42 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -43,6 +43,9 @@ #if INCLUDE_ALL_GCS #include "gc/g1/heapRegion.hpp" #endif // INCLUDE_ALL_GCS +#ifdef TRACE_HAVE_INTRINSICS +#include "trace/traceMacros.hpp" +#endif #ifdef ASSERT #define __ gen()->lir(__FILE__, __LINE__)-> @@ -3067,42 +3070,7 @@ void LIRGenerator::do_RuntimeCall(address routine, Intrinsic* x) { __ move(reg, result); } -#ifdef TRACE_HAVE_INTRINSICS -void LIRGenerator::do_ThreadIDIntrinsic(Intrinsic* x) { - LIR_Opr thread = getThreadPointer(); - LIR_Opr osthread = new_pointer_register(); - __ move(new LIR_Address(thread, in_bytes(JavaThread::osthread_offset()), osthread->type()), osthread); - size_t thread_id_size = OSThread::thread_id_size(); - if (thread_id_size == (size_t) BytesPerLong) { - LIR_Opr id = new_register(T_LONG); - __ move(new LIR_Address(osthread, in_bytes(OSThread::thread_id_offset()), T_LONG), id); - __ convert(Bytecodes::_l2i, id, rlock_result(x)); - } else if (thread_id_size == (size_t) BytesPerInt) { - __ move(new LIR_Address(osthread, in_bytes(OSThread::thread_id_offset()), T_INT), rlock_result(x)); - } else { - ShouldNotReachHere(); - } -} -void LIRGenerator::do_ClassIDIntrinsic(Intrinsic* x) { - CodeEmitInfo* info = state_for(x); - CodeEmitInfo* info2 = new CodeEmitInfo(info); // Clone for the second null check - BasicType klass_pointer_type = NOT_LP64(T_INT) LP64_ONLY(T_LONG); - assert(info != NULL, "must have info"); - LIRItem arg(x->argument_at(1), this); - arg.load_item(); - LIR_Opr klass = new_pointer_register(); - __ move(new LIR_Address(arg.result(), java_lang_Class::klass_offset_in_bytes(), klass_pointer_type), klass, info); - LIR_Opr id = new_register(T_LONG); - ByteSize offset = TRACE_ID_OFFSET; - LIR_Address* trace_id_addr = new LIR_Address(klass, in_bytes(offset), T_LONG); - __ move(trace_id_addr, id); - __ logical_or(id, LIR_OprFact::longConst(0x01l), id); - __ store(id, trace_id_addr); - __ logical_and(id, LIR_OprFact::longConst(~0x3l), id); - __ move(id, rlock_result(x)); -} -#endif void LIRGenerator::do_Intrinsic(Intrinsic* x) { switch (x->id()) { @@ -3115,8 +3083,6 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) { } #ifdef TRACE_HAVE_INTRINSICS - case vmIntrinsics::_threadID: do_ThreadIDIntrinsic(x); break; - case vmIntrinsics::_classID: do_ClassIDIntrinsic(x); break; case vmIntrinsics::_counterTime: do_RuntimeCall(CAST_FROM_FN_PTR(address, TRACE_TIME_METHOD), x); break; diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp index 9438d77288c..4f459dbd1a0 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp @@ -440,10 +440,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void do_SwitchRanges(SwitchRangeArray* x, LIR_Opr value, BlockBegin* default_sux); void do_RuntimeCall(address routine, Intrinsic* x); -#ifdef TRACE_HAVE_INTRINSICS - void do_ThreadIDIntrinsic(Intrinsic* x); - void do_ClassIDIntrinsic(Intrinsic* x); -#endif + ciKlass* profile_type(ciMethodData* md, int md_first_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_at_call_k, ciKlass* callee_signature_k); diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index a75504d2025..97d6bdfcd56 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -5380,7 +5380,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) { } } - TRACE_INIT_ID(ik); + TRACE_INIT_KLASS_ID(ik); // If we reach here, all is well. // Now remove the InstanceKlass* from the _klass_to_deallocate field diff --git a/hotspot/src/share/vm/classfile/vmSymbols.cpp b/hotspot/src/share/vm/classfile/vmSymbols.cpp index 81dda6e4fd0..287db197252 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.cpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp @@ -328,8 +328,6 @@ bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) { assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); switch(id) { #ifdef TRACE_HAVE_INTRINSICS - case vmIntrinsics::_classID: - case vmIntrinsics::_threadID: case vmIntrinsics::_counterTime: #endif case vmIntrinsics::_currentTimeMillis: diff --git a/hotspot/src/share/vm/gc/shared/copyFailedInfo.hpp b/hotspot/src/share/vm/gc/shared/copyFailedInfo.hpp index 6a6a64e31eb..b7e0bbe98b0 100644 --- a/hotspot/src/share/vm/gc/shared/copyFailedInfo.hpp +++ b/hotspot/src/share/vm/gc/shared/copyFailedInfo.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #define SHARE_VM_GC_SHARED_COPYFAILEDINFO_HPP #include "runtime/thread.hpp" +#include "trace/traceMacros.hpp" #include "utilities/globalDefinitions.hpp" class CopyFailedInfo : public CHeapObj { @@ -63,26 +64,28 @@ class CopyFailedInfo : public CHeapObj { }; class PromotionFailedInfo : public CopyFailedInfo { - OSThread* _thread; + traceid _thread_trace_id; public: - PromotionFailedInfo() : CopyFailedInfo(), _thread(NULL) {} + PromotionFailedInfo() : CopyFailedInfo(), _thread_trace_id(0) {} void register_copy_failure(size_t size) { CopyFailedInfo::register_copy_failure(size); - if (_thread == NULL) { - _thread = Thread::current()->osthread(); + if (_thread_trace_id == 0) { + _thread_trace_id = THREAD_TRACE_ID(Thread::current()); } else { - assert(_thread == Thread::current()->osthread(), "The PromotionFailedInfo should be thread local."); + assert(THREAD_TRACE_ID(Thread::current()) == _thread_trace_id, + "The PromotionFailedInfo should be thread local."); } } void reset() { CopyFailedInfo::reset(); - _thread = NULL; + _thread_trace_id = 0; } - OSThread* thread() const { return _thread; } + traceid thread_trace_id() const { return _thread_trace_id; } + }; class EvacuationFailedInfo : public CopyFailedInfo {}; diff --git a/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp b/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp index 0bd6fef7471..db538eb4f41 100644 --- a/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp +++ b/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -174,7 +174,7 @@ void YoungGCTracer::send_promotion_failed_event(const PromotionFailedInfo& pf_in if (e.should_commit()) { e.set_gcId(GCId::current()); e.set_data(to_trace_struct(pf_info)); - e.set_thread(pf_info.thread()->thread_id()); + e.set_thread(pf_info.thread_trace_id()); e.commit(); } } diff --git a/hotspot/src/share/vm/oops/arrayKlass.cpp b/hotspot/src/share/vm/oops/arrayKlass.cpp index e92df43076f..2278ce92471 100644 --- a/hotspot/src/share/vm/oops/arrayKlass.cpp +++ b/hotspot/src/share/vm/oops/arrayKlass.cpp @@ -89,7 +89,7 @@ ArrayKlass::ArrayKlass(Symbol* name) : set_super(Universe::is_bootstrapping() ? (Klass*)NULL : SystemDictionary::Object_klass()); set_layout_helper(Klass::_lh_neutral_value); set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5) - TRACE_INIT_ID(this); + TRACE_INIT_KLASS_ID(this); } diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index f7a3a24800f..7e5d8360596 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -839,7 +839,7 @@ public: // support for stub routines static ByteSize init_state_offset() { return in_ByteSize(offset_of(InstanceKlass, _init_state)); } - TRACE_DEFINE_OFFSET; + TRACE_DEFINE_KLASS_TRACE_ID_OFFSET; static ByteSize init_thread_offset() { return in_ByteSize(offset_of(InstanceKlass, _init_thread)); } // subclass/subinterface checks diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp index b391f222d6a..3cedd3470f0 100644 --- a/hotspot/src/share/vm/oops/klass.cpp +++ b/hotspot/src/share/vm/oops/klass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -494,7 +494,7 @@ void Klass::remove_unshareable_info() { } void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { - TRACE_INIT_ID(this); + TRACE_INIT_KLASS_ID(this); // If an exception happened during CDS restore, some of these fields may already be // set. We leave the class on the CLD list, even if incomplete so that we don't // modify the CLD list outside a safepoint. diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index 00fe28d614b..cff1d74d6ef 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -132,7 +132,7 @@ class Klass : public Metadata { jint _modifier_flags; // Processed access flags, for use by Class.getModifiers. AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. - TRACE_DEFINE_KLASS_TRACE_ID; + TRACE_DEFINE_TRACE_ID_FIELD; // Biased locking implementation and statistics // (the 64-bit chunk goes first, to avoid some fragmentation) @@ -569,7 +569,7 @@ protected: jlong last_biased_lock_bulk_revocation_time() { return _last_biased_lock_bulk_revocation_time; } void set_last_biased_lock_bulk_revocation_time(jlong cur_time) { _last_biased_lock_bulk_revocation_time = cur_time; } - TRACE_DEFINE_KLASS_METHODS; + TRACE_DEFINE_TRACE_ID_METHODS; // garbage collection support void oops_do(OopClosure* cl); diff --git a/hotspot/src/share/vm/opto/c2compiler.cpp b/hotspot/src/share/vm/opto/c2compiler.cpp index 7068b5cfb1a..bc08a298dc6 100644 --- a/hotspot/src/share/vm/opto/c2compiler.cpp +++ b/hotspot/src/share/vm/opto/c2compiler.cpp @@ -400,8 +400,6 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_currentThread: case vmIntrinsics::_isInterrupted: #ifdef TRACE_HAVE_INTRINSICS - case vmIntrinsics::_classID: - case vmIntrinsics::_threadID: case vmIntrinsics::_counterTime: #endif case vmIntrinsics::_currentTimeMillis: diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 753612c206f..f9942825e23 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -49,7 +49,9 @@ #include "opto/subnode.hpp" #include "prims/nativeLookup.hpp" #include "runtime/sharedRuntime.hpp" +#ifdef TRACE_HAVE_INTRINSICS #include "trace/traceMacros.hpp" +#endif class LibraryIntrinsic : public InlineCallGenerator { // Extend the set of intrinsics known to the runtime: @@ -246,10 +248,7 @@ class LibraryCallKit : public GraphKit { bool inline_unsafe_allocate(); bool inline_unsafe_copyMemory(); bool inline_native_currentThread(); -#ifdef TRACE_HAVE_INTRINSICS - bool inline_native_classID(); - bool inline_native_threadID(); -#endif + bool inline_native_time_funcs(address method, const char* funcName); bool inline_native_isInterrupted(); bool inline_native_Class_query(vmIntrinsics::ID id); @@ -642,8 +641,6 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_isInterrupted: return inline_native_isInterrupted(); #ifdef TRACE_HAVE_INTRINSICS - case vmIntrinsics::_classID: return inline_native_classID(); - case vmIntrinsics::_threadID: return inline_native_threadID(); case vmIntrinsics::_counterTime: return inline_native_time_funcs(CAST_FROM_FN_PTR(address, TRACE_TIME_METHOD), "counterTime"); #endif case vmIntrinsics::_currentTimeMillis: return inline_native_time_funcs(CAST_FROM_FN_PTR(address, os::javaTimeMillis), "currentTimeMillis"); @@ -2932,52 +2929,6 @@ bool LibraryCallKit::inline_unsafe_allocate() { return true; } -#ifdef TRACE_HAVE_INTRINSICS -/* - * oop -> myklass - * myklass->trace_id |= USED - * return myklass->trace_id & ~0x3 - */ -bool LibraryCallKit::inline_native_classID() { - null_check_receiver(); // null-check, then ignore - Node* cls = null_check(argument(1), T_OBJECT); - Node* kls = load_klass_from_mirror(cls, false, NULL, 0); - kls = null_check(kls, T_OBJECT); - ByteSize offset = TRACE_ID_OFFSET; - Node* insp = basic_plus_adr(kls, in_bytes(offset)); - Node* tvalue = make_load(NULL, insp, TypeLong::LONG, T_LONG, MemNode::unordered); - Node* bits = longcon(~0x03l); // ignore bit 0 & 1 - Node* andl = _gvn.transform(new AndLNode(tvalue, bits)); - Node* clsused = longcon(0x01l); // set the class bit - Node* orl = _gvn.transform(new OrLNode(tvalue, clsused)); - - const TypePtr *adr_type = _gvn.type(insp)->isa_ptr(); - store_to_memory(control(), insp, orl, T_LONG, adr_type, MemNode::unordered); - set_result(andl); - return true; -} - -bool LibraryCallKit::inline_native_threadID() { - Node* tls_ptr = NULL; - Node* cur_thr = generate_current_thread(tls_ptr); - Node* p = basic_plus_adr(top()/*!oop*/, tls_ptr, in_bytes(JavaThread::osthread_offset())); - Node* osthread = make_load(NULL, p, TypeRawPtr::NOTNULL, T_ADDRESS, MemNode::unordered); - p = basic_plus_adr(top()/*!oop*/, osthread, in_bytes(OSThread::thread_id_offset())); - - Node* threadid = NULL; - size_t thread_id_size = OSThread::thread_id_size(); - if (thread_id_size == (size_t) BytesPerLong) { - threadid = ConvL2I(make_load(control(), p, TypeLong::LONG, T_LONG, MemNode::unordered)); - } else if (thread_id_size == (size_t) BytesPerInt) { - threadid = make_load(control(), p, TypeInt::INT, T_INT, MemNode::unordered); - } else { - ShouldNotReachHere(); - } - set_result(threadid); - return true; -} -#endif - //------------------------inline_native_time_funcs-------------- // inline code for System.currentTimeMillis() and System.nanoTime() // these have the same type and signature diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 419963ef412..ffca3342ebd 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -73,6 +73,7 @@ #include "runtime/vm_operations.hpp" #include "services/memTracker.hpp" #include "services/runtimeService.hpp" +#include "trace/traceMacros.hpp" #include "trace/tracing.hpp" #include "utilities/defaultStream.hpp" #include "utilities/dtrace.hpp" @@ -3929,7 +3930,7 @@ static jint JNI_CreateJavaVM_inner(JavaVM **vm, void **penv, void *args) { EventThreadStart event; if (event.should_commit()) { - event.set_javalangthread(java_lang_Thread::thread_id(thread->threadObj())); + event.set_thread(THREAD_TRACE_ID(thread)); event.commit(); } @@ -4149,7 +4150,7 @@ static jint attach_current_thread(JavaVM *vm, void **penv, void *_args, bool dae EventThreadStart event; if (event.should_commit()) { - event.set_javalangthread(java_lang_Thread::thread_id(thread->threadObj())); + event.set_thread(THREAD_TRACE_ID(thread)); event.commit(); } diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index 84235d8803f..a30acc9a9bd 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -64,6 +64,7 @@ #include "runtime/timer.hpp" #include "runtime/vm_operations.hpp" #include "services/memTracker.hpp" +#include "trace/traceMacros.hpp" #include "trace/tracing.hpp" #include "utilities/dtrace.hpp" #include "utilities/globalDefinitions.hpp" @@ -485,7 +486,7 @@ void before_exit(JavaThread* thread) { EventThreadEnd event; if (event.should_commit()) { - event.set_javalangthread(java_lang_Thread::thread_id(thread->threadObj())); + event.set_thread(THREAD_TRACE_ID(thread)); event.commit(); } diff --git a/hotspot/src/share/vm/runtime/objectMonitor.cpp b/hotspot/src/share/vm/runtime/objectMonitor.cpp index 2f7937d4f3e..6258d64ad2f 100644 --- a/hotspot/src/share/vm/runtime/objectMonitor.cpp +++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -401,7 +401,7 @@ void NOINLINE ObjectMonitor::enter(TRAPS) { if (event.should_commit()) { event.set_klass(((oop)this->object())->klass()); - event.set_previousOwner((TYPE_JAVALANGTHREAD)_previous_owner_tid); + event.set_previousOwner((TYPE_THREAD)_previous_owner_tid); event.set_address((TYPE_ADDRESS)(uintptr_t)(this->object_addr())); event.commit(); } @@ -937,7 +937,7 @@ void NOINLINE ObjectMonitor::exit(bool not_suspended, TRAPS) { // get the owner's thread id for the MonitorEnter event // if it is enabled and the thread isn't suspended if (not_suspended && Tracing::is_event_enabled(TraceJavaMonitorEnterEvent)) { - _previous_owner_tid = SharedRuntime::get_java_tid(Self); + _previous_owner_tid = THREAD_TRACE_ID(Self); } #endif @@ -1391,11 +1391,12 @@ void ObjectMonitor::post_monitor_wait_event(EventJavaMonitorWait* event, jlong notifier_tid, jlong timeout, bool timedout) { + assert(event != NULL, "invariant"); event->set_klass(((oop)this->object())->klass()); - event->set_timeout((TYPE_ULONG)timeout); - event->set_address((TYPE_ADDRESS)(uintptr_t)(this->object_addr())); - event->set_notifier((TYPE_OSTHREAD)notifier_tid); - event->set_timedOut((TYPE_BOOLEAN)timedout); + event->set_timeout(timeout); + event->set_address((TYPE_ADDRESS)this->object_addr()); + event->set_notifier(notifier_tid); + event->set_timedOut(timedout); event->commit(); } @@ -1655,7 +1656,7 @@ void ObjectMonitor::INotify(Thread * Self) { iterator->TState = ObjectWaiter::TS_ENTER; } iterator->_notified = 1; - iterator->_notifier_tid = Self->osthread()->thread_id(); + iterator->_notifier_tid = THREAD_TRACE_ID(Self); ObjectWaiter * list = _EntryList; if (list != NULL) { diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 8e1e997f8c1..a411b6868dc 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -1694,7 +1694,7 @@ void JavaThread::run() { EventThreadStart event; if (event.should_commit()) { - event.set_javalangthread(java_lang_Thread::thread_id(this->threadObj())); + event.set_thread(THREAD_TRACE_ID(this)); event.commit(); } @@ -1799,7 +1799,7 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { // from java_lang_Thread object EventThreadEnd event; if (event.should_commit()) { - event.set_javalangthread(java_lang_Thread::thread_id(this->threadObj())); + event.set_thread(THREAD_TRACE_ID(this)); event.commit(); } @@ -3554,6 +3554,10 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { return status; } + if (TRACE_INITIALIZE() != JNI_OK) { + vm_exit_during_initialization("Failed to initialize tracing backend"); + } + // Should be done after the heap is fully created main_thread->cache_global_variables(); @@ -3622,11 +3626,6 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { quicken_jni_functions(); - // Must be run after init_ft which initializes ft_enabled - if (TRACE_INITIALIZE() != JNI_OK) { - vm_exit_during_initialization("Failed to initialize tracing backend"); - } - // No more stub generation allowed after that point. StubCodeDesc::freeze(); diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index 4d94026e313..eed983d3841 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -448,7 +448,8 @@ class Thread: public ThreadShadow { void incr_allocated_bytes(jlong size) { _allocated_bytes += size; } inline jlong cooked_allocated_bytes(); - TRACE_DATA* trace_data() { return &_trace_data; } + TRACE_DEFINE_THREAD_TRACE_DATA_OFFSET; + TRACE_DATA* trace_data() const { return &_trace_data; } const ThreadExt& ext() const { return _ext; } ThreadExt& ext() { return _ext; } diff --git a/hotspot/src/share/vm/runtime/vmThread.cpp b/hotspot/src/share/vm/runtime/vmThread.cpp index 77935603075..f4584b1fc9b 100644 --- a/hotspot/src/share/vm/runtime/vmThread.cpp +++ b/hotspot/src/share/vm/runtime/vmThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -359,7 +359,7 @@ void VMThread::evaluate_operation(VM_Operation* op) { // Only write caller thread information for non-concurrent vm operations. // For concurrent vm operations, the thread id is set to 0 indicating thread is unknown. // This is because the caller thread could have exited already. - event.set_caller(is_concurrent ? 0 : op->calling_thread()->osthread()->thread_id()); + event.set_caller(is_concurrent ? 0 : THREAD_TRACE_ID(op->calling_thread())); event.commit(); } diff --git a/hotspot/src/share/vm/trace/trace.xml b/hotspot/src/share/vm/trace/trace.xml index 7e357f4c106..d6d76d9398f 100644 --- a/hotspot/src/share/vm/trace/trace.xml +++ b/hotspot/src/share/vm/trace/trace.xml @@ -1,6 +1,6 @@ - + diff --git a/hotspot/src/share/vm/trace/traceBackend.hpp b/hotspot/src/share/vm/trace/traceBackend.hpp index c65d89e41d8..36635321ad6 100644 --- a/hotspot/src/share/vm/trace/traceBackend.hpp +++ b/hotspot/src/share/vm/trace/traceBackend.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,10 @@ public: static void on_unloading_classes(void) { } + + static void on_vm_error(bool) { + } + }; class TraceThreadData { diff --git a/hotspot/src/share/vm/trace/traceDataTypes.hpp b/hotspot/src/share/vm/trace/traceDataTypes.hpp index 31004d934b5..b51343d9575 100644 --- a/hotspot/src/share/vm/trace/traceDataTypes.hpp +++ b/hotspot/src/share/vm/trace/traceDataTypes.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,39 +31,32 @@ enum { CONTENT_TYPE_NONE = 0, - CONTENT_TYPE_BYTES = 1, - CONTENT_TYPE_EPOCHMILLIS = 2, - CONTENT_TYPE_MILLIS = 3, - CONTENT_TYPE_NANOS = 4, - CONTENT_TYPE_TICKS = 5, - CONTENT_TYPE_ADDRESS = 6, + CONTENT_TYPE_CLASS = 20, + CONTENT_TYPE_UTF8 = 21, + CONTENT_TYPE_THREAD = 22, + CONTENT_TYPE_STACKTRACE = 23, + CONTENT_TYPE_BYTES = 24, + CONTENT_TYPE_EPOCHMILLIS = 25, + CONTENT_TYPE_MILLIS = 26, + CONTENT_TYPE_NANOS = 27, + CONTENT_TYPE_TICKS = 28, + CONTENT_TYPE_ADDRESS = 29, + CONTENT_TYPE_PERCENTAGE = 30, - CONTENT_TYPE_OSTHREAD, - CONTENT_TYPE_JAVALANGTHREAD, - CONTENT_TYPE_STACKTRACE, - CONTENT_TYPE_CLASS, - CONTENT_TYPE_PERCENTAGE, - - JVM_CONTENT_TYPES_START = 30, - JVM_CONTENT_TYPES_END = 100 + JVM_CONTENT_TYPES_START = 33, + JVM_CONTENT_TYPES_END = 255 }; enum ReservedEvent { - EVENT_PRODUCERS, + EVENT_METADATA, EVENT_CHECKPOINT, EVENT_BUFFERLOST, - NUM_RESERVED_EVENTS + NUM_RESERVED_EVENTS = JVM_CONTENT_TYPES_END }; typedef enum ReservedEvent ReservedEvent; -typedef u8 classid; -typedef u8 stacktraceid; -typedef u8 methodid; -typedef u8 fieldid; - -class TraceUnicodeString; +class Symbol; #endif // SHARE_VM_TRACE_TRACEDATATYPES_HPP - diff --git a/hotspot/src/share/vm/trace/traceEvent.hpp b/hotspot/src/share/vm/trace/traceEvent.hpp index a0548d76513..f56ea19f716 100644 --- a/hotspot/src/share/vm/trace/traceEvent.hpp +++ b/hotspot/src/share/vm/trace/traceEvent.hpp @@ -99,8 +99,13 @@ class TraceEvent : public StackObj { cancel(); return; } - if (_endTime == 0) { - static_cast(this)->set_endtime(Tracing::time()); + + if (_startTime == 0) { + static_cast(this)->set_starttime(Tracing::time()); + } else { + if (_endTime == 0) { + static_cast(this)->set_endtime(Tracing::time()); + } } if (static_cast(this)->should_write()) { static_cast(this)->writeEvent(); diff --git a/hotspot/src/share/vm/trace/traceEventClasses.xsl b/hotspot/src/share/vm/trace/traceEventClasses.xsl index 41d3a446a9e..16b30c7b909 100644 --- a/hotspot/src/share/vm/trace/traceEventClasses.xsl +++ b/hotspot/src/share/vm/trace/traceEventClasses.xsl @@ -1,6 +1,6 @@ - + - + - - + - - - + type="const char*" sizeop="sizeof_utf(%)"/> + type="const Symbol*" sizeop="sizeof(u8)"/> + type="const Klass*" sizeop="sizeof(u8)"/> + type="const Method*" sizeop="sizeof(u8)"/> - - - - - - - - + + - + sizeop="sizeof(u8)"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp index 8d6a9398764..f0aa8371f17 100644 --- a/hotspot/src/share/vm/utilities/debug.cpp +++ b/hotspot/src/share/vm/utilities/debug.cpp @@ -51,9 +51,14 @@ #include "services/heapDumper.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" +#include "utilities/macros.hpp" #include "utilities/top.hpp" #include "utilities/vmError.hpp" +#if INCLUDE_TRACE +#include "trace/tracing.hpp" +#endif + #ifndef ASSERT # ifdef _DEBUG // NOTE: don't turn the lines below into a comment -- if you're getting @@ -280,6 +285,12 @@ void report_out_of_shared_space(SharedSpaceType shared_space) { exit(2); } +static void notify_tracing() { +#if INCLUDE_TRACE + Tracing::on_vm_error(true); +#endif +} + void report_insufficient_metaspace(size_t required_size) { warning("\nThe MaxMetaspaceSize of " SIZE_FORMAT " bytes is not large enough.\n" "Either don't specify the -XX:MaxMetaspaceSize=\n" @@ -302,6 +313,8 @@ void report_java_out_of_memory(const char* message) { HeapDumper::dump_heap_from_oome(); } + notify_tracing(); + if (OnOutOfMemoryError && OnOutOfMemoryError[0]) { VMError::report_java_out_of_memory(message); } diff --git a/hotspot/src/share/vm/utilities/hashtable.cpp b/hotspot/src/share/vm/utilities/hashtable.cpp index 10f4456274a..8af6156ed45 100644 --- a/hotspot/src/share/vm/utilities/hashtable.cpp +++ b/hotspot/src/share/vm/utilities/hashtable.cpp @@ -383,4 +383,9 @@ template class BasicHashtable; template class BasicHashtable; template class BasicHashtable; template class BasicHashtable; +#if INCLUDE_TRACE +template class Hashtable; +template class HashtableEntry; +template class BasicHashtable; +#endif template class BasicHashtable; From 1593edaf5947e841a2e162553bebb749dca9faf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Tue, 1 Mar 2016 23:47:30 +0100 Subject: [PATCH 090/129] 8066814: Reduce accessibility in TraceEvent Reviewed-by: egahlin, jbachorik --- hotspot/src/share/vm/trace/traceEvent.hpp | 76 ++++++++++++----------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/hotspot/src/share/vm/trace/traceEvent.hpp b/hotspot/src/share/vm/trace/traceEvent.hpp index f56ea19f716..3a083c402ce 100644 --- a/hotspot/src/share/vm/trace/traceEvent.hpp +++ b/hotspot/src/share/vm/trace/traceEvent.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,6 @@ class TraceEvent : public StackObj { _endTime = time; } - public: TraceEvent(EventStartTime timing=TIMED) : _startTime(0), _endTime(0), @@ -76,12 +75,21 @@ class TraceEvent : public StackObj { { if (T::is_enabled()) { _started = true; - if (timing == TIMED && !T::isInstant) { - static_cast(this)->set_starttime(Tracing::time()); + if (TIMED == timing && !T::isInstant) { + static_cast(this)->set_starttime(Tracing::time()); } } } + public: + void set_starttime(const Ticks& time) { + _startTime = time.value(); + } + + void set_endtime(const Ticks& time) { + _endTime = time.value(); + } + static bool is_enabled() { return Tracing::is_event_enabled(T::eventId); } @@ -90,72 +98,68 @@ class TraceEvent : public StackObj { return _started; } - void ignoreCheck() { - DEBUG_ONLY(_ignore_check = true); - } - void commit() { if (!should_commit()) { - cancel(); - return; + DEBUG_ONLY(cancel()); + return; } - + assert(!_cancelled, "Committing an event that has already been cancelled"); if (_startTime == 0) { static_cast(this)->set_starttime(Tracing::time()); - } else { - if (_endTime == 0) { - static_cast(this)->set_endtime(Tracing::time()); - } + } else if (_endTime == 0) { + static_cast(this)->set_endtime(Tracing::time()); } if (static_cast(this)->should_write()) { static_cast(this)->writeEvent(); } - set_commited(); + DEBUG_ONLY(set_commited()); } - void set_starttime(const Ticks& time) { - _startTime = time.value(); - } - - void set_endtime(const Ticks& time) { - _endTime = time.value(); - } - - TraceEventId id() const { + static TraceEventId id() { return T::eventId; } - bool is_instant() const { + static bool is_instant() { return T::isInstant; } - bool is_requestable() const { + static bool is_requestable() { return T::isRequestable; } - bool has_thread() const { + static bool has_thread() { return T::hasThread; } - bool has_stacktrace() const { + static bool has_stacktrace() { return T::hasStackTrace; } void cancel() { - assert(!_committed && !_cancelled, "event was already committed/cancelled"); + assert(!_committed && !_cancelled, + "event was already committed/cancelled"); DEBUG_ONLY(_cancelled = true); } - void set_commited() { - assert(!_committed, "event has already been committed"); - DEBUG_ONLY(_committed = true); - } - ~TraceEvent() { if (_started) { - assert(_ignore_check || _committed || _cancelled, "event was not committed/cancelled"); + assert(_ignore_check || _committed || _cancelled, + "event was not committed/cancelled"); } } + +#ifdef ASSERT + protected: + void ignoreCheck() { + _ignore_check = true; + } + + private: + void set_commited() { + assert(!_committed, "event has already been committed"); + _committed = true; + } +#endif // ASSERT }; #endif // INCLUDE_TRACE From 64f55fb26703749d8d07063a347c3a2d773323fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Tue, 1 Mar 2016 23:48:46 +0100 Subject: [PATCH 091/129] 8147442: Event-based tracing to allow for tracing Klass creation Reviewed-by: jbachorik, egahlin --- hotspot/src/share/vm/classfile/klassFactory.cpp | 5 ++++- hotspot/src/share/vm/trace/traceMacros.hpp | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/classfile/klassFactory.cpp b/hotspot/src/share/vm/classfile/klassFactory.cpp index 14af5574021..033d9bfb660 100644 --- a/hotspot/src/share/vm/classfile/klassFactory.cpp +++ b/hotspot/src/share/vm/classfile/klassFactory.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "classfile/klassFactory.hpp" #include "memory/resourceArea.hpp" #include "prims/jvmtiEnvBase.hpp" +#include "trace/traceMacros.hpp" static ClassFileStream* prologue(ClassFileStream* stream, Symbol* name, @@ -136,5 +137,7 @@ instanceKlassHandle KlassFactory::create_from_stream(ClassFileStream* stream, result->set_cached_class_file(cached_class_file); } + TRACE_KLASS_CREATION(result, parser, THREAD); + return result; } diff --git a/hotspot/src/share/vm/trace/traceMacros.hpp b/hotspot/src/share/vm/trace/traceMacros.hpp index ee9be4a8967..c67024ae3f0 100644 --- a/hotspot/src/share/vm/trace/traceMacros.hpp +++ b/hotspot/src/share/vm/trace/traceMacros.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ typedef u8 traceid; #define EVENT_THREAD_EXIT(thread) #define EVENT_THREAD_DESTRUCT(thread) +#define TRACE_KLASS_CREATION(k, p, t) #define TRACE_INIT_KLASS_ID(k) #define TRACE_INIT_THREAD_ID(td) From 75b02a64c682529204a11bfa3f252cc43e5732c6 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Wed, 2 Mar 2016 08:41:02 +0100 Subject: [PATCH 092/129] 8058944: Unify the reporting strings for the GC debug level logging in G1 Reviewed-by: sjohanss, tschatzl --- hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp | 4 ++-- hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp index 5ece63cea5d..33e001122ae 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp @@ -1097,7 +1097,7 @@ void G1ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { reset_marking_state(); } else { { - GCTraceTime(Debug, gc) trace("GC Aggregate Data", g1h->gc_timer_cm()); + GCTraceTime(Debug, gc) trace("Aggregate Data", g1h->gc_timer_cm()); // Aggregate the per-task counting data that we have accumulated // while marking. @@ -2018,7 +2018,7 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { // Inner scope to exclude the cleaning of the string and symbol // tables from the displayed time. { - GCTraceTime(Debug, gc) trace("GC Ref Proc", g1h->gc_timer_cm()); + GCTraceTime(Debug, gc) trace("Reference Processing", g1h->gc_timer_cm()); ReferenceProcessor* rp = g1h->ref_processor_cm(); diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp index b5dce4ffc3d..9ab25e6a73f 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp @@ -277,8 +277,8 @@ void G1GCPhaseTimes::print() { } debug_line("Choose CSet", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms)); debug_line("Preserve CM Refs", _recorded_preserve_cm_referents_time_ms); - debug_line("Ref Proc", _cur_ref_proc_time_ms); - debug_line("Ref Enq", _cur_ref_enq_time_ms); + debug_line("Reference Processing", _cur_ref_proc_time_ms); + debug_line("Reference Enqueuing", _cur_ref_enq_time_ms); debug_line("Redirty Cards", _recorded_redirty_logged_cards_time_ms); trace_phase(_gc_par_phases[RedirtyCards]); trace_phase(_gc_par_phases[PreserveCMReferents]); From ff51364bf687223eeae1a74ac9635bdfe49f396b Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 2 Mar 2016 12:29:17 +0300 Subject: [PATCH 093/129] 8151017: [TESTBUG] test/compiler/c1/CanonicalizeArrayLength does not work on product builds Reviewed-by: thartmann, zmajo --- hotspot/test/compiler/c1/CanonicalizeArrayLength.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hotspot/test/compiler/c1/CanonicalizeArrayLength.java b/hotspot/test/compiler/c1/CanonicalizeArrayLength.java index 9971d25bde8..ee2649a3b3a 100644 --- a/hotspot/test/compiler/c1/CanonicalizeArrayLength.java +++ b/hotspot/test/compiler/c1/CanonicalizeArrayLength.java @@ -25,10 +25,10 @@ * @test * @bug 8150102 8150514 8150534 * @summary C1 crashes in Canonicalizer::do_ArrayLength() after fix for JDK-8150102 - * @run main/othervm -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation CanonicalizeArrayLength - * @run main/othervm -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:+PatchALot CanonicalizeArrayLength - * @run main/othervm -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:ScavengeRootsInCode=0 CanonicalizeArrayLength - * @run main/othervm -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:ScavengeRootsInCode=1 CanonicalizeArrayLength + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation CanonicalizeArrayLength + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:+PatchALot CanonicalizeArrayLength + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:ScavengeRootsInCode=0 CanonicalizeArrayLength + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:ScavengeRootsInCode=1 CanonicalizeArrayLength */ public class CanonicalizeArrayLength { int[] arr = new int[42]; From 68ce6b3b9f3a3f1cb848225e90ca0840d4f350ba Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Wed, 2 Mar 2016 15:42:03 +0300 Subject: [PATCH 094/129] 8151020: [TESTBUG] UnsafeGetStableArrayElement::testL_* fail intermittently Reviewed-by: zmajo, shade --- .../unsafe/UnsafeGetStableArrayElement.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java index 0cf5f44dc85..e103d46454e 100644 --- a/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java +++ b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java @@ -182,6 +182,10 @@ public class UnsafeGetStableArrayElement { static long testJ_U() { return U.getLongUnaligned( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET + 1); } } + static void run(Callable c) throws Exception { + run(c, null, null); + } + static void run(Callable c, Runnable sameResultAction, Runnable changeResultAction) throws Exception { Object first = c.call(); @@ -295,13 +299,7 @@ public class UnsafeGetStableArrayElement { testMatched( Test::testD_D, Test::changeD); // Object[], aligned accesses - testMismatched(Test::testL_Z, Test::changeL); - testMismatched(Test::testL_B, Test::changeL); - testMismatched(Test::testL_S, Test::changeL); - testMismatched(Test::testL_C, Test::changeL); - testMismatched(Test::testL_I, Test::changeL); - testMismatched(Test::testL_J, Test::changeL); - testMismatched(Test::testL_F, Test::changeL); + testMismatched(Test::testL_J, Test::changeL); // long & double are always as large as an OOP testMismatched(Test::testL_D, Test::changeL); testMatched( Test::testL_L, Test::changeL); @@ -310,5 +308,17 @@ public class UnsafeGetStableArrayElement { testMismatched(Test::testC_U, Test::changeC); testMismatched(Test::testI_U, Test::changeI); testMismatched(Test::testJ_U, Test::changeJ); + + // No way to reliably check the expected behavior: + // (1) OOPs change during GC; + // (2) there's no way to reliably change some part of an OOP (e.g., when reading a byte from it). + // + // Just trigger the compilation hoping to catch any problems with asserts. + run(Test::testL_B); + run(Test::testL_Z); + run(Test::testL_S); + run(Test::testL_C); + run(Test::testL_I); + run(Test::testL_F); } } From 9035e8480580c46282773aa75e9d4ca0e39a89c5 Mon Sep 17 00:00:00 2001 From: Dmitry Samersoff Date: Wed, 2 Mar 2016 17:08:26 +0300 Subject: [PATCH 095/129] 8150318: serviceability/dcmd/jvmti/LoadAgentDcmdTest.java - Could not find JDK_DIR/lib/x86_64/libinstrument.so Refactor test Reviewed-by: jbachorik, sspitsyn --- .../dcmd/jvmti/LoadAgentDcmdTest.java | 76 +++++++++++------ .../dcmd/jvmti/LoadJavaAgentDcmdTest.java | 81 ------------------- .../testlibrary/jdk/test/lib/Platform.java | 29 ++++++- 3 files changed, 81 insertions(+), 105 deletions(-) delete mode 100644 hotspot/test/serviceability/dcmd/jvmti/LoadJavaAgentDcmdTest.java diff --git a/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java b/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java index f0db464e46b..da7224583e0 100644 --- a/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java +++ b/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java @@ -22,6 +22,10 @@ */ import java.io.*; import java.nio.file.*; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; import jdk.test.lib.*; import jdk.test.lib.dcmd.*; import org.testng.annotations.Test; @@ -55,12 +59,7 @@ public class LoadAgentDcmdTest { "'-Dtest.jdk=/path/to/jdk'."); } - Path libpath; - if (Platform.isWindows()) { - libpath = Paths.get(jdkPath, "bin", "instrument.dll"); - } else { - libpath = Paths.get(jdkPath, "lib", Platform.getOsArch(), "libinstrument.so"); - } + Path libpath = Paths.get(jdkPath, Platform.jdkLibPath(), Platform.sharedObjectName("instrument")); if (!libpath.toFile().exists()) { throw new FileNotFoundException( @@ -70,31 +69,62 @@ public class LoadAgentDcmdTest { return libpath.toAbsolutePath().toString(); } + + public void createJarFileForAgent() + throws IOException { + + final String jarName = "agent.jar"; + final String agentClass = "SimpleJvmtiAgent"; + + Manifest manifest = new Manifest(); + + manifest.getMainAttributes().put( + Attributes.Name.MANIFEST_VERSION, "1.0"); + + manifest.getMainAttributes().put( + new Attributes.Name("Agent-Class"), agentClass); + + JarOutputStream target = null; + + try { + target = new + JarOutputStream(new FileOutputStream(jarName), manifest); + JarEntry entry = new JarEntry(agentClass + ".class"); + target.putNextEntry(entry); + target.closeEntry(); + } finally { + target.close(); + } + } + public void run(CommandExecutor executor) { try{ - PrintWriter pw = new PrintWriter("MANIFEST.MF"); - pw.println("Agent-Class: SimpleJvmtiAgent"); - pw.close(); - ProcessBuilder pb = new ProcessBuilder(); - pb.command(new String[] { JDKToolFinder.getJDKTool("jar"), - "cmf", - "MANIFEST.MF", - "agent.jar", - "SimpleJvmtiAgent.class"}); - pb.start().waitFor(); + createJarFileForAgent(); String libpath = getLibInstrumentPath(); + OutputAnalyzer output = null; - // Test 1: No argument - OutputAnalyzer output = executor.execute("JVMTI.agent_load " + - libpath + " agent.jar"); - output.stderrShouldBeEmpty(); - - // Test 2: With argument + // Test 1: Native agent, no arguments output = executor.execute("JVMTI.agent_load " + - libpath + " \"agent.jar=foo=bar\""); + libpath + " agent.jar"); output.stderrShouldBeEmpty(); + + // Test 2: Native agent, with arguments + output = executor.execute("JVMTI.agent_load " + + libpath + " \"agent.jar=foo=bar\""); + output.stderrShouldBeEmpty(); + + // Test 3: Java agent, no arguments + output = executor.execute("JVMTI.agent_load " + + "agent.jar"); + output.stderrShouldBeEmpty(); + + // Test 4: Java agent, with arguments + output = executor.execute("JVMTI.agent_load " + + "\"agent.jar=foo=bar\""); + output.stderrShouldBeEmpty(); + } catch (Exception e) { throw new RuntimeException(e); } diff --git a/hotspot/test/serviceability/dcmd/jvmti/LoadJavaAgentDcmdTest.java b/hotspot/test/serviceability/dcmd/jvmti/LoadJavaAgentDcmdTest.java deleted file mode 100644 index 6c0c17760aa..00000000000 --- a/hotspot/test/serviceability/dcmd/jvmti/LoadJavaAgentDcmdTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -import java.io.*; -import jdk.test.lib.*; -import jdk.test.lib.dcmd.*; -import org.testng.annotations.Test; - -/* - * Test to attach JVMTI java agent. - * - * @test - * @bug 8147388 - * @library /testlibrary - * @modules java.base/sun.misc - * java.compiler - * java.instrument - * java.management - * jdk.jvmstat/sun.jvmstat.monitor - * @build ClassFileInstaller jdk.test.lib.* SimpleJvmtiAgent - * @run main ClassFileInstaller SimpleJvmtiAgent - * @run testng LoadJavaAgentDcmdTest - */ -public class LoadJavaAgentDcmdTest { - public void run(CommandExecutor executor) { - try{ - PrintWriter pw = new PrintWriter("MANIFEST.MF"); - pw.println("Agent-Class: SimpleJvmtiAgent"); - pw.close(); - - ProcessBuilder pb = new ProcessBuilder(); - pb.command(new String[] { JDKToolFinder.getJDKTool("jar"), - "cmf", - "MANIFEST.MF", - "agent.jar", - "SimpleJvmtiAgent.class"}); - pb.start().waitFor(); - - // Test 1: No argument - OutputAnalyzer output = executor.execute("JVMTI.agent_load " + - "agent.jar"); - output.stderrShouldBeEmpty(); - - // Test 2: With argument - output = executor.execute("JVMTI.agent_load " + - "\"agent.jar=foo=bar\""); - output.stderrShouldBeEmpty(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Test - public void jmx() throws Throwable { - run(new JMXExecutor()); - } - - @Test - public void cli() throws Throwable { - run(new PidJcmdExecutor()); - } -} diff --git a/hotspot/test/testlibrary/jdk/test/lib/Platform.java b/hotspot/test/testlibrary/jdk/test/lib/Platform.java index ecd6a0f64d5..64773223556 100644 --- a/hotspot/test/testlibrary/jdk/test/lib/Platform.java +++ b/hotspot/test/testlibrary/jdk/test/lib/Platform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -203,4 +203,31 @@ public class Platform { public static boolean canAttachOSX() throws Exception { return userName.equals("root"); } + + /** + * return path to library inside jdk tree + */ + public static String jdkLibPath() { + if (isWindows()) { + return "bin"; + } + if (isOSX()) { + return "lib"; + } + + return "lib/" + getOsArch(); + } + + /** + * Build name of shared object according to platform rules + */ + public static String sharedObjectName(String name) { + if (isWindows()) { + return name + ".dll"; + } + if (isOSX()) { + return "lib" + name + ".dylib"; + } + return "lib" + name + ".so"; + } } From a07ffdd31d077481ad060e86e45070f610dfd324 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 2 Mar 2016 15:55:47 +0100 Subject: [PATCH 096/129] 8147121: Evacuation failure allocation statistics added too late Move adding evacuation failure statistics to after free_collection_set. Reviewed-by: brutisso, drwhite --- hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index 846b81805aa..2c0f452ba09 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -3384,6 +3384,10 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { g1_policy()->clear_collection_set(); + record_obj_copy_mem_stats(); + _survivor_evac_stats.adjust_desired_plab_sz(); + _old_evac_stats.adjust_desired_plab_sz(); + // Start a new incremental collection set for the next pause. g1_policy()->start_incremental_cset_building(); @@ -4701,11 +4705,6 @@ void G1CollectedHeap::post_evacuate_collection_set(EvacuationInfo& evacuation_in merge_per_thread_state_info(per_thread_states); - record_obj_copy_mem_stats(); - - _survivor_evac_stats.adjust_desired_plab_sz(); - _old_evac_stats.adjust_desired_plab_sz(); - // Reset and re-enable the hot card cache. // Note the counts for the cards in the regions in the // collection set are reset when the collection set is freed. From 619ec3dd6fff42fb5be1242822c025f1dec600f7 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 2 Mar 2016 15:57:48 +0100 Subject: [PATCH 097/129] 8141141: Young and Old gen PLAB stats are similar in output with -XX:+PrintPLAB Improve PLAB statistic by adding generation, output values are now in bytes, including units, and split it into multiple messages. Reviewed-by: brutisso, sjohanss --- .../src/share/vm/gc/cms/parNewGeneration.cpp | 6 +-- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 4 +- hotspot/src/share/vm/gc/g1/g1EvacStats.cpp | 48 ++++++++++++------- hotspot/src/share/vm/gc/g1/g1EvacStats.hpp | 19 +++----- hotspot/src/share/vm/gc/shared/plab.cpp | 37 ++++++++++++-- hotspot/src/share/vm/gc/shared/plab.hpp | 16 ++++++- hotspot/test/gc/g1/TestPLABOutput.java | 4 +- .../test/gc/g1/plab/TestPLABPromotion.java | 11 ++--- hotspot/test/gc/g1/plab/TestPLABResize.java | 4 +- hotspot/test/gc/g1/plab/lib/LogParser.java | 42 ++++++++-------- 10 files changed, 119 insertions(+), 72 deletions(-) diff --git a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp index 6962f158e5c..366bf4671b3 100644 --- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp @@ -615,7 +615,7 @@ ParNewGeneration::ParNewGeneration(ReservedSpace rs, size_t initial_byte_size) : DefNewGeneration(rs, initial_byte_size, "PCopy"), _overflow_list(NULL), _is_alive_closure(this), - _plab_stats(YoungPLABSize, PLABWeight) + _plab_stats("Young", YoungPLABSize, PLABWeight) { NOT_PRODUCT(_overflow_counter = ParGCWorkQueueOverflowInterval;) NOT_PRODUCT(_num_par_pushes = 0;) @@ -1008,9 +1008,7 @@ void ParNewGeneration::collect(bool full, from()->set_concurrent_iteration_safe_limit(from()->top()); to()->set_concurrent_iteration_safe_limit(to()->top()); - if (ResizePLAB) { - plab_stats()->adjust_desired_plab_sz(); - } + plab_stats()->adjust_desired_plab_sz(); TASKQUEUE_STATS_ONLY(thread_state_set.print_termination_stats()); TASKQUEUE_STATS_ONLY(thread_state_set.print_taskqueue_stats()); diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index 2c0f452ba09..743bdd598f7 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -1760,8 +1760,8 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : _young_list(new YoungList(this)), _gc_time_stamp(0), _summary_bytes_used(0), - _survivor_evac_stats(YoungPLABSize, PLABWeight), - _old_evac_stats(OldPLABSize, PLABWeight), + _survivor_evac_stats("Young", YoungPLABSize, PLABWeight), + _old_evac_stats("Old", OldPLABSize, PLABWeight), _expand_heap_after_alloc_failure(true), _old_marking_cycles_started(0), _old_marking_cycles_completed(0), diff --git a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp index a000a1e40ce..1cb7384ed46 100644 --- a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp +++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,15 +29,26 @@ #include "logging/log.hpp" #include "trace/tracing.hpp" +void G1EvacStats::log_plab_allocation() { + PLABStats::log_plab_allocation(); + log_debug(gc, plab)("%s other allocation: " + "region end waste: " SIZE_FORMAT "B, " + "regions filled: %u, " + "direct allocated: " SIZE_FORMAT "B, " + "failure used: " SIZE_FORMAT "B, " + "failure wasted: " SIZE_FORMAT "B", + _description, + _region_end_waste * HeapWordSize, + _regions_filled, + _direct_allocated * HeapWordSize, + _failure_used * HeapWordSize, + _failure_waste * HeapWordSize); +} + void G1EvacStats::adjust_desired_plab_sz() { + log_plab_allocation(); + if (!ResizePLAB) { - log_debug(gc, plab)(" (allocated = " SIZE_FORMAT " wasted = " SIZE_FORMAT " " - "unused = " SIZE_FORMAT " used = " SIZE_FORMAT " " - "undo_waste = " SIZE_FORMAT " region_end_waste = " SIZE_FORMAT " " - "regions filled = %u direct_allocated = " SIZE_FORMAT " " - "failure_used = " SIZE_FORMAT " failure_waste = " SIZE_FORMAT ") ", - _allocated, _wasted, _unused, used(), _undo_wasted, _region_end_waste, - _regions_filled, _direct_allocated, _failure_used, _failure_waste); // Clear accumulators for next round. reset(); return; @@ -107,18 +118,19 @@ void G1EvacStats::adjust_desired_plab_sz() { // Latch the result _desired_net_plab_sz = plab_sz; - log_debug(gc, plab)(" (allocated = " SIZE_FORMAT " wasted = " SIZE_FORMAT " " - "unused = " SIZE_FORMAT " used = " SIZE_FORMAT " " - "undo_waste = " SIZE_FORMAT " region_end_waste = " SIZE_FORMAT " " - "regions filled = %u direct_allocated = " SIZE_FORMAT " " - "failure_used = " SIZE_FORMAT " failure_waste = " SIZE_FORMAT ") " - " (plab_sz = " SIZE_FORMAT " desired_plab_sz = " SIZE_FORMAT ")", - _allocated, _wasted, _unused, used(), _undo_wasted, _region_end_waste, - _regions_filled, _direct_allocated, _failure_used, _failure_waste, - cur_plab_sz, plab_sz); - + log_sizing(cur_plab_sz, plab_sz); // Clear accumulators for next round. reset(); } +G1EvacStats::G1EvacStats(const char* description, size_t desired_plab_sz_, unsigned wt) : + PLABStats(description, desired_plab_sz_, wt), + _region_end_waste(0), + _regions_filled(0), + _direct_allocated(0), + _failure_used(0), + _failure_waste(0) { +} + + G1EvacStats::~G1EvacStats() { } diff --git a/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp b/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp index 1d0a53f5453..b322593e7ea 100644 --- a/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp +++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,20 +51,15 @@ class G1EvacStats : public PLABStats { _failure_waste = 0; } + virtual void log_plab_allocation(); + public: - G1EvacStats(size_t desired_plab_sz_, unsigned wt) : PLABStats(desired_plab_sz_, wt), - _region_end_waste(0), _regions_filled(0), _direct_allocated(0), - _failure_used(0), _failure_waste(0) { - } + G1EvacStats(const char* description, size_t desired_plab_sz_, unsigned wt); + + ~G1EvacStats(); virtual void adjust_desired_plab_sz(); - size_t allocated() const { return _allocated; } - size_t wasted() const { return _wasted; } - size_t unused() const { return _unused; } - size_t used() const { return allocated() - (wasted() + unused()); } - size_t undo_wasted() const { return _undo_wasted; } - uint regions_filled() const { return _regions_filled; } size_t region_end_waste() const { return _region_end_waste; } size_t direct_allocated() const { return _direct_allocated; } @@ -77,8 +72,6 @@ class G1EvacStats : public PLABStats { 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); - - ~G1EvacStats(); }; #endif // SHARE_VM_GC_G1_G1EVACSTATS_HPP diff --git a/hotspot/src/share/vm/gc/shared/plab.cpp b/hotspot/src/share/vm/gc/shared/plab.cpp index d8566523e7c..1743bffb089 100644 --- a/hotspot/src/share/vm/gc/shared/plab.cpp +++ b/hotspot/src/share/vm/gc/shared/plab.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -110,6 +110,30 @@ void PLAB::undo_allocation(HeapWord* obj, size_t word_sz) { } } +void PLABStats::log_plab_allocation() { + log_debug(gc, plab)("%s PLAB allocation: " + "allocated: " SIZE_FORMAT "B, " + "wasted: " SIZE_FORMAT "B, " + "unused: " SIZE_FORMAT "B, " + "used: " SIZE_FORMAT "B, " + "undo waste: " SIZE_FORMAT "B, ", + _description, + _allocated * HeapWordSize, + _wasted * HeapWordSize, + _unused * HeapWordSize, + used() * HeapWordSize, + _undo_wasted * HeapWordSize); +} + +void PLABStats::log_sizing(size_t calculated_words, size_t net_desired_words) { + log_debug(gc, plab)("%s sizing: " + "calculated: " SIZE_FORMAT "B, " + "actual: " SIZE_FORMAT "B", + _description, + calculated_words * HeapWordSize, + net_desired_words * HeapWordSize); +} + // Calculates plab size for current number of gc worker threads. size_t PLABStats::desired_plab_sz(uint no_of_gc_workers) { return MAX2(min_size(), (size_t)align_object_size(_desired_net_plab_sz / no_of_gc_workers)); @@ -119,7 +143,13 @@ size_t PLABStats::desired_plab_sz(uint no_of_gc_workers) { // use. This should be called once at the end of parallel // scavenge; it clears the sensor accumulators. void PLABStats::adjust_desired_plab_sz() { - assert(ResizePLAB, "Not set"); + log_plab_allocation(); + + if (!ResizePLAB) { + // Clear accumulators for next round. + reset(); + return; + } assert(is_object_aligned(max_size()) && min_size() <= max_size(), "PLAB clipping computation may be incorrect"); @@ -150,8 +180,9 @@ void PLABStats::adjust_desired_plab_sz() { new_plab_sz = MIN2(max_size(), new_plab_sz); new_plab_sz = align_object_size(new_plab_sz); // Latch the result - log_trace(gc, plab)("plab_size = " SIZE_FORMAT " desired_net_plab_sz = " SIZE_FORMAT ") ", recent_plab_sz, new_plab_sz); _desired_net_plab_sz = new_plab_sz; + log_sizing(recent_plab_sz, new_plab_sz); + reset(); } diff --git a/hotspot/src/share/vm/gc/shared/plab.hpp b/hotspot/src/share/vm/gc/shared/plab.hpp index b684769ed61..e73562b301f 100644 --- a/hotspot/src/share/vm/gc/shared/plab.hpp +++ b/hotspot/src/share/vm/gc/shared/plab.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,6 +146,8 @@ public: // PLAB book-keeping. class PLABStats : public CHeapObj { protected: + const char* _description; // Identifying string. + size_t _allocated; // Total allocated size_t _wasted; // of which wasted (internal fragmentation) size_t _undo_wasted; // of which wasted on undo (is not used for calculation of PLAB size) @@ -160,8 +162,12 @@ class PLABStats : public CHeapObj { _undo_wasted = 0; _unused = 0; } + + virtual void log_plab_allocation(); + virtual void log_sizing(size_t calculated, size_t net_desired); public: - PLABStats(size_t desired_net_plab_sz_, unsigned wt) : + PLABStats(const char* description, size_t desired_net_plab_sz_, unsigned wt) : + _description(description), _allocated(0), _wasted(0), _undo_wasted(0), @@ -172,6 +178,12 @@ class PLABStats : public CHeapObj { virtual ~PLABStats() { } + size_t allocated() const { return _allocated; } + size_t wasted() const { return _wasted; } + size_t unused() const { return _unused; } + size_t used() const { return allocated() - (wasted() + unused()); } + size_t undo_wasted() const { return _undo_wasted; } + static const size_t min_size() { return PLAB::min_size(); } diff --git a/hotspot/test/gc/g1/TestPLABOutput.java b/hotspot/test/gc/g1/TestPLABOutput.java index a8265ac00c1..4b85b1cbcd6 100644 --- a/hotspot/test/gc/g1/TestPLABOutput.java +++ b/hotspot/test/gc/g1/TestPLABOutput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ public class TestPLABOutput { System.out.println(output.getStdout()); - String pattern = ".*GC\\(0\\) .*allocated = (\\d+).*"; + String pattern = ".*GC\\(0\\) .*allocated: (\\d+).*"; Pattern r = Pattern.compile(pattern); Matcher m = r.matcher(output.getStdout()); diff --git a/hotspot/test/gc/g1/plab/TestPLABPromotion.java b/hotspot/test/gc/g1/plab/TestPLABPromotion.java index 54a56bb5092..7b892f29fa3 100644 --- a/hotspot/test/gc/g1/plab/TestPLABPromotion.java +++ b/hotspot/test/gc/g1/plab/TestPLABPromotion.java @@ -23,7 +23,7 @@ /* * @test TestPLABPromotion - * @bug 8141278 + * @bug 8141278 8141141 * @summary Test PLAB promotion * @requires vm.gc=="G1" | vm.gc=="null" * @requires vm.opt.FlightRecorder != true @@ -130,16 +130,15 @@ public class TestPLABPromotion { long plabAllocatedOld; long directAllocatedOld; long memAllocated = testCase.getMemToFill(); - long wordSize = Platform.is32bit() ? 4l : 8l; LogParser logParser = new LogParser(output); Map survivorStats = getPlabStats(logParser, LogParser.ReportType.SURVIVOR_STATS, GC_ID_SURVIVOR_STATS); Map oldStats = getPlabStats(logParser, LogParser.ReportType.OLD_STATS, GC_ID_OLD_STATS); - plabAllocatedSurvivor = wordSize * survivorStats.get("used"); - directAllocatedSurvivor = wordSize * survivorStats.get("direct_allocated"); - plabAllocatedOld = wordSize * oldStats.get("used"); - directAllocatedOld = wordSize * oldStats.get("direct_allocated"); + plabAllocatedSurvivor = survivorStats.get("used"); + directAllocatedSurvivor = survivorStats.get("direct allocated"); + plabAllocatedOld = oldStats.get("used"); + directAllocatedOld = oldStats.get("direct allocated"); System.out.printf("Survivor PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedSurvivor, directAllocatedSurvivor, memAllocated); System.out.printf("Old PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedOld, directAllocatedOld, memAllocated); diff --git a/hotspot/test/gc/g1/plab/TestPLABResize.java b/hotspot/test/gc/g1/plab/TestPLABResize.java index b07b769baa3..e9aef79c07f 100644 --- a/hotspot/test/gc/g1/plab/TestPLABResize.java +++ b/hotspot/test/gc/g1/plab/TestPLABResize.java @@ -23,7 +23,7 @@ /* * @test TestPLABResize - * @bug 8141278 + * @bug 8141278 8141141 * @summary Test for PLAB resizing * @requires vm.gc=="G1" | vm.gc=="null" * @requires vm.opt.FlightRecorder != true @@ -117,7 +117,7 @@ public class TestPLABResize { .map(item -> { return item.getValue() .get(LogParser.ReportType.SURVIVOR_STATS) - .get("desired_plab_sz"); + .get("actual"); }) .collect(Collectors.toCollection(ArrayList::new)); diff --git a/hotspot/test/gc/g1/plab/lib/LogParser.java b/hotspot/test/gc/g1/plab/lib/LogParser.java index ce2f94ef6e6..2bf933edabd 100644 --- a/hotspot/test/gc/g1/plab/lib/LogParser.java +++ b/hotspot/test/gc/g1/plab/lib/LogParser.java @@ -35,14 +35,12 @@ import java.util.regex.Pattern; * * Typical GC log with PLAB statistics (options - -Xlog:gc=debug,gc+plab=debug) looks like: * - * [2,244s][info ][gc ] GC(30) Concurrent Mark abort - * [2,245s][debug ][gc,plab] GC(33) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) - * [2,245s][debug ][gc,plab] GC(33) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) - * [2,245s][info ][gc ] GC(33) Pause Young (G1 Evacuation Pause) 127M->127M(128M) (2,244s, 2,245s) 0,899ms - * [2,246s][debug ][gc,plab] GC(34) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) - * [2,246s][debug ][gc,plab] GC(34) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) - * [2,246s][info ][gc ] GC(34) Pause Initial Mark (G1 Evacuation Pause) 127M->127M(128M) (2,245s, 2,246s) 0,907ms - + * [0.330s][debug][gc,plab ] GC(0) Young PLAB allocation: allocated: 1825632B, wasted: 29424B, unused: 2320B, used: 1793888B, undo waste: 0B, + * [0.330s][debug][gc,plab ] GC(0) Young other allocation: region end waste: 0B, regions filled: 2, direct allocated: 271520B, failure used: 0B, failure wasted: 0B + * [0.330s][debug][gc,plab ] GC(0) Young sizing: calculated: 358776B, actual: 358776B + * [0.330s][debug][gc,plab ] GC(0) Old PLAB allocation: allocated: 427248B, wasted: 592B, unused: 368584B, used: 58072B, undo waste: 0B, + * [0.330s][debug][gc,plab ] GC(0) Old other allocation: region end waste: 0B, regions filled: 1, direct allocated: 41704B, failure used: 0B, failure wasted: 0B + * [0.330s][debug][gc,plab ] GC(0) Old sizing: calculated: 11608B, actual: 11608B */ final public class LogParser { @@ -53,7 +51,6 @@ final public class LogParser { * Type of parsed log element. */ public static enum ReportType { - SURVIVOR_STATS, OLD_STATS } @@ -64,8 +61,8 @@ final public class LogParser { // GC ID private static final Pattern GC_ID_PATTERN = Pattern.compile("\\[gc,plab\\s*\\] GC\\((\\d+)\\)"); - // Pattern for extraction pair = - private static final Pattern PAIRS_PATTERN = Pattern.compile("\\w+\\s+=\\s+\\d+"); + // Pattern for extraction pair : + private static final Pattern PAIRS_PATTERN = Pattern.compile("\\w* \\w+:\\s+\\d+"); /** * Construct LogParser Object @@ -108,24 +105,29 @@ final public class LogParser { if (matcher.find()) { Map> oneReportItem; ReportType reportType; - // Second line in log is statistics for Old PLAB allocation - if ( !allocationStatistics.containsKey(gc_id.get()) ) { - oneReportItem = new EnumMap<>(ReportType.class); + + if (!allocationStatistics.containsKey(gc_id.get())) { + allocationStatistics.put(gc_id.get(), new EnumMap<>(ReportType.class)); + } + + if ( line.contains("Young") ) { reportType = ReportType.SURVIVOR_STATS; - allocationStatistics.put(gc_id.get(), oneReportItem); } else { - oneReportItem = allocationStatistics.get(gc_id.get()); reportType = ReportType.OLD_STATS; } + oneReportItem = allocationStatistics.get(gc_id.get()); + if (!oneReportItem.containsKey(reportType)) { + oneReportItem.put(reportType,new HashMap()); + } + // Extract all pairs from log. - HashMap plabStats = new HashMap<>(); + Map plabStats = oneReportItem.get(reportType); do { String pair = matcher.group(); - String[] nameValue = pair.replaceAll(" ", "").split("="); - plabStats.put(nameValue[0], Long.parseLong(nameValue[1])); + String[] nameValue = pair.replaceAll(": ", ":").split(":"); + plabStats.put(nameValue[0].trim(), Long.parseLong(nameValue[1])); } while (matcher.find()); - oneReportItem.put(reportType,plabStats); } } } From 1c5a7710e3d6c3d27d47f898cd9528e308154638 Mon Sep 17 00:00:00 2001 From: Rachel Protacio Date: Wed, 2 Mar 2016 10:59:25 -0500 Subject: [PATCH 098/129] 8150746: runtime/logging/ItablesTest.java fails with: java.lang.RuntimeException: 'Resolving: klass: ' missing from stdout/stderr Deleted logging line from code and test because unnecessary Reviewed-by: twisti, coleenp --- hotspot/src/share/vm/interpreter/interpreterRuntime.cpp | 8 -------- hotspot/test/runtime/logging/ItablesTest.java | 1 - 2 files changed, 9 deletions(-) diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp index 166390d8d6b..839eec62153 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp @@ -762,14 +762,6 @@ void InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code byte ConstantPoolCacheEntry* cp_cache_entry = cache_entry(thread); if (cp_cache_entry->is_resolved(bytecode)) return; - if (bytecode == Bytecodes::_invokeinterface) { - if (log_develop_is_enabled(Trace, itables)) { - ResourceMark rm(thread); - log_develop_trace(itables)("Resolving: klass: %s to method: %s", - info.resolved_klass()->name()->as_C_string(), - info.resolved_method()->name()->as_C_string()); - } - } #ifdef ASSERT if (bytecode == Bytecodes::_invokeinterface) { if (info.resolved_method()->method_holder() == diff --git a/hotspot/test/runtime/logging/ItablesTest.java b/hotspot/test/runtime/logging/ItablesTest.java index c1cfd33d865..0fe9d84213c 100644 --- a/hotspot/test/runtime/logging/ItablesTest.java +++ b/hotspot/test/runtime/logging/ItablesTest.java @@ -49,7 +49,6 @@ public class ItablesTest { output.shouldContain("invokespecial resolved method: caller-class:ClassB"); output.shouldContain("invokespecial selected method: resolved-class:ClassB"); output.shouldContain("invokeinterface selected method: receiver-class"); - output.shouldContain("Resolving: klass: "); output.shouldHaveExitValue(0); pb = ProcessTools.createJavaProcessBuilder("-Xlog:itables=trace", "ItablesVtableTest"); From b7658ef0b7f0af83426ec4164b6747bb466db070 Mon Sep 17 00:00:00 2001 From: Rachel Protacio Date: Wed, 2 Mar 2016 15:10:38 -0500 Subject: [PATCH 099/129] 8145098: JNI GetVersion should return JNI_VERSION_9 Updated JNI_VERSION for current version to be JNI_VERSION_9 Reviewed-by: hseigel, gtriantafill, dholmes, alanb --- hotspot/src/share/vm/prims/jni.cpp | 2 +- hotspot/src/share/vm/prims/jni.h | 3 ++- hotspot/src/share/vm/runtime/thread.cpp | 1 + hotspot/test/native_sanity/JniVersion.java | 6 +++--- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index ffca3342ebd..40e3c92668a 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -89,7 +89,7 @@ #include "jvmci/jvmciRuntime.hpp" #endif -static jint CurrentVersion = JNI_VERSION_1_8; +static jint CurrentVersion = JNI_VERSION_9; #ifdef _WIN32 extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* ); diff --git a/hotspot/src/share/vm/prims/jni.h b/hotspot/src/share/vm/prims/jni.h index 582f2c97024..564499f83da 100644 --- a/hotspot/src/share/vm/prims/jni.h +++ b/hotspot/src/share/vm/prims/jni.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1952,6 +1952,7 @@ JNI_OnUnload(JavaVM *vm, void *reserved); #define JNI_VERSION_1_4 0x00010004 #define JNI_VERSION_1_6 0x00010006 #define JNI_VERSION_1_8 0x00010008 +#define JNI_VERSION_9 0x00090000 #ifdef __cplusplus } /* extern "C" */ diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index a411b6868dc..fb5e56e8bdc 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -4133,6 +4133,7 @@ jboolean Threads::is_supported_jni_version(jint version) { if (version == JNI_VERSION_1_4) return JNI_TRUE; if (version == JNI_VERSION_1_6) return JNI_TRUE; if (version == JNI_VERSION_1_8) return JNI_TRUE; + if (version == JNI_VERSION_9) return JNI_TRUE; return JNI_FALSE; } diff --git a/hotspot/test/native_sanity/JniVersion.java b/hotspot/test/native_sanity/JniVersion.java index a85a184c241..e1451d2e9a5 100644 --- a/hotspot/test/native_sanity/JniVersion.java +++ b/hotspot/test/native_sanity/JniVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,12 +27,12 @@ */ public class JniVersion { - public static final int JNI_VERSION_1_8 = 0x00010008; + public static final int JNI_VERSION_9 = 0x00090000; public static void main(String... args) throws Exception { System.loadLibrary("JniVersion"); int res = getJniVersion(); - if (res < JNI_VERSION_1_8) { + if (res != JNI_VERSION_9) { throw new Exception("Unexpected value returned from getJniVersion(): 0x" + Integer.toHexString(res)); } } From 311e77373d270bf6b2328677562ff402b55ab6f9 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Wed, 2 Mar 2016 14:36:55 -0600 Subject: [PATCH 100/129] 8146849: Remove TraceJNIHandleAllocation rather than converting to UL Removed TraceJNIHandleAllocation Reviewed-by: coleenp, dholmes --- hotspot/src/share/vm/runtime/globals.hpp | 3 --- hotspot/src/share/vm/runtime/jniHandles.cpp | 10 +--------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 672b3c340ab..28ecd890b5e 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1433,9 +1433,6 @@ public: product(bool, VerifyMergedCPBytecodes, true, \ "Verify bytecodes after RedefineClasses constant pool merging") \ \ - develop(bool, TraceJNIHandleAllocation, false, \ - "Trace allocation/deallocation of JNI handle blocks") \ - \ develop(bool, TraceBytecodes, false, \ "Trace bytecode execution") \ \ diff --git a/hotspot/src/share/vm/runtime/jniHandles.cpp b/hotspot/src/share/vm/runtime/jniHandles.cpp index 3c4baed8e0e..8e4636bf640 100644 --- a/hotspot/src/share/vm/runtime/jniHandles.cpp +++ b/hotspot/src/share/vm/runtime/jniHandles.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -278,10 +278,6 @@ JNIHandleBlock* JNIHandleBlock::allocate_block(Thread* thread) { // Allocate new block block = new JNIHandleBlock(); _blocks_allocated++; - if (TraceJNIHandleAllocation) { - tty->print_cr("JNIHandleBlock " INTPTR_FORMAT " allocated (%d total blocks)", - p2i(block), _blocks_allocated); - } if (ZapJNIHandleArea) block->zap(); #ifndef PRODUCT // Link new block to list of all allocated blocks @@ -499,10 +495,6 @@ void JNIHandleBlock::rebuild_free_list() { // Not as many free handles as we would like - compute number of new blocks to append _allocate_before_rebuild = (extra + block_size_in_oops - 1) / block_size_in_oops; } - if (TraceJNIHandleAllocation) { - tty->print_cr("Rebuild free list JNIHandleBlock " INTPTR_FORMAT " blocks=%d used=%d free=%d add=%d", - p2i(this), blocks, total-free, free, _allocate_before_rebuild); - } } From 2cfacfc3a461b48e024155f10eb6e63ad3125ee3 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Thu, 3 Mar 2016 11:28:48 +0300 Subject: [PATCH 101/129] 8150723: HSDB toolbar icons are missing Reviewed-by: erikj, dsamersoff --- .../toolbarButtonGraphics/development/Server16.gif | Bin .../toolbarButtonGraphics/development/Server24.gif | Bin .../toolbarButtonGraphics/general/About16.gif | Bin .../toolbarButtonGraphics/general/About24.gif | Bin .../toolbarButtonGraphics/general/Delete16.gif | Bin .../toolbarButtonGraphics/general/Delete24.gif | Bin .../toolbarButtonGraphics/general/Find16.gif | Bin .../toolbarButtonGraphics/general/Help16.gif | Bin .../toolbarButtonGraphics/general/Help24.gif | Bin .../toolbarButtonGraphics/general/History16.gif | Bin .../toolbarButtonGraphics/general/History24.gif | Bin .../toolbarButtonGraphics/general/Information16.gif | Bin .../toolbarButtonGraphics/general/Information24.gif | Bin .../toolbarButtonGraphics/general/New16.gif | Bin .../toolbarButtonGraphics/general/New24.gif | Bin .../toolbarButtonGraphics/general/Open16.gif | Bin .../toolbarButtonGraphics/general/Open24.gif | Bin .../toolbarButtonGraphics/general/Save24.gif | Bin .../toolbarButtonGraphics/general/SaveAs16.gif | Bin .../toolbarButtonGraphics/general/SaveAs24.gif | Bin .../toolbarButtonGraphics/general/Zoom16.gif | Bin .../toolbarButtonGraphics/general/ZoomIn16.gif | Bin .../toolbarButtonGraphics/general/ZoomIn24.gif | Bin .../toolbarButtonGraphics/navigation/Down16.gif | Bin .../toolbarButtonGraphics/navigation/Up16.gif | Bin .../toolbarButtonGraphics/text/AlignCenter16.gif | Bin .../toolbarButtonGraphics/text/AlignCenter24.gif | Bin .../toolbarButtonGraphics/text/AlignLeft16.gif | Bin .../toolbarButtonGraphics/text/AlignLeft24.gif | Bin .../toolbarButtonGraphics/text/AlignRight16.gif | Bin .../toolbarButtonGraphics/text/AlignRight24.gif | Bin 31 files changed, 0 insertions(+), 0 deletions(-) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/development/Server16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/development/Server24.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/About16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/About24.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/Delete16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/Delete24.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/Find16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/Help16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/Help24.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/History16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/History24.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/Information16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/Information24.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/New16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/New24.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/Open16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/Open24.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/Save24.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/SaveAs16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/SaveAs24.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/Zoom16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/ZoomIn16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/general/ZoomIn24.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/navigation/Down16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/navigation/Up16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/text/AlignCenter16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/text/AlignCenter24.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/text/AlignLeft16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/text/AlignLeft24.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/text/AlignRight16.gif (100%) rename hotspot/src/jdk.hotspot.agent/share/classes/{images => }/toolbarButtonGraphics/text/AlignRight24.gif (100%) diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/development/Server16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/development/Server16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/development/Server16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/development/Server16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/development/Server24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/development/Server24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/development/Server24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/development/Server24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/About16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/About16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/About16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/About16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/About24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/About24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/About24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/About24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Delete16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Delete16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Delete16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Delete16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Delete24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Delete24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Delete24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Delete24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Find16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Find16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Find16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Find16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Help16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Help16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Help16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Help16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Help24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Help24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Help24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Help24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/History16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/History16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/History16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/History16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/History24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/History24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/History24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/History24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Information16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Information16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Information16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Information16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Information24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Information24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Information24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Information24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/New16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/New16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/New16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/New16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/New24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/New24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/New24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/New24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Open16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Open16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Open16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Open16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Open24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Open24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Open24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Open24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Save24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Save24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Save24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Save24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/SaveAs16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/SaveAs16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/SaveAs16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/SaveAs16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/SaveAs24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/SaveAs24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/SaveAs24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/SaveAs24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Zoom16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Zoom16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Zoom16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Zoom16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/ZoomIn16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/ZoomIn16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/ZoomIn16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/ZoomIn16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/ZoomIn24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/ZoomIn24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/ZoomIn24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/ZoomIn24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/navigation/Down16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/navigation/Down16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/navigation/Down16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/navigation/Down16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/navigation/Up16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/navigation/Up16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/navigation/Up16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/navigation/Up16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignCenter16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignCenter16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignCenter16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignCenter16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignCenter24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignCenter24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignCenter24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignCenter24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignLeft16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignLeft16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignLeft16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignLeft16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignLeft24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignLeft24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignLeft24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignLeft24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignRight16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignRight16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignRight16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignRight16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignRight24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignRight24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignRight24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignRight24.gif From 041e265d0d9c5999ca22cdcbb2a5f147b0b7e219 Mon Sep 17 00:00:00 2001 From: Andreas Eriksson Date: Thu, 3 Mar 2016 12:36:54 +0100 Subject: [PATCH 102/129] 8150986: serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java failing because expects HPROF JAVA PROFILE 1.0.1 file format Reviewed-by: dcubed, dsamersoff --- .../sa/jmap-hprof/JMapHProfLargeHeapTest.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java index 3ef260a5dfd..33b59c9af07 100644 --- a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java +++ b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,6 @@ import jdk.test.lib.ProcessTools; public class JMapHProfLargeHeapTest { private static final String HEAP_DUMP_FILE_NAME = "heap.hprof"; - private static final String HPROF_HEADER_1_0_1 = "JAVA PROFILE 1.0.1"; private static final String HPROF_HEADER_1_0_2 = "JAVA PROFILE 1.0.2"; private static final long M = 1024L; private static final long G = 1024L * M; @@ -79,8 +78,8 @@ public class JMapHProfLargeHeapTest { } } - // Small heap 22 megabytes, should create 1.0.1 file format - testHProfFileFormat("-Xmx1g", 22 * M, HPROF_HEADER_1_0_1); + // All heap dumps should create 1.0.2 file format + testHProfFileFormat("-Xmx1g", 22 * M, HPROF_HEADER_1_0_2); /** * This test was deliberately commented out since the test system lacks From 2c4627b3991788949d47a921c6a82442b4d12ef8 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Thu, 3 Mar 2016 13:18:53 +0100 Subject: [PATCH 103/129] 8151130: [BACKOUT] Remove Method::_method_data for C1 Backing out the fix for JDK-8147978 because it fails and blocks integration. Reviewed-by: vlivanov, zmajo --- hotspot/src/share/vm/c1/c1_Runtime1.cpp | 26 ++++++++++------------ hotspot/src/share/vm/oops/method.cpp | 5 ++--- hotspot/src/share/vm/oops/method.hpp | 18 --------------- hotspot/src/share/vm/runtime/arguments.cpp | 6 ----- hotspot/src/share/vm/runtime/vmStructs.cpp | 2 +- hotspot/src/share/vm/utilities/macros.hpp | 11 +-------- 6 files changed, 16 insertions(+), 52 deletions(-) diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index 01e639258c8..92c721575d0 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -1502,23 +1502,21 @@ JRT_ENTRY(void, Runtime1::predicate_failed_trap(JavaThread* thread)) nm->make_not_entrant(); methodHandle m(nm->method()); - if (ProfileInterpreter) { - MethodData* mdo = m->method_data(); + MethodData* mdo = m->method_data(); - if (mdo == NULL && !HAS_PENDING_EXCEPTION) { - // Build an MDO. Ignore errors like OutOfMemory; - // that simply means we won't have an MDO to update. - Method::build_interpreter_method_data(m, THREAD); - if (HAS_PENDING_EXCEPTION) { - assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here"); - CLEAR_PENDING_EXCEPTION; - } - mdo = m->method_data(); + if (mdo == NULL && !HAS_PENDING_EXCEPTION) { + // Build an MDO. Ignore errors like OutOfMemory; + // that simply means we won't have an MDO to update. + Method::build_interpreter_method_data(m, THREAD); + if (HAS_PENDING_EXCEPTION) { + assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here"); + CLEAR_PENDING_EXCEPTION; } + mdo = m->method_data(); + } - if (mdo != NULL) { - mdo->inc_trap_count(Deoptimization::Reason_none); - } + if (mdo != NULL) { + mdo->inc_trap_count(Deoptimization::Reason_none); } if (TracePredicateFailedTraps) { diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 1f3eb751413..7620ea9f985 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -383,15 +383,14 @@ void Method::build_interpreter_method_data(const methodHandle& method, TRAPS) { MutexLocker ml(MethodData_lock, THREAD); if (method->method_data() == NULL) { ClassLoaderData* loader_data = method->method_holder()->class_loader_data(); -#if defined(COMPILER2) || INCLUDE_JVMCI MethodData* method_data = MethodData::allocate(loader_data, method, THREAD); if (HAS_PENDING_EXCEPTION) { CompileBroker::log_metaspace_failure(); ClassLoaderDataGraph::set_metaspace_oom(true); return; // return the exception (which is cleared) } + method->set_method_data(method_data); -#endif if (PrintMethodData && (Verbose || WizardMode)) { ResourceMark rm(THREAD); tty->print("build_interpreter_method_data for "); @@ -921,7 +920,7 @@ void Method::unlink_method() { // shared class that failed to load, this->link_method() may // have already been called (before an exception happened), so // this->_method_data may not be NULL. - assert(!DumpSharedSpaces || method_data() == NULL, "unexpected method data?"); + assert(!DumpSharedSpaces || _method_data == NULL, "unexpected method data?"); set_method_data(NULL); clear_method_counters(); diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index fdf7d1f9fb0..8fc7b133a16 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -64,9 +64,7 @@ class Method : public Metadata { friend class JVMCIVMStructs; private: ConstMethod* _constMethod; // Method read-only data. -#if defined(COMPILER2) || INCLUDE_JVMCI MethodData* _method_data; -#endif MethodCounters* _method_counters; AccessFlags _access_flags; // Access flags int _vtable_index; // vtable index of this method (see VtableIndexFlag) @@ -321,7 +319,6 @@ class Method : public Metadata { // InterpreterRuntime::exception_handler_for_exception. static int fast_exception_handler_bci_for(methodHandle mh, KlassHandle ex_klass, int throw_bci, TRAPS); -#if defined(COMPILER2) || INCLUDE_JVMCI // method data access MethodData* method_data() const { return _method_data; @@ -333,10 +330,6 @@ class Method : public Metadata { // the initialization of data otherwise. OrderAccess::release_store_ptr((volatile void *)&_method_data, data); } -#else - MethodData* method_data() const { return NULL; } - void set_method_data(MethodData* data) { } -#endif MethodCounters* method_counters() const { return _method_counters; @@ -646,16 +639,9 @@ class Method : public Metadata { #endif /* CC_INTERP */ static ByteSize from_compiled_offset() { return byte_offset_of(Method, _from_compiled_entry); } static ByteSize code_offset() { return byte_offset_of(Method, _code); } -#if defined(COMPILER2) || INCLUDE_JVMCI static ByteSize method_data_offset() { return byte_offset_of(Method, _method_data); } -#else - static ByteSize method_data_offset() { - ShouldNotReachHere(); - return in_ByteSize(0); - } -#endif static ByteSize method_counters_offset() { return byte_offset_of(Method, _method_counters); } @@ -668,11 +654,7 @@ class Method : public Metadata { static ByteSize signature_handler_offset() { return in_ByteSize(sizeof(Method) + wordSize); } // for code generation -#if defined(COMPILER2) || INCLUDE_JVMCI static int method_data_offset_in_bytes() { return offset_of(Method, _method_data); } -#else - static int method_data_offset_in_bytes() { ShouldNotReachHere(); return 0; } -#endif static int intrinsic_id_offset_in_bytes() { return offset_of(Method, _intrinsic_id); } static int intrinsic_id_size_in_bytes() { return sizeof(u2); } diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index ca25748543e..006e3c94739 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -3464,12 +3464,6 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req } #endif -#if !defined(COMPILER2) && !INCLUDE_JVMCI - UNSUPPORTED_OPTION(ProfileInterpreter, "ProfileInterpreter"); - NOT_PRODUCT(UNSUPPORTED_OPTION(TraceProfileInterpreter, "TraceProfileInterpreter")); - UNSUPPORTED_OPTION(PrintMethodData, "PrintMethodData"); -#endif - #ifndef TIERED // Tiered compilation is undefined. UNSUPPORTED_OPTION(TieredCompilation, "TieredCompilation"); diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 6630da1633c..84d2c6ebd3b 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -390,7 +390,7 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(MethodCounters, _invocation_counter, InvocationCounter) \ nonstatic_field(MethodCounters, _backedge_counter, InvocationCounter) \ nonstatic_field(Method, _constMethod, ConstMethod*) \ - COMPILER2_OR_JVMCI_PRESENT(nonstatic_field(Method, _method_data, MethodData*)) \ + nonstatic_field(Method, _method_data, MethodData*) \ nonstatic_field(Method, _method_counters, MethodCounters*) \ nonstatic_field(Method, _access_flags, AccessFlags) \ nonstatic_field(Method, _vtable_index, int) \ diff --git a/hotspot/src/share/vm/utilities/macros.hpp b/hotspot/src/share/vm/utilities/macros.hpp index 11b4fe4f3aa..ccdb90813b7 100644 --- a/hotspot/src/share/vm/utilities/macros.hpp +++ b/hotspot/src/share/vm/utilities/macros.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, 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 @@ -206,15 +206,6 @@ #define NOT_COMPILER2(code) code #endif // COMPILER2 -// COMPILER2 or JVMCI -#if defined(COMPILER2) || INCLUDE_JVMCI -#define COMPILER2_OR_JVMCI_PRESENT(code) code -#define NOT_COMPILER2_OR_JVMCI(code) -#else -#define COMPILER2_OR_JVMCI_PRESENT(code) -#define NOT_COMPILER2_OR_JVMCI(code) code -#endif - #ifdef TIERED #define TIERED_ONLY(code) code #define NOT_TIERED(code) From c69ad2078e19a4d7e0cbfd992fffd44d9cea2ea8 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Thu, 3 Mar 2016 16:46:58 +0300 Subject: [PATCH 104/129] 8151157: Quarantine test/compiler/unsafe/UnsafeGetStableArrayElement.java Reviewed-by: zmajo, thartmann --- hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java index e103d46454e..1ec5dc5ba17 100644 --- a/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java +++ b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java @@ -27,6 +27,7 @@ * @test * @summary tests on constant folding of unsafe get operations from stable arrays * @library /testlibrary /test/lib + * @ignore 8151137 * * @requires vm.flavor != "client" * From 7c23a31489d82eb71f15f623fbf9ab628a871ada Mon Sep 17 00:00:00 2001 From: Joseph Provino Date: Thu, 3 Mar 2016 12:20:22 -0500 Subject: [PATCH 105/129] 8150984: Invalid VM argument causes crash -XX:G1ConcRefinementServiceIntervalMillis=2147483648 Change maximum range so it can't be negative Reviewed-by: kbarrett, sangheki --- hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp | 2 +- .../src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp | 2 +- hotspot/src/share/vm/gc/g1/g1_globals.hpp | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp index 1e8081e53e0..778b37f058e 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp @@ -68,7 +68,7 @@ ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *nex void ConcurrentG1RefineThread::initialize() { // Current thread activation threshold _threshold = MIN2(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(), - cg1r()->yellow_zone()); + cg1r()->yellow_zone()); // A thread deactivates once the number of buffer reached a deactivation threshold _deactivation_threshold = MAX2(_threshold - MIN2(_threshold, cg1r()->thread_threshold_step()), diff --git a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp index 060b7feb3ad..8df01b58511 100644 --- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp +++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp @@ -70,7 +70,7 @@ G1YoungRemSetSamplingThread::G1YoungRemSetSamplingThread() : void G1YoungRemSetSamplingThread::sleep_before_next_cycle() { MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag); if (!_should_terminate) { - intx waitms = G1ConcRefinementServiceIntervalMillis; // 300, really should be? + uintx waitms = G1ConcRefinementServiceIntervalMillis; // 300, really should be? _monitor.wait(Mutex::_no_safepoint_check_flag, waitms); } } diff --git a/hotspot/src/share/vm/gc/g1/g1_globals.hpp b/hotspot/src/share/vm/gc/g1/g1_globals.hpp index fa210295098..7bc980e0fee 100644 --- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp @@ -107,25 +107,25 @@ "Number of enqueued update buffers that will " \ "trigger concurrent processing. Will be selected ergonomically " \ "by default.") \ - range(0, SIZE_MAX) \ + range(0, max_intx) \ \ product(size_t, G1ConcRefinementRedZone, 0, \ "Maximum number of enqueued update buffers before mutator " \ "threads start processing new ones instead of enqueueing them. " \ "Will be selected ergonomically by default. Zero will disable " \ "concurrent processing.") \ - range(0, SIZE_MAX) \ + range(0, max_intx) \ \ product(size_t, G1ConcRefinementGreenZone, 0, \ "The number of update buffers that are left in the queue by the " \ "concurrent processing threads. Will be selected ergonomically " \ "by default.") \ - range(0, SIZE_MAX) \ + range(0, max_intx) \ \ product(uintx, G1ConcRefinementServiceIntervalMillis, 300, \ "The last concurrent refinement thread wakes up every " \ "specified number of milliseconds to do miscellaneous work.") \ - range(0, max_uintx) \ + range(0, max_jint) \ \ product(size_t, G1ConcRefinementThresholdStep, 0, \ "Each time the rset update queue increases by this amount " \ From 11def8caf10630801d75d22813c02f20557231ea Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Tue, 8 Mar 2016 15:51:49 +0100 Subject: [PATCH 106/129] 8151435: Windows devkit missing 32bit msvcdis120.dll Reviewed-by: tbell --- make/devkit/createWindowsDevkit.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/make/devkit/createWindowsDevkit.sh b/make/devkit/createWindowsDevkit.sh index 187a4c7c154..fd007a01a9b 100644 --- a/make/devkit/createWindowsDevkit.sh +++ b/make/devkit/createWindowsDevkit.sh @@ -74,6 +74,10 @@ if [ ! -d $DEVKIT_ROOT/VC ]; then cp $DEVKIT_ROOT/VC/redist/x86/$MSVCP_DLL $DEVKIT_ROOT/VC/bin/ cp $DEVKIT_ROOT/VC/redist/x64/$MSVCR_DLL $DEVKIT_ROOT/VC/bin/amd64/ cp $DEVKIT_ROOT/VC/redist/x64/$MSVCP_DLL $DEVKIT_ROOT/VC/bin/amd64/ + # The msvcdis dll is needed to run some of the tools in VC/bin but is not + # shipped in that directory. Copy it from the common dir. + cp "$VS_INSTALL_DIR/Common7/IDE/msvcdis${VS_VERSION_NUM_NODOT}.dll" \ + $DEVKIT_ROOT/VC/bin/ fi ################################################################################ From 685358ed9331fc2afad346611ddeb6275b4e29d4 Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Tue, 8 Mar 2016 11:36:30 -0800 Subject: [PATCH 107/129] 8148187: Remove OS X-specific com.apple.concurrent package Removed jdk.deploy.osx module (including com.apple.concurrent) Reviewed-by: alanb, erikj, mchung --- common/bin/unshuffle_list.txt | 8 ++------ make/Images.gmk | 4 ---- make/Main.gmk | 3 --- make/common/NON_CORE_PKGS.gmk | 3 +-- modules.xml | 9 --------- 5 files changed, 3 insertions(+), 24 deletions(-) diff --git a/common/bin/unshuffle_list.txt b/common/bin/unshuffle_list.txt index a419fe43a57..daa919b9444 100644 --- a/common/bin/unshuffle_list.txt +++ b/common/bin/unshuffle_list.txt @@ -1293,12 +1293,8 @@ jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/j2secmod_md.c : jdk/src/win jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/j2secmod_md.h : jdk/src/windows/native/sun/security/pkcs11/j2secmod_md.h jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/p11_md.c : jdk/src/windows/native/sun/security/pkcs11/wrapper/p11_md.c jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/p11_md.h : jdk/src/windows/native/sun/security/pkcs11/wrapper/p11_md.h -jdk/src/jdk.deploy.osx/macosx/classes/com/apple/concurrent/package.html : jdk/src/macosx/classes/com/apple/concurrent/package.html -jdk/src/jdk.deploy.osx/macosx/classes/com/apple/concurrent : jdk/src/macosx/classes/com/apple/concurrent -jdk/src/jdk.deploy.osx/macosx/native/libosx/CFileManager.m : jdk/src/macosx/native/com/apple/eio/CFileManager.m -jdk/src/jdk.deploy.osx/macosx/native/libosx/Dispatch.m : jdk/src/macosx/native/com/apple/concurrent/Dispatch.m -jdk/src/jdk.deploy.osx/macosx/native/libosx/JavaAppLauncher.m : jdk/src/macosx/native/apple/launcher/JavaAppLauncher.m -jdk/src/jdk.deploy.osx/macosx/native/libosx/KeystoreImpl.m : jdk/src/macosx/native/apple/security/KeystoreImpl.m +jdk/src/java.desktop/macosx/native/libosx/CFileManager.m : jdk/src/macosx/native/com/apple/eio/CFileManager.m +jdk/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m : jdk/src/macosx/native/apple/security/KeystoreImpl.m jdk/src/jdk.hprof.agent/share/classes/com/sun/demo/jvmti/hprof : jdk/src/share/classes/com/sun/demo/jvmti/hprof jdk/src/jdk.httpserver/share/classes/com/sun/net/httpserver : jdk/src/share/classes/com/sun/net/httpserver jdk/src/jdk.httpserver/share/classes/sun/net/httpserver : jdk/src/share/classes/sun/net/httpserver diff --git a/make/Images.gmk b/make/Images.gmk index 094f9429920..7fc063773d6 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -62,10 +62,6 @@ ifeq ($(OPENJDK_TARGET_OS), solaris) PROVIDER_MODULES += jdk.crypto.ucrypto endif -ifeq ($(OPENJDK_TARGET_OS), macosx) - MAIN_MODULES += jdk.deploy.osx -endif - JRE_MODULES := $(filter-out $(MODULES_FILTER), $(MAIN_MODULES) $(PROVIDER_MODULES)) JDK_MODULES := $(filter-out $(MODULES_FILTER), $(JRE_MODULES) $(TOOLS_MODULES)) diff --git a/make/Main.gmk b/make/Main.gmk index b354d9de9ab..66509ddfdcb 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -413,9 +413,6 @@ else # Declare dependencies from all other -lib to java.base-lib $(foreach t, $(filter-out java.base-libs, $(LIBS_TARGETS)), \ $(eval $t: java.base-libs)) - # Declare the special case dependency for jdk.deploy.osx where libosx - # links against libosxapp. - jdk.deploy.osx-libs: java.desktop-libs # jdk.accessibility depends on java.desktop jdk.accessibility-libs: java.desktop-libs diff --git a/make/common/NON_CORE_PKGS.gmk b/make/common/NON_CORE_PKGS.gmk index bf02064cf63..7e63750d28f 100644 --- a/make/common/NON_CORE_PKGS.gmk +++ b/make/common/NON_CORE_PKGS.gmk @@ -98,8 +98,7 @@ SMARTCARDIO_PKGS = javax.smartcardio SCTPAPI_PKGS = com.sun.nio.sctp ifeq ($(PLATFORM), macosx) - APPLE_EXT_PKGS = com.apple.concurrent \ - com.apple.eawt \ + APPLE_EXT_PKGS = com.apple.eawt \ com.apple.eawt.event \ com.apple.eio endif diff --git a/modules.xml b/modules.xml index d1b092aaff3..29133b98552 100644 --- a/modules.xml +++ b/modules.xml @@ -300,7 +300,6 @@ java.xml jdk.charsets jdk.crypto.pkcs11 - jdk.deploy.osx jdk.httpserver jdk.jartool jdk.jconsole @@ -421,7 +420,6 @@ sun.security.pkcs jdk.crypto.ec - jdk.deploy.osx jdk.jartool @@ -462,7 +460,6 @@ jdk.crypto.mscapi jdk.crypto.pkcs11 jdk.crypto.ucrypto - jdk.deploy.osx jdk.jartool jdk.policytool jdk.security.auth @@ -473,7 +470,6 @@ java.naming jdk.crypto.ec jdk.crypto.pkcs11 - jdk.deploy.osx jdk.jartool jdk.security.auth @@ -1706,11 +1702,6 @@ jdk.crypto.ucrypto java.base - - jdk.deploy.osx - java.base - java.desktop - jdk.dev java.base From 2610c1da55feb1fbafd49d0033c97d81446301dd Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Wed, 9 Mar 2016 11:15:04 +0100 Subject: [PATCH 108/129] 8151497: Set REQUIRED_OS_NAME and REQUIRED_OS_VERSION on AIX Reviewed-by: erikj --- common/autoconf/generated-configure.sh | 6 +++++- common/autoconf/platform.m4 | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 7a9d7900667..35744afa3fe 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -4862,7 +4862,7 @@ VS_SDK_PLATFORM_NAME_2013= #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1456136781 +DATE_WHEN_GENERATED=1457518447 ############################################################################### # @@ -15118,6 +15118,10 @@ $as_echo "$COMPILE_TYPE" >&6; } REQUIRED_OS_NAME=Darwin REQUIRED_OS_VERSION=11.2 fi + if test "x$OPENJDK_TARGET_OS" = "xaix"; then + REQUIRED_OS_NAME=AIX + REQUIRED_OS_VERSION=7.1 + fi diff --git a/common/autoconf/platform.m4 b/common/autoconf/platform.m4 index 3b7e3e33e5d..7553dfe0323 100644 --- a/common/autoconf/platform.m4 +++ b/common/autoconf/platform.m4 @@ -406,6 +406,10 @@ AC_DEFUN([PLATFORM_SET_RELEASE_FILE_OS_VALUES], REQUIRED_OS_NAME=Darwin REQUIRED_OS_VERSION=11.2 fi + if test "x$OPENJDK_TARGET_OS" = "xaix"; then + REQUIRED_OS_NAME=AIX + REQUIRED_OS_VERSION=7.1 + fi AC_SUBST(REQUIRED_OS_NAME) AC_SUBST(REQUIRED_OS_VERSION) From e53b5a35bec5e9b45d821885c86f15a827c77eb0 Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Wed, 9 Mar 2016 13:24:01 +0100 Subject: [PATCH 109/129] 8151291: $EXEC yields "unknown command" on Cygwin Reviewed-by: jlaskey, hannesw, sdama --- nashorn/.hgignore | 1 + .../jdk/nashorn/internal/objects/Global.java | 9 +-- .../internal/runtime/CommandExecutor.java | 54 +++++++++++++-- .../internal/runtime/ScriptingFunctions.java | 2 +- nashorn/test/script/nosecurity/JDK-8151291.js | 68 +++++++++++++++++++ 5 files changed, 120 insertions(+), 14 deletions(-) create mode 100644 nashorn/test/script/nosecurity/JDK-8151291.js diff --git a/nashorn/.hgignore b/nashorn/.hgignore index cba852416c5..92acdd9d019 100644 --- a/nashorn/.hgignore +++ b/nashorn/.hgignore @@ -28,3 +28,4 @@ test/script/external/* .project .externalToolBuilders/* .settings/* +NashornProfile.txt diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java index db042890cd7..adfb15ba20a 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java @@ -2724,12 +2724,9 @@ public final class Global extends Scope { // Retrieve current state of ENV variables. env.putAll(System.getenv(), scriptEnv._strict); - // Some platforms, e.g., Windows, do not define the PWD environment - // variable, so that the $ENV.PWD property needs to be explicitly - // set. - if (!env.containsKey(ScriptingFunctions.PWD_NAME)) { - env.put(ScriptingFunctions.PWD_NAME, System.getProperty("user.dir"), scriptEnv._strict); - } + // Set the PWD variable to a value that is guaranteed to be understood + // by the underlying platform. + env.put(ScriptingFunctions.PWD_NAME, System.getProperty("user.dir"), scriptEnv._strict); } addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env); diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CommandExecutor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CommandExecutor.java index d8115bc4324..1126e507caf 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CommandExecutor.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CommandExecutor.java @@ -64,6 +64,9 @@ class CommandExecutor { return System.getProperty("os.name").contains("Windows"); }); + // Cygwin drive alias prefix. + private static final String CYGDRIVE = "/cygdrive/"; + // User's home directory private static final String HOME_DIRECTORY = AccessController.doPrivileged((PrivilegedAction)() -> { @@ -388,7 +391,7 @@ class CommandExecutor { * @return resolved Path to file */ private static Path resolvePath(final String cwd, final String fileName) { - return Paths.get(cwd).resolve(fileName).normalize(); + return Paths.get(sanitizePath(cwd)).resolve(fileName).normalize(); } /** @@ -402,7 +405,8 @@ class CommandExecutor { switch (cmd.get(0)) { // Set current working directory. case "cd": - // If zero args then use home dirrectory as cwd else use first arg. + final boolean cygpath = IS_WINDOWS && cwd.startsWith(CYGDRIVE); + // If zero args then use home directory as cwd else use first arg. final String newCWD = cmd.size() < 2 ? HOME_DIRECTORY : cmd.get(1); // Normalize the cwd final Path cwdPath = resolvePath(cwd, newCWD); @@ -418,7 +422,13 @@ class CommandExecutor { } // Set PWD environment variable to be picked up as cwd. - environment.put("PWD", cwdPath.toString()); + // Make sure Cygwin paths look like Unix paths. + String scwd = cwdPath.toString(); + if (cygpath && scwd.length() >= 2 && + Character.isLetter(scwd.charAt(0)) && scwd.charAt(1) == ':') { + scwd = CYGDRIVE + Character.toLowerCase(scwd.charAt(0)) + "/" + scwd.substring(2); + } + environment.put("PWD", scwd); return true; // Set an environment variable. @@ -445,7 +455,8 @@ class CommandExecutor { } /** - * preprocessCommand - scan the command for redirects + * preprocessCommand - scan the command for redirects, and sanitize the + * executable path * @param tokens command tokens * @param cwd current working directory * @param redirectInfo redirection information @@ -471,9 +482,38 @@ class CommandExecutor { command.add(stripQuotes(token)); } + if (command.size() > 0) { + command.set(0, sanitizePath(command.get(0))); + } + return command; } + /** + * Sanitize a path in case the underlying platform is Cygwin. In that case, + * convert from the {@code /cygdrive/x} drive specification to the usual + * Windows {@code X:} format. + * + * @param d a String representing a path + * @return a String representing the same path in a form that can be + * processed by the underlying platform + */ + private static String sanitizePath(final String d) { + if (!IS_WINDOWS || (IS_WINDOWS && !d.startsWith(CYGDRIVE))) { + return d; + } + final String pd = d.substring(CYGDRIVE.length()); + if (pd.length() >= 2 && pd.charAt(1) == '/') { + // drive letter plus / -> convert /cygdrive/x/... to X:/... + return pd.charAt(0) + ":" + pd.substring(1); + } else if (pd.length() == 1) { + // just drive letter -> convert /cygdrive/x to X: + return pd.charAt(0) + ":"; + } + // remaining case: /cygdrive/ -> can't convert + return d; + } + /** * createProcessBuilder - create a ProcessBuilder for the command. * @param command command tokens @@ -485,7 +525,7 @@ class CommandExecutor { // Create new ProcessBuilder. final ProcessBuilder pb = new ProcessBuilder(command); // Set current working directory. - pb.directory(new File(cwd)); + pb.directory(new File(sanitizePath(cwd))); // Map environment variables. final Map processEnvironment = pb.environment(); @@ -523,7 +563,7 @@ class CommandExecutor { // Create ProcessBuilder with cwd and redirects set. createProcessBuilder(command, cwd, redirectInfo); - // If piped the wait for the next command. + // If piped, wait for the next command. if (isPiped) { return; } @@ -765,7 +805,7 @@ class CommandExecutor { /** * process - process a command array of strings - * @param script command script to be processed + * @param tokens command script to be processed */ void process(final List tokens) { // Prepare to accumulate command tokens. diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java index 5c312cc6040..42f17522656 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java @@ -72,7 +72,7 @@ public final class ScriptingFunctions { public static final String EXIT_NAME = "$EXIT"; /** Names of special properties used by $ENV API. */ - public static final String ENV_NAME = "$ENV"; + public static final String ENV_NAME = "$ENV"; /** Name of the environment variable for the current working directory. */ public static final String PWD_NAME = "PWD"; diff --git a/nashorn/test/script/nosecurity/JDK-8151291.js b/nashorn/test/script/nosecurity/JDK-8151291.js new file mode 100644 index 00000000000..9357b71543c --- /dev/null +++ b/nashorn/test/script/nosecurity/JDK-8151291.js @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 $EXEC and $ENV.PWD handling across platforms. + * There must be a java executable in the PATH. + * + * @test + * @option -scripting + * @run + */ + +$EXEC(["java", "-version"]) +if ($EXIT != 0) { + throw 'java executable problem: ' + $ERR +} + +function eq(p, q, e) { + if (p != q) { + throw e + } +} + +function neq(p, q, e) { + if (p == q) { + throw e + } +} + +var File = Java.type("java.io.File"), + System = Java.type("java.lang.System"), + win = System.getProperty("os.name").startsWith("Windows"), + sep = File.separator, + startwd = $ENV.PWD, + upwd = startwd.substring(0, startwd.lastIndexOf(sep)) + +$EXEC("ls") +var ls_startwd = $OUT +$EXEC("cd ..; ls") +var ls_cdupwd = $OUT +eq($ENV.PWD, startwd, 'PWD changed during $EXEC cd') +neq(ls_startwd, ls_cdupwd, 'same ls result for startwd and upwd') + +$ENV.PWD = upwd +eq($ENV.PWD, upwd, '$ENV.PWD change had no effect') +$EXEC("ls") +var ls_epupwd = $OUT +eq(ls_cdupwd, ls_epupwd, 'different results for upwd') From 3b675d58d4640eba80098c4ed977ff4ef21a9297 Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Wed, 9 Mar 2016 15:15:29 +0100 Subject: [PATCH 110/129] 8151518: relax test requirements to reduce dependency on directory contents Reviewed-by: hannesw, sundar --- nashorn/test/script/nosecurity/JDK-8151291.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nashorn/test/script/nosecurity/JDK-8151291.js b/nashorn/test/script/nosecurity/JDK-8151291.js index 9357b71543c..15ae427913c 100644 --- a/nashorn/test/script/nosecurity/JDK-8151291.js +++ b/nashorn/test/script/nosecurity/JDK-8151291.js @@ -59,10 +59,10 @@ var ls_startwd = $OUT $EXEC("cd ..; ls") var ls_cdupwd = $OUT eq($ENV.PWD, startwd, 'PWD changed during $EXEC cd') -neq(ls_startwd, ls_cdupwd, 'same ls result for startwd and upwd') +neq(ls_startwd, ls_cdupwd, 'same ls result for startwd and upwd with $EXEC cd') $ENV.PWD = upwd eq($ENV.PWD, upwd, '$ENV.PWD change had no effect') $EXEC("ls") var ls_epupwd = $OUT -eq(ls_cdupwd, ls_epupwd, 'different results for upwd') +neq(ls_startwd, ls_epupwd, 'same ls result for startwd and upwd with $ENV.PWD cd') From a8987f1075fc5668dd90b08146ecfc1da7c3af00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 9 Mar 2016 15:45:44 +0100 Subject: [PATCH 111/129] 8151515: $EXEC output is truncated Reviewed-by: sundar, jlaskey --- .../internal/runtime/CommandExecutor.java | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CommandExecutor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CommandExecutor.java index 1126e507caf..dcebbbb3db8 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CommandExecutor.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CommandExecutor.java @@ -249,18 +249,22 @@ class CommandExecutor { // Stream to copy to. private final OutputStream output; + private final Thread thread; + Piper(final InputStream input, final OutputStream output) { this.input = input; this.output = output; + this.thread = new Thread(this, "$EXEC Piper"); } /** * start - start the Piper in a new daemon thread + * @return this Piper */ - void start() { - Thread thread = new Thread(this, "$EXEC Piper"); + Piper start() { thread.setDaemon(true); thread.start(); + return this; } /** @@ -295,6 +299,10 @@ class CommandExecutor { } } + public void join() throws InterruptedException { + thread.join(); + } + // Exit thread. } @@ -621,15 +629,17 @@ class CommandExecutor { ByteArrayOutputStream byteOutputStream = null; ByteArrayOutputStream byteErrorStream = null; + final List piperThreads = new ArrayList<>(); + // If input is not redirected. if (inputIsPipe) { // If inputStream other than System.in is provided. if (inputStream != null) { // Pipe inputStream to first process output stream. - new Piper(inputStream, firstProcess.getOutputStream()).start(); + piperThreads.add(new Piper(inputStream, firstProcess.getOutputStream()).start()); } else { // Otherwise assume an input string has been provided. - new Piper(new ByteArrayInputStream(inputString.getBytes()), firstProcess.getOutputStream()).start(); + piperThreads.add(new Piper(new ByteArrayInputStream(inputString.getBytes()), firstProcess.getOutputStream()).start()); } } @@ -638,11 +648,11 @@ class CommandExecutor { // If outputStream other than System.out is provided. if (outputStream != null ) { // Pipe outputStream from last process input stream. - new Piper(lastProcess.getInputStream(), outputStream).start(); + piperThreads.add(new Piper(lastProcess.getInputStream(), outputStream).start()); } else { // Otherwise assume an output string needs to be prepared. byteOutputStream = new ByteArrayOutputStream(BUFFER_SIZE); - new Piper(lastProcess.getInputStream(), byteOutputStream).start(); + piperThreads.add(new Piper(lastProcess.getInputStream(), byteOutputStream).start()); } } @@ -650,11 +660,11 @@ class CommandExecutor { if (errorIsPipe) { // If errorStream other than System.err is provided. if (errorStream != null) { - new Piper(lastProcess.getErrorStream(), errorStream).start(); + piperThreads.add(new Piper(lastProcess.getErrorStream(), errorStream).start()); } else { // Otherwise assume an error string needs to be prepared. byteErrorStream = new ByteArrayOutputStream(BUFFER_SIZE); - new Piper(lastProcess.getErrorStream(), byteErrorStream).start(); + piperThreads.add(new Piper(lastProcess.getErrorStream(), byteErrorStream).start()); } } @@ -662,13 +672,13 @@ class CommandExecutor { for (int i = 0, n = processes.size() - 1; i < n; i++) { final Process prev = processes.get(i); final Process next = processes.get(i + 1); - new Piper(prev.getInputStream(), next.getOutputStream()).start(); + piperThreads.add(new Piper(prev.getInputStream(), next.getOutputStream()).start()); } // Wind up processes. try { // Get the user specified timeout. - long timeout = envVarLongValue("JJS_TIMEOUT"); + final long timeout = envVarLongValue("JJS_TIMEOUT"); // If user specified timeout (milliseconds.) if (timeout != 0) { @@ -683,6 +693,10 @@ class CommandExecutor { // Wait for last process and get exit code. exitCode = lastProcess.waitFor(); } + // Wait for all piper threads to terminate + for (final Piper piper : piperThreads) { + piper.join(); + } // Accumulate the output and error streams. outputString += byteOutputStream != null ? byteOutputStream.toString() : ""; From 7b2839f9ee66f24f1c4415cc82dcc43a8ad52160 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Wed, 9 Mar 2016 16:09:55 -0800 Subject: [PATCH 112/129] 8150704: XALAN: ERROR: 'No more DTM IDs are available' when transforming with lots of temporary result trees Reviewed-by: joehw --- .../org/apache/xalan/internal/xsltc/DOM.java | 6 +- .../xsltc/compiler/ApplyTemplates.java | 20 +- .../internal/xsltc/compiler/CallTemplate.java | 37 +- .../xalan/internal/xsltc/compiler/Sort.java | 60 +- .../xsltc/compiler/SyntaxTreeNode.java | 9 +- .../internal/xsltc/compiler/Template.java | 9 +- .../internal/xsltc/compiler/VariableBase.java | 53 +- .../internal/xsltc/compiler/WithParam.java | 43 +- .../xsltc/dom/AdaptiveResultTreeImpl.java | 13 +- .../xalan/internal/xsltc/dom/DOMAdapter.java | 15 +- .../xalan/internal/xsltc/dom/MultiDOM.java | 52 +- .../xalan/internal/xsltc/dom/SAXImpl.java | 25 +- .../xsltc/dom/SimpleResultTreeImpl.java | 16 +- .../jaxp/unittest/transform/Bug4693341.out | 19 - .../unittest/transform/Bug4693341Test.java | 26 +- .../unittest/transform/Bug4693341_golden.dtd | 39 - .../unittest/transform/Bug4693341_golden.xml | 20 - .../jaxp/unittest/transform/Bug6505031.java | 94 - .../jaxp/unittest/transform/Bug8150704-1.ref | 1 + .../jaxp/unittest/transform/Bug8150704-1.xml | 5 + .../jaxp/unittest/transform/Bug8150704-1.xsl | 76 + .../jaxp/unittest/transform/Bug8150704-2.ref | 83 + .../jaxp/unittest/transform/Bug8150704-2.xml | 2438 +++++++++++++++++ .../jaxp/unittest/transform/Bug8150704-2.xsl | 1935 +++++++++++++ .../unittest/transform/TransformerTest.java | 218 +- 25 files changed, 4916 insertions(+), 396 deletions(-) delete mode 100644 jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341.out delete mode 100644 jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341_golden.dtd delete mode 100644 jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341_golden.xml delete mode 100644 jaxp/test/javax/xml/jaxp/unittest/transform/Bug6505031.java create mode 100644 jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.ref create mode 100644 jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.xml create mode 100644 jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.xsl create mode 100644 jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.ref create mode 100644 jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.xml create mode 100644 jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.xsl diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/DOM.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/DOM.java index 1e6be9a9d85..47534bc4a8e 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/DOM.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/DOM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,9 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: DOM.java,v 1.2.4.1 2005/08/31 10:18:49 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc; @@ -102,4 +99,5 @@ public interface DOM { public int getDocument(); public String getUnparsedEntityURI(String name); public Map getElementsWithIDs(); + public void release(); } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/ApplyTemplates.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/ApplyTemplates.java index 6d6a47c157a..fbbb5c8e986 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/ApplyTemplates.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/ApplyTemplates.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,9 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: ApplyTemplates.java,v 1.2.4.1 2005/09/12 09:59:21 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.compiler; @@ -122,12 +119,10 @@ final class ApplyTemplates extends Instruction { final int current = methodGen.getLocalIndex("current"); // check if sorting nodes is required - final Vector sortObjects = new Vector(); - final Iterator children = elements(); - while (children.hasNext()) { - final SyntaxTreeNode child = children.next(); + final Vector sortObjects = new Vector<>(); + for (final SyntaxTreeNode child : getContents()) { if (child instanceof Sort) { - sortObjects.addElement(child); + sortObjects.addElement((Sort)child); } } @@ -193,6 +188,13 @@ final class ApplyTemplates extends Instruction { applyTemplatesSig); il.append(new INVOKEVIRTUAL(applyTemplates)); + // unmap parameters to release temporary result trees + for (final SyntaxTreeNode child : getContents()) { + if (child instanceof WithParam) { + ((WithParam)child).releaseResultTree(classGen, methodGen); + } + } + // Pop parameter frame if (stylesheet.hasLocalParams() || hasContents()) { il.append(classGen.loadTranslet()); diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/CallTemplate.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/CallTemplate.java index caace085213..2e2ca146e84 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/CallTemplate.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/CallTemplate.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2001-2004 The Apache Software Foundation. @@ -17,18 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: CallTemplate.java,v 1.2.4.1 2005/09/12 10:02:41 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.compiler; -import com.sun.org.apache.bcel.internal.generic.ALOAD; -import com.sun.org.apache.bcel.internal.generic.ASTORE; import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; import com.sun.org.apache.bcel.internal.generic.InstructionList; -import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; @@ -56,7 +49,7 @@ final class CallTemplate extends Instruction { * this array can be either a WithParam or a Param if no WithParam * exists for a particular parameter. */ - private Object[] _parameters = null; + private SyntaxTreeNode[] _parameters = null; /** * The corresponding template which this CallTemplate calls. @@ -147,11 +140,10 @@ final class CallTemplate extends Instruction { // If calling a simply named template, push actual arguments if (_calleeTemplate != null) { - Vector calleeParams = _calleeTemplate.getParameters(); int numParams = _parameters.length; for (int i = 0; i < numParams; i++) { - SyntaxTreeNode node = (SyntaxTreeNode)_parameters[i]; + SyntaxTreeNode node = _parameters[i]; methodSig.append(OBJECT_SIG); // append Object to signature // Push 'null' if Param to indicate no actual parameter specified @@ -170,6 +162,15 @@ final class CallTemplate extends Instruction { methodName, methodSig.toString()))); + // release temporary result trees + if (_parameters != null) { + for (int i = 0; i < _parameters.length; i++) { + if (_parameters[i] instanceof WithParam) { + ((WithParam)_parameters[i]).releaseResultTree(classGen, methodGen); + } + } + } + // Do not need to call Translet.popParamFrame() if we are // calling a simple named template. if (_calleeTemplate == null && (stylesheet.hasLocalParams() || hasContents())) { @@ -203,9 +204,9 @@ final class CallTemplate extends Instruction { private void buildParameterList() { // Put the parameters from the called template into the array first. // This is to ensure the order of the parameters. - Vector defaultParams = _calleeTemplate.getParameters(); + Vector defaultParams = _calleeTemplate.getParameters(); int numParams = defaultParams.size(); - _parameters = new Object[numParams]; + _parameters = new SyntaxTreeNode[numParams]; for (int i = 0; i < numParams; i++) { _parameters[i] = defaultParams.elementAt(i); } @@ -222,15 +223,15 @@ final class CallTemplate extends Instruction { // Search for a Param with the same name for (int k = 0; k < numParams; k++) { - Object object = _parameters[k]; - if (object instanceof Param - && ((Param)object).getName().equals(name)) { + SyntaxTreeNode parm = _parameters[k]; + if (parm instanceof Param + && ((Param)parm).getName().equals(name)) { withParam.setDoParameterOptimization(true); _parameters[k] = withParam; break; } - else if (object instanceof WithParam - && ((WithParam)object).getName().equals(name)) { + else if (parm instanceof WithParam + && ((WithParam)parm).getName().equals(name)) { withParam.setDoParameterOptimization(true); _parameters[k] = withParam; break; diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Sort.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Sort.java index d8264a23f93..f7309e50125 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Sort.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Sort.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2001-2005 The Apache Software Foundation. @@ -17,32 +16,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: Sort.java,v 1.2.4.1 2005/09/12 11:08:12 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.compiler; -import java.text.Collator; import java.util.ArrayList; -import java.util.NoSuchElementException; -import java.util.StringTokenizer; import java.util.Vector; import com.sun.org.apache.bcel.internal.classfile.Field; -import com.sun.org.apache.bcel.internal.classfile.Method; import com.sun.org.apache.bcel.internal.generic.ALOAD; import com.sun.org.apache.bcel.internal.generic.ANEWARRAY; import com.sun.org.apache.bcel.internal.generic.ASTORE; import com.sun.org.apache.bcel.internal.generic.CHECKCAST; import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; import com.sun.org.apache.bcel.internal.generic.GETFIELD; -import com.sun.org.apache.bcel.internal.generic.ICONST; import com.sun.org.apache.bcel.internal.generic.ILOAD; import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; -import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC; -import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; import com.sun.org.apache.bcel.internal.generic.InstructionHandle; import com.sun.org.apache.bcel.internal.generic.InstructionList; import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; @@ -76,13 +65,10 @@ final class Sort extends Instruction implements Closure { private AttributeValue _order; private AttributeValue _caseOrder; private AttributeValue _dataType; - private String _lang; // bug! see 26869 - - private String _data = null; - + private String _lang; // bug! see 26869 private String _className = null; - private ArrayList _closureVars = null; + private ArrayList _closureVars = null; private boolean _needsSortRecordFactory = false; // -- Begin Closure interface -------------------- @@ -115,7 +101,7 @@ final class Sort extends Instruction implements Closure { */ public void addVariable(VariableRefBase variableRef) { if (_closureVars == null) { - _closureVars = new ArrayList(); + _closureVars = new ArrayList<>(); } // Only one reference per variable @@ -246,7 +232,7 @@ final class Sort extends Instruction implements Closure { public static void translateSortIterator(ClassGenerator classGen, MethodGenerator methodGen, Expression nodeSet, - Vector sortObjects) + Vector sortObjects) { final ConstantPoolGen cpg = classGen.getConstantPool(); final InstructionList il = methodGen.getInstructionList(); @@ -312,7 +298,7 @@ final class Sort extends Instruction implements Closure { * Compiles code that instantiates a NodeSortRecordFactory object which * will produce NodeSortRecord objects of a specific type. */ - public static void compileSortRecordFactory(Vector sortObjects, + public static void compileSortRecordFactory(Vector sortObjects, ClassGenerator classGen, MethodGenerator methodGen) { String sortRecordClass = @@ -321,7 +307,7 @@ final class Sort extends Instruction implements Closure { boolean needsSortRecordFactory = false; final int nsorts = sortObjects.size(); for (int i = 0; i < nsorts; i++) { - final Sort sort = (Sort) sortObjects.elementAt(i); + final Sort sort = sortObjects.elementAt(i); needsSortRecordFactory |= sort._needsSortRecordFactory; } @@ -429,7 +415,7 @@ final class Sort extends Instruction implements Closure { + "[" + STRING_SIG + ")V"))); // Initialize closure variables in sortRecordFactory - final ArrayList dups = new ArrayList(); + final ArrayList dups = new ArrayList<>(); for (int j = 0; j < nsorts; j++) { final Sort sort = (Sort) sortObjects.get(j); @@ -437,7 +423,7 @@ final class Sort extends Instruction implements Closure { sort._closureVars.size(); for (int i = 0; i < length; i++) { - VariableRefBase varRef = (VariableRefBase) sort._closureVars.get(i); + VariableRefBase varRef = sort._closureVars.get(i); // Discard duplicate variable references if (dups.contains(varRef)) continue; @@ -455,11 +441,11 @@ final class Sort extends Instruction implements Closure { } } - public static String compileSortRecordFactory(Vector sortObjects, + public static String compileSortRecordFactory(Vector sortObjects, ClassGenerator classGen, MethodGenerator methodGen, String sortRecordClass) { - final XSLTC xsltc = ((Sort)sortObjects.firstElement()).getXSLTC(); + final XSLTC xsltc = (sortObjects.firstElement()).getXSLTC(); final String className = xsltc.getHelperClassName(); final NodeSortRecordFactGenerator sortRecordFactory = @@ -474,15 +460,15 @@ final class Sort extends Instruction implements Closure { // Add a new instance variable for each var in closure final int nsorts = sortObjects.size(); - final ArrayList dups = new ArrayList(); + final ArrayList dups = new ArrayList<>(); for (int j = 0; j < nsorts; j++) { - final Sort sort = (Sort) sortObjects.get(j); + final Sort sort = sortObjects.get(j); final int length = (sort._closureVars == null) ? 0 : sort._closureVars.size(); for (int i = 0; i < length; i++) { - final VariableRefBase varRef = (VariableRefBase) sort._closureVars.get(i); + final VariableRefBase varRef = sort._closureVars.get(i); // Discard duplicate variable references if (dups.contains(varRef)) continue; @@ -600,10 +586,10 @@ final class Sort extends Instruction implements Closure { /** * Create a new auxillary class extending NodeSortRecord. */ - private static String compileSortRecord(Vector sortObjects, + private static String compileSortRecord(Vector sortObjects, ClassGenerator classGen, MethodGenerator methodGen) { - final XSLTC xsltc = ((Sort)sortObjects.firstElement()).getXSLTC(); + final XSLTC xsltc = sortObjects.firstElement().getXSLTC(); final String className = xsltc.getHelperClassName(); // This generates a new class for handling this specific sort @@ -619,10 +605,10 @@ final class Sort extends Instruction implements Closure { // Add a new instance variable for each var in closure final int nsorts = sortObjects.size(); - final ArrayList dups = new ArrayList(); + final ArrayList dups = new ArrayList<>(); for (int j = 0; j < nsorts; j++) { - final Sort sort = (Sort) sortObjects.get(j); + final Sort sort = sortObjects.get(j); // Set the name of the inner class in this sort object sort.setInnerClassName(className); @@ -644,8 +630,7 @@ final class Sort extends Instruction implements Closure { } } - MethodGenerator init = compileInit(sortObjects, sortRecord, - cpg, className); + MethodGenerator init = compileInit(sortRecord, cpg, className); MethodGenerator extract = compileExtract(sortObjects, sortRecord, cpg, className); sortRecord.addMethod(init); @@ -660,8 +645,7 @@ final class Sort extends Instruction implements Closure { * collator in the super calls only when the stylesheet specifies a new * language in xsl:sort. */ - private static MethodGenerator compileInit(Vector sortObjects, - NodeSortRecordGenerator sortRecord, + private static MethodGenerator compileInit(NodeSortRecordGenerator sortRecord, ConstantPoolGen cpg, String className) { @@ -688,7 +672,7 @@ final class Sort extends Instruction implements Closure { /** * Compiles a method that overloads NodeSortRecord.extractValueFromDOM() */ - private static MethodGenerator compileExtract(Vector sortObjects, + private static MethodGenerator compileExtract(Vector sortObjects, NodeSortRecordGenerator sortRecord, ConstantPoolGen cpg, String className) { @@ -730,7 +714,7 @@ final class Sort extends Instruction implements Closure { // Append all the cases for the switch statment for (int level = 0; level < levels; level++) { match[level] = level; - final Sort sort = (Sort)sortObjects.elementAt(level); + final Sort sort = sortObjects.elementAt(level); target[level] = il.append(NOP); sort.translateSelect(sortRecord, extractMethod); il.append(ARETURN); diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java index bfa00213915..3b921a1b815 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,9 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: SyntaxTreeNode.java,v 1.6 2006/06/06 22:34:33 spericas Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.compiler; @@ -519,9 +516,9 @@ public abstract class SyntaxTreeNode implements Constants { // references falling out-of-scope inside the for-each element. // (the cause of which being 'lazy' register allocation for references) for (int i = 0; i < n; i++) { - if( _contents.get(i) instanceof VariableBase) { + if ( _contents.get(i) instanceof VariableBase) { final VariableBase var = (VariableBase)_contents.get(i); - var.unmapRegister(methodGen); + var.unmapRegister(classGen, methodGen); } } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Template.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Template.java index 9450702c90c..9284f2a03a3 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Template.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Template.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,9 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: Template.java,v 1.2.4.1 2005/09/12 11:30:11 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.compiler; @@ -63,7 +60,7 @@ public final class Template extends TopLevelElement { // The list of parameters in this template. This is only used // for simple named templates. - private Vector _parameters = new Vector(); + private Vector _parameters = new Vector<>(); public boolean hasParams() { return _parameters.size() > 0; @@ -85,7 +82,7 @@ public final class Template extends TopLevelElement { _parameters.addElement(param); } - public Vector getParameters() { + public Vector getParameters() { return _parameters; } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/VariableBase.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/VariableBase.java index 7ef4c1cabd6..02e1a5f3ef4 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/VariableBase.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/VariableBase.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2001-2004 The Apache Software Foundation. @@ -17,18 +16,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: VariableBase.java,v 1.5 2005/09/28 13:48:18 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.compiler; import java.util.Vector; +import com.sun.org.apache.bcel.internal.generic.CHECKCAST; import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; import com.sun.org.apache.bcel.internal.generic.Instruction; import com.sun.org.apache.bcel.internal.generic.InstructionList; +import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; +import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; import com.sun.org.apache.bcel.internal.generic.NEW; import com.sun.org.apache.bcel.internal.generic.PUSH; @@ -36,6 +35,7 @@ import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType; +import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ResultTreeType; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; import com.sun.org.apache.xml.internal.utils.XML11Char; @@ -49,21 +49,18 @@ import com.sun.org.apache.xml.internal.utils.XML11Char; */ class VariableBase extends TopLevelElement { - protected QName _name; // The name of the variable. - protected String _escapedName; // The escaped qname of the variable. - protected Type _type; // The type of this variable. - protected boolean _isLocal; // True if the variable is local. - protected LocalVariableGen _local; // Reference to JVM variable - protected Instruction _loadInstruction; // Instruction to load JVM variable + protected QName _name; // The name of the variable. + protected String _escapedName; // The escaped qname of the variable. + protected Type _type; // The type of this variable. + protected boolean _isLocal; // True if the variable is local. + protected LocalVariableGen _local; // Reference to JVM variable + protected Instruction _loadInstruction; // Instruction to load JVM variable protected Instruction _storeInstruction; // Instruction to load JVM variable - protected Expression _select; // Reference to variable expression - protected String select; // Textual repr. of variable expr. + protected Expression _select; // Reference to variable expression + protected String select; // Textual repr. of variable expr. // References to this variable (when local) - protected Vector _refs = new Vector(2); - - // Dependencies to other variables/parameters (for globals only) - protected Vector _dependencies = null; + protected Vector _refs = new Vector<>(2); // Used to make sure parameter field is not added twice protected boolean _ignore = false; @@ -92,7 +89,7 @@ class VariableBase extends TopLevelElement { public void copyReferences(VariableBase var) { final int size = _refs.size(); for (int i = 0; i < size; i++) { - var.addReference((VariableRefBase) _refs.get(i)); + var.addReference(_refs.get(i)); } } @@ -112,8 +109,24 @@ class VariableBase extends TopLevelElement { * Remove the mapping of this variable to a register. * Called when we leave the AST scope of the variable's declaration */ - public void unmapRegister(MethodGenerator methodGen) { + public void unmapRegister(ClassGenerator classGen, MethodGenerator methodGen) { if (_local != null) { + if (_type instanceof ResultTreeType) { + final ConstantPoolGen cpg = classGen.getConstantPool(); + final InstructionList il = methodGen.getInstructionList(); + if (classGen.getStylesheet().callsNodeset() && classGen.getDOMClass().equals(MULTI_DOM_CLASS)) { + final int removeDA = cpg.addMethodref(MULTI_DOM_CLASS, "removeDOMAdapter", "(" + DOM_ADAPTER_SIG + ")V"); + il.append(methodGen.loadDOM()); + il.append(new CHECKCAST(cpg.addClass(MULTI_DOM_CLASS))); + il.append(loadInstruction()); + il.append(new CHECKCAST(cpg.addClass(DOM_ADAPTER_CLASS))); + il.append(new INVOKEVIRTUAL(removeDA)); + } + final int release = cpg.addInterfaceMethodref(DOM_IMPL_CLASS, "release", "()V"); + il.append(loadInstruction()); + il.append(new INVOKEINTERFACE(release, 1)); + } + _local.setEnd(methodGen.getInstructionList().getEnd()); methodGen.removeLocalVariable(_local); _refs = null; @@ -126,7 +139,6 @@ class VariableBase extends TopLevelElement { * the JVM stack. */ public Instruction loadInstruction() { - final Instruction instr = _loadInstruction; if (_loadInstruction == null) { _loadInstruction = _type.LOAD(_local.getIndex()); } @@ -138,7 +150,6 @@ class VariableBase extends TopLevelElement { * into this variable. */ public Instruction storeInstruction() { - final Instruction instr = _storeInstruction; if (_storeInstruction == null) { _storeInstruction = _type.STORE(_local.getIndex()); } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/WithParam.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/WithParam.java index 3a87d59313c..fc2b202ceea 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/WithParam.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/WithParam.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2001-2004 The Apache Software Foundation. @@ -17,15 +16,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: WithParam.java,v 1.2.4.1 2005/09/12 11:38:01 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.compiler; +import com.sun.org.apache.bcel.internal.generic.ALOAD; +import com.sun.org.apache.bcel.internal.generic.ASTORE; +import com.sun.org.apache.bcel.internal.generic.CHECKCAST; import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; +import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; import com.sun.org.apache.bcel.internal.generic.InstructionList; +import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; import com.sun.org.apache.bcel.internal.generic.PUSH; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; @@ -59,6 +60,11 @@ final class WithParam extends Instruction { */ private Expression _select; + /** + * Reference to JVM variable holding temporary result tree. + */ + private LocalVariableGen _domAdapter; + /** * %OPT% This is set to true when the WithParam is used in a CallTemplate * for a simple named template. If this is true, the parameters are @@ -164,8 +170,13 @@ final class WithParam extends Instruction { _select.startIterator(classGen, methodGen); } // If not, compile result tree from parameter body if present. + // Store result tree into local variable for releasing it later else if (hasContents()) { + final InstructionList il = methodGen.getInstructionList(); compileResultTree(classGen, methodGen); + _domAdapter = methodGen.addLocalVariable2("@" + _escapedName, Type.ResultTree.toJCType(), il.getEnd()); + il.append(DUP); + il.append(new ASTORE(_domAdapter.getIndex())); } // If neither are present then store empty string in parameter slot else { @@ -208,4 +219,26 @@ final class WithParam extends Instruction { ADD_PARAMETER_SIG))); il.append(POP); // cleanup stack } + + /** + * Release the compiled result tree. + */ + public void releaseResultTree(ClassGenerator classGen, MethodGenerator methodGen) { + if (_domAdapter != null) { + final ConstantPoolGen cpg = classGen.getConstantPool(); + final InstructionList il = methodGen.getInstructionList(); + if (classGen.getStylesheet().callsNodeset() && classGen.getDOMClass().equals(MULTI_DOM_CLASS)) { + final int removeDA = cpg.addMethodref(MULTI_DOM_CLASS, "removeDOMAdapter", "(" + DOM_ADAPTER_SIG + ")V"); + il.append(methodGen.loadDOM()); + il.append(new CHECKCAST(cpg.addClass(MULTI_DOM_CLASS))); + il.append(new ALOAD(_domAdapter.getIndex())); + il.append(new CHECKCAST(cpg.addClass(DOM_ADAPTER_CLASS))); + il.append(new INVOKEVIRTUAL(removeDA)); + } + final int release = cpg.addInterfaceMethodref(DOM_IMPL_CLASS, "release", "()V"); + il.append(new ALOAD(_domAdapter.getIndex())); + il.append(new INVOKEINTERFACE(release, 1)); + _domAdapter = null; + } + } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/AdaptiveResultTreeImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/AdaptiveResultTreeImpl.java index fc1b1d9412c..cb50cf5d779 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/AdaptiveResultTreeImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/AdaptiveResultTreeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,9 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: AdaptiveResultTreeImpl.java,v 1.2.4.1 2005/09/06 05:52:18 pvedula Exp $ - */ + package com.sun.org.apache.xalan.internal.xsltc.dom; import com.sun.org.apache.xalan.internal.xsltc.DOM; @@ -1338,4 +1336,11 @@ public class AdaptiveResultTreeImpl extends SimpleResultTreeImpl } } + public void release() { + if (_dom != null) { + _dom.release(); + _dom = null; + } + super.release(); + } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/DOMAdapter.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/DOMAdapter.java index a12d9e42c85..4f44ae1baa6 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/DOMAdapter.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/DOMAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,9 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: DOMAdapter.java,v 1.2.4.1 2005/09/06 06:07:28 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.dom; @@ -56,8 +53,6 @@ public final class DOMAdapter implements DOM { private short[] _NSmapping = null; private short[] _NSreverse = null; - private StripFilter _filter = null; - private int _multiDOMMask; public DOMAdapter(DOM dom, @@ -165,9 +160,7 @@ public final class DOMAdapter implements DOM { } } - public void setFilter(StripFilter filter) { - _filter = filter; - } + public void setFilter(StripFilter filter) {} public DTMAxisIterator getTypedChildren(final int type) { final int[] reverse = getReverse(); @@ -464,4 +457,8 @@ public final class DOMAdapter implements DOM { public Map getElementsWithIDs() { return _dom.getElementsWithIDs(); } + + public void release() { + _dom.release(); + } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/MultiDOM.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/MultiDOM.java index fae254fabc8..cf22c31920f 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/MultiDOM.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/MultiDOM.java @@ -1,7 +1,6 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ - /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -30,8 +29,8 @@ import com.sun.org.apache.xml.internal.dtm.DTM; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.dtm.DTMManager; import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIteratorBase; -import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase; import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIterNodeList; +import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; import com.sun.org.apache.xml.internal.utils.SuballocatedIntVector; import java.util.HashMap; @@ -671,4 +670,51 @@ public final class MultiDOM implements DOM { public Map getElementsWithIDs() { return _main.getElementsWithIDs(); } + + public void release() { + _main.release(); + } + + private boolean isMatchingAdapterEntry(DOM entry, DOMAdapter adapter) { + DOM dom = adapter.getDOMImpl(); + + return (entry == adapter) || ( + /* + * Method addDOMAdapter overwrites for AdaptiveResultTreeImpl + * objects the usual entry with an adapter to the nested + * DOM, so we must check this here. See last 'if' statement + * of addDOMAdapter. + */ + (dom instanceof AdaptiveResultTreeImpl) && + (entry instanceof DOMAdapter) && + (((AdaptiveResultTreeImpl)dom).getNestedDOM() == ((DOMAdapter)entry).getDOMImpl()) + ); + } + + public void removeDOMAdapter(DOMAdapter adapter) { + _documents.remove(adapter.getDocumentURI(0)); + DOM dom = adapter.getDOMImpl(); + + if (dom instanceof DTMDefaultBase) { + SuballocatedIntVector ids = ((DTMDefaultBase) dom).getDTMIDs(); + int idsSize = ids.size(); + for (int i = 0; i < idsSize; i++) { + _adapters[ids.elementAt(i) >>> DTMManager.IDENT_DTM_NODE_BITS] = null; + } + } else { + int id = dom.getDocument() >>> DTMManager.IDENT_DTM_NODE_BITS; + if ((id > 0) && (id < _adapters.length) && isMatchingAdapterEntry(_adapters[id], adapter)) { + _adapters[id] = null; + } else { + boolean found = false; + for (int i = 0; i < _adapters.length; i++) { + if (isMatchingAdapterEntry(_adapters[id], adapter)) { + _adapters[i] = null; + found = true; + break; + } + } + } + } + } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SAXImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SAXImpl.java index c6b06931702..9a8bc34892a 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SAXImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SAXImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,9 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: SAXImpl.java,v 1.5 2005/09/28 13:48:37 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.dom; @@ -82,7 +79,7 @@ public final class SAXImpl extends SAX2DTM2 // Namespace prefix-to-uri mapping stuff private int _uriCount = 0; - private int _prefixCount = 0; + // private int _prefixCount = 0; // Stack used to keep track of what whitespace text nodes are protected // by xml:space="preserve" attributes and which nodes that are not. @@ -90,11 +87,11 @@ public final class SAXImpl extends SAX2DTM2 private int _idx = 1; private boolean _preserve = false; - private static final String XML_STRING = "xml:"; + // private static final String XML_STRING = "xml:"; private static final String XML_PREFIX = "xml"; private static final String XMLSPACE_STRING = "xml:space"; private static final String PRESERVE_STRING = "preserve"; - private static final String XMLNS_PREFIX = "xmlns"; + // private static final String XMLNS_PREFIX = "xmlns"; private static final String XML_URI = "http://www.w3.org/XML/1998/namespace"; private boolean _escaping = true; @@ -123,7 +120,7 @@ public final class SAXImpl extends SAX2DTM2 private BitArray _dontEscape = null; // The URI to this document - private String _documentURI = null; + // private String _documentURI = null; static private int _documentURIIndex = 0; // The owner Document when the input source is DOMSource. @@ -143,8 +140,7 @@ public final class SAXImpl extends SAX2DTM2 // Support for access/navigation through org.w3c.dom API private Node[] _nodes; private NodeList[] _nodeLists; - private final static String XML_LANG_ATTRIBUTE = - "http://www.w3.org/XML/1998/namespace:@lang"; + // private final static String XML_LANG_ATTRIBUTE = "http://www.w3.org/XML/1998/namespace:@lang"; /** * Define the origin of the document from which the tree was built @@ -491,6 +487,7 @@ public final class SAXImpl extends SAX2DTM2 /** * Sets up a translet-to-dom type mapping table */ + /* private int[] setupMapping(String[] names, String[] uris, int[] types, int nNames) { // Padding with number of names, because they // may need to be added, i.e for RTFs. See copy03 @@ -502,6 +499,7 @@ public final class SAXImpl extends SAX2DTM2 } return result; } + */ /** * Returns the internal type associated with an expanded QName @@ -1230,9 +1228,6 @@ public final class SAXImpl extends SAX2DTM2 */ public DTMAxisIterator getNamespaceAxisIterator(int axis, int ns) { - - DTMAxisIterator iterator = null; - if (ns == NO_TYPE) { return EMPTYITERATOR; } @@ -1546,7 +1541,6 @@ public final class SAXImpl extends SAX2DTM2 */ public DTMAxisIterator getNthDescendant(int type, int n, boolean includeself) { - DTMAxisIterator source = (DTMAxisIterator) new TypedDescendantIterator(type); return new NthDescendantIterator(n); } @@ -1882,4 +1876,7 @@ public final class SAXImpl extends SAX2DTM2 } } + public void release() { + _dtmManager.release(this, true); + } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SimpleResultTreeImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SimpleResultTreeImpl.java index 6739458a94b..812258a8f76 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SimpleResultTreeImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SimpleResultTreeImpl.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 1999-2004 The Apache Software Foundation. @@ -17,15 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: SimpleResultTreeImpl.java,v 1.2.4.1 2005/09/06 10:09:25 pvedula Exp $ - */ + package com.sun.org.apache.xalan.internal.xsltc.dom; import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.StripFilter; import com.sun.org.apache.xalan.internal.xsltc.TransletException; - import com.sun.org.apache.xml.internal.dtm.Axis; import com.sun.org.apache.xml.internal.dtm.DTM; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; @@ -1014,4 +1010,12 @@ public class SimpleResultTreeImpl extends EmptySerializer implements DOM, DTM public void migrateTo(DTMManager manager) { } + + public void release() + { + if (_documentID != 0) { + _dtmManager.release(this, true); + _documentID = 0; + } + } } diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341.out b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341.out deleted file mode 100644 index e946a45a944..00000000000 --- a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341.out +++ /dev/null @@ -1,19 +0,0 @@ - - -10016 -Wed May 29 12:45:00 PDT 2002 - -ABC -XYZ -1234 Anywhere Street -Palo Alto -California -USA -94303 -NULL -NULL - - - - - \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341Test.java b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341Test.java index f0dc71feb5a..8daef2e5cce 100644 --- a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341Test.java +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package transform; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.net.URL; import javax.xml.parsers.SAXParser; @@ -45,16 +46,27 @@ import org.xml.sax.helpers.DefaultHandler; * @summary Test transform with external dtd. */ public class Bug4693341Test { + // save dtd file to current working directory to avoid writing into source repository + public void copyDTDtoWorkDir() throws IOException { + try (FileInputStream dtdres = new FileInputStream(getClass().getResource("Bug4693341.dtd").getPath()); + FileOutputStream dtdwork = new FileOutputStream("Bug4693341.dtd");) { + int n; + byte[] buffer = new byte[1024]; + while((n = dtdres.read(buffer)) > -1) { + dtdwork.write(buffer, 0, n); + } + } + } @Test public void test() { - boolean status = false; - try { Transformer transformer = TransformerFactory.newInstance().newTransformer(); - String out = getClass().getResource("Bug4693341.out").getPath(); - StreamResult result = new StreamResult(new FileOutputStream(out)); + copyDTDtoWorkDir(); + + File outf = new File("Bug4693341.out"); + StreamResult result = new StreamResult(new FileOutputStream(outf)); String in = getClass().getResource("Bug4693341.xml").getPath(); File file = new File(in); @@ -63,7 +75,7 @@ public class Bug4693341Test { transformer.transform(source, result); //URL inputsource = new URL("file", "", golden); - URL output = new URL("file", "", out); + URL output = new URL("file", "", outf.getPath()); // error happens when trying to parse output String systemId = output.toExternalForm(); @@ -71,10 +83,8 @@ public class Bug4693341Test { InputSource is = new InputSource(systemId); SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); parser.parse(is, new DefaultHandler()); - } catch (Exception ex) { Assert.fail(ex.getMessage()); } } - } diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341_golden.dtd b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341_golden.dtd deleted file mode 100644 index 9e4dd578483..00000000000 --- a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341_golden.dtd +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341_golden.xml b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341_golden.xml deleted file mode 100644 index 5c0928e85ab..00000000000 --- a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341_golden.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - -10016 -Wed May 29 12:45:00 PDT 2002 - -ABC -XYZ -1234 Anywhere Street -Palo Alto -California -USA -94303 -NULL -NULL - - - - - diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug6505031.java b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug6505031.java deleted file mode 100644 index d3fa4fd30f4..00000000000 --- a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug6505031.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package transform; - -import java.io.StringWriter; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - -import org.testng.Assert; -import org.testng.annotations.Test; - -/* - * @bug 6505031 - * @summary Test transformer parses keys and their values coming from different xml documents. - */ -public class Bug6505031 { - - private String getResource(String s) { - return getClass().getResource(s).toString(); - - } - - @Test - public void test() { - Map params = new HashMap(); - - params.put("config", getResource("config.xml")); - params.put("mapsFile", getResource("maps.xml")); - generate(getResource("template.xml"), getResource("transform.xsl"), params); - } - - private void generate(String in, String xsl, Map params) { - try { - Transformer transformer = getTransformer(xsl); - - for (Iterator i = params.entrySet().iterator(); i.hasNext();) { - Map.Entry entry = (Map.Entry) i.next(); - - transformer.setParameter((String) entry.getKey(), entry.getValue()); - } - transform(in, transformer); - } catch (Exception e) { - Assert.fail(e.getMessage()); - } - } - - private Transformer getTransformer(String transform) throws Exception { - TransformerFactory tfactory = TransformerFactory.newInstance(); - - try { - // tfactory.setAttribute("generate-translet", Boolean.TRUE); - } catch (Exception e) { - // Ignore - } - - Transformer transformer = tfactory.newTransformer(new StreamSource(transform)); - return (transformer); - } - - private void transform(String in, Transformer transformer) throws Exception { - StringWriter sw = new StringWriter(); - transformer.transform(new StreamSource(in), new StreamResult(sw)); - String s = sw.toString(); - Assert.assertTrue(s.contains("map1key1value") && s.contains("map2key1value")); - } - -} diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.ref b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.ref new file mode 100644 index 00000000000..0af2588d894 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.ref @@ -0,0 +1 @@ +................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................ diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.xml b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.xml new file mode 100644 index 00000000000..382a25f08fb --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.xml @@ -0,0 +1,5 @@ + + + + . + diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.xsl b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.xsl new file mode 100644 index 00000000000..f390323c2f9 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.xsl @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.ref b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.ref new file mode 100644 index 00000000000..b012e31307c --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.ref @@ -0,0 +1,83 @@ +0fto-erech 200amos-batch 00000000X/ +1FB01 20150709 EWF 2016021207USD 0000,9302122026623 ////////91284422 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000007366,71//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////D8OOoOOooooOoooooO////15/07 P0480715 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40090597 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150630 EWF 2016021206USD 0000,9302122026624 ////////1500006837 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000003844,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////b3oooooooooooooooo////15/07 R1683315 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40127254 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150709 EWF 2016021207CHF 0001,0000022026625 ////////94043801 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000438,50//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////0CooOooooooooooOOo////15/07 P0472115 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30092874 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150702 EWF 2016021207EUR 0001,0468822026626 ////////TL152062 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000661,30//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////3coooooooooooooooo////15/07 P0431815 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40099751 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150617 EWF 2016021206EUR 0001,0468822026627 ////////TKL100216 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000699,92//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////55oooooOoOooooOoOo////15/07 L0032815 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////2014686 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150702 EWF 2016021207EUR 0001,0468822026628 ////////TL152063 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000001983,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9boooooooooooooooo////15/07 P0431815 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40099751 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150713 EWF 2016021207EUR 0001,0468822026629 ////////000359084 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000002230,76//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////51oOoOoOoOoooooOOO////15/07 R1735915 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40128088 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150708 EWF 2016021207CHF 0001,0000022026630 ////////90864081 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000001893,20//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////acoooooooooooooooo////15/07 P0470615 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30090668 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150708 EWF 2016021207USD 0000,9302122026631 ////////123939 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000007896,34//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////09oooooooooooooooo////15/07 P0400015 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40128846 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150707 EWF 2016021207USD 0000,9302122026633 ////////000358117 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000006810,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////f5oooooooooooooooo////15/07 P0462815 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40128088 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150713 EWF 2016021207CHF 0001,0000022026635 ////////M90257500 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000016300,50//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////C3oOOOooOoOooOOOoo////15/07 R1488615 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30124373 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150713 EWF 2016021207USD 0000,9302122026637 ////////M90257457 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000831,90//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////60ooooOooOOOoOoOoo////15/07 P0463815 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30124373 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 40///////////////0000000000055,22//////////////////////////////////////////////// /////////////////////////////////////7000 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////P0463815 ////15/07 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////400158 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150713 EWF 2016021207USD 0000,9302122026638 ////////M90257509 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000002218,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////60OoooooOOooooOooo////15/07 P0491115 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30124373 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 40///////////////0000000000055,22//////////////////////////////////////////////// /////////////////////////////////////7000 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////P0491115 ////15/07 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////400158 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150713 EWF 2016021207CHF 0001,0000022026639 ////////M90257515 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000005833,20//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////A6OOooOoOoOooOoooo////15/07 R1575215 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30124373 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150701 EWF 2016021207USD 0000,9302122026642 ////////C/5 335835 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000515,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////16OooooOooOOoOoooo////15/07 R1612715 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150701 EWF 2016021207USD 0000,9302122026643 ////////C/5 335833 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000835,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////58OOoOOooooOooOOoo////15/07 R1441715 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150706 EWF 2016021207USD 0000,9302122026644 ////////C/5 336036 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000515,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////6BooooOOoooOooOooo////15/07 R1659015 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150701 EWF 2016021207USD 0000,9302122026645 ////////C/5 335836 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000515,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////6DoOoooOooOOoOooOo////15/07 R1613415 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150708 EWF 2016021207USD 0000,9302122026646 ////////C/5 336201 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000515,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////74ooOoOooooooooOoO////15/07 R1728915 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150706 EWF 2016021207USD 0000,9302122026647 ////////C/5 336035 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000515,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////86OoooOOoooOoooOOo////15/07 R1612615 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150706 EWF 2016021207USD 0000,9302122026648 ////////C/5 336034 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000835,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////99OOooooooOooOoooo////15/07 R1445115 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150701 EWF 2016021207USD 0000,9302122026649 ////////C/5 335834 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000835,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////D8OOoooOOOooooOOoo////15/07 R1445315 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150706 EWF 2016021207CHF 0001,0000022026650 ////////351732 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000192,80//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////4BooOooooOOOoOOOOo////15/07 P0448015 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30090682 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150706 EWF 2016021207CHF 0001,0000022026651 ////////351730 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000057,25//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////69ooOoOooooooooooO////15/07 P0451715 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30090682 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 40///////////////0000000000007,02//////////////////////////////////////////////// /////////////////////////////////////7000 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////P0451715 ////15/07 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////400122 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150706 EWF 2016021207CHF 0001,0000022026652 ////////351731 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000100,05//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////A9oooooooOoOooOOOo////15/07 P0448015 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30090682 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150707 EWF 2016021207EUR 0001,0468822026653 ////////05/91014407 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000225,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////22oooOooooOooOooOO////15/07 R1727915 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40096899 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150707 EWF 2016021207EUR 0001,0468822026654 ////////05/91015508 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000225,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////24OooooOOoOooOoOoO////15/07 R1728015 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40096899 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150701 EWF 2016021207EUR 0001,0468822026655 ////////05/91015531 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000768,45//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////76oOOOOooOoOooooOO////15/07 W0054415 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40096899 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150708 EWF 2016021207USD 0000,9302122026656 ////////SI156008034 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000261,79//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////96OooooOoOoooOOOoo////15/07 P0479215 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126601 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150709 EWF 2016021207EUR 0001,0468822026657 ////////05/91015509 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000705,35//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////99ooOoOOoooooOoooo////15/07 R1625015 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40096899 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150713 EWF 2016021207EUR 0001,0468822026662 ////////55941607 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000725,60//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////4BOoooOOOoOoooooOo////15/07 P0486115 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40091085 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150708 EWF 2016021207CHF 0001,0000022026663 ////////100-120606 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000004229,50//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////0boooooooooooooooo////15/07 P0474115 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30094003 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 40///////////////0000000000430,56//////////////////////////////////////////////// /////////////////////////////////////7000 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////P0474115 ////15/07 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////400158 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 40///////////////0000000000054,38//////////////////////////////////////////////// /////////////////////////////////////7000 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////P0474115 ////15/07 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////400122 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150707 EWF 2016021207CHF 0001,0000022026664 ////////13143106 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000318,65//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////6eoooooooooooooooo////15/07 P0468115 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30092269 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 40///////////////0000000000014,04//////////////////////////////////////////////// /////////////////////////////////////7000 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////P0468115 ////15/07 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////400122 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150709 EWF 2016021207EUR 0001,0468822026665 ////////TL152315 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000001983,90//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////74oooooooooooooooo////15/07 P0431815 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40099751 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150710 EWF 2016021207EUR 0001,0468822026667 ////////11321 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000840,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////caoooooooooooooooo////15/07 P0471915 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40129316 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150401 EWF 2016021204EUR 0001,0553176278995 ////////76278995 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000007833,33//////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////15/04 S0026415 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////566//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VERB05001 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20110209 EWF 2016021202CHF 0001,0000090149059 ////////M90149059 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000001077,30//////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////11/03 S0080410 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////566//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30124373 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20110209 EWF 2016021202USD 0000,9570290149062 ////////90149062 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000002185,78//////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////11/03 S0125011 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////566//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30124374 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.xml b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.xml new file mode 100644 index 00000000000..19a8381e919 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.xml @@ -0,0 +1,2438 @@ + + + + 22026623 + + + CRX + CHF + + OPEN + I + V0409 + CAGE1 + 40090597 + + 91284422 + 2015-07-09 + + 2015-07-15 + 2015-07-15 + D8OOoOOooooOoooooOOOOooOoooOoOoo + + 7366.71 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0480715 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-08 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026624 + + + CRX + CHF + + OPEN + I + V0307 + CAGE2 + 40127254 + + 1500006837 + 2015-06-30 + + 2015-07-16 + 2015-07-16 + b3oooooooooooooooooooooooooooooo + + 3844.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1683315 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-07-30 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026625 + + + CRX + CHF + + CLOSED + I + V0568 + 30092874 + + 94043801 + 2015-07-09 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 0CooOooooooooooOOoooOooOoOOoooOo + + 438.5 + 190.008 + 0.0 + 0.0 + + 4V + 32.48 + + + + P + P0472115 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-08 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + 22026626 + + + CRX + CHF + + OPEN + I + V0316 + CAGE3 + 40099751 + + TL152062 + 2015-07-02 + + 2015-07-16 + 2015-07-16 + 3coooooooooooooooooooooooooooooo + + 661.3 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0431815 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-01 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026627 + + + CRX + CHF + + OPEN + I + V0440 + 2014686 + + TKL100216 + 2015-06-17 + + 2015-07-16 + 2015-07-16 + 55oooooOoOooooOoOoOOOoOOOoooOOoo + + 699.92 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + L + L0032815 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-07-17 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026628 + + + CRX + CHF + + OPEN + I + V0316 + CAGE4 + 40099751 + + TL152063 + 2015-07-02 + + 2015-07-16 + 2015-07-16 + 9boooooooooooooooooooooooooooooo + + 1983.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0431815 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-01 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026629 + + + CRX + CHF + + OPEN + I + V0506 + 40128088 + + 000359084 + 2015-07-13 + + 2015-07-16 + 2015-07-16 + 51oOoOoOoOoooooOOOoOooooOOoooOoO + + 2230.76 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1735915 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-12 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026630 + + + CRX + CHF + + OPEN + I + V0497 + 30090668 + + 90864081 + 2015-07-08 + + 2015-07-16 + 2015-07-16 + acoooooooooooooooooooooooooooooo + + 1893.2 + 0.0 + 0.0 + 0.0 + + 4V + 0.0 + + + + P + P0470615 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-07 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + 22026631 + + + CRX + CHF + + OPEN + I + V0512 + 40128846 + + 123939 + 2015-07-08 + + 2015-07-16 + 2015-07-16 + 09oooooooooooooooooooooooooooooo + + 7896.34 + 0.0 + 0.0 + 0.0 + + TAX + 0.0 + + + + P + P0400015 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-07 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026633 + + + CRX + CHF + + CLOSED + I + V0202 + 40128088 + + 000358117 + 2015-07-07 + 2015-07-16 + 2015-07-16 + 2015-07-16 + f5oooooooooooooooooooooooooooooo + + 6810.0 + 3187.08 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0462815 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-06 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026635 + + + CRX + CHF + + OPEN + I + V0011 + 30124373 + + M90257500 + 2015-07-13 + + 2015-07-16 + 2015-07-16 + C3oOOOooOoOooOOOoooOOOoOOoooOoOO + + 16300.5 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1488615 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-12 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + 22026637 + + + CRX + CHF + + CLOSED + I + V0139 + 30124373 + + M90257457 + 2015-07-13 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 60ooooOooOOOoOoOoooooooOOOOoooOO + + 831.9 + 334.1052 + 118.0 + 0.0 + + V0 + 0.0 + + + + P + P0463815 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-12 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + H + HANDLING CHARGE + N + N + + 400158 + + 7000 + 7000 + + + 55.224 + 55.224 + + V0 + V0 + 0.0 + + + D + + + + 22026638 + + + CRX + CHF + + CLOSED + I + V0139 + 30124373 + + M90257509 + 2015-07-13 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 60OoooooOOooooOoooooooooOOooOOOO + + 2218.0 + 982.8 + 118.0 + 0.0 + + V0 + 0.0 + + + + P + P0491115 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-12 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + H + HANDLING CHARGE + N + N + + 400158 + + 7000 + 7000 + + + 55.224 + 55.224 + + V0 + V0 + 0.0 + + + D + + + + 22026639 + + + CRX + CHF + + OPEN + I + V0162 + 30124373 + + M90257515 + 2015-07-13 + + 2015-07-16 + 2015-07-16 + A6OOooOoOoOooOoooooooooOooooOOoo + + 5833.2 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1575215 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-12 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + 22026642 + + + CRX + CHF + + OPEN + I + V0400 + CAGE5 + 40126141 + + C/5 335835 + 2015-07-01 + + 2015-07-16 + 2015-07-16 + 16OooooOooOOoOooooOoooooooooooOO + + 515.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1612715 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-07-31 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026643 + + + CRX + CHF + + OPEN + I + V0400 + CAGE6 + 40126141 + + C/5 335833 + 2015-07-01 + + 2015-07-16 + 2015-07-16 + 58OOoOOooooOooOOooOoooOooooOOoOo + + 835.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1441715 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-07-31 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026644 + + + CRX + CHF + + OPEN + I + V0400 + CAGE7 + 40126141 + + C/5 336036 + 2015-07-06 + + 2015-07-16 + 2015-07-16 + 6BooooOOoooOooOooooOooooOoOOoooo + + 515.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1659015 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-05 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026645 + + + CRX + CHF + + OPEN + I + V0400 + CAGE8 + 40126141 + + C/5 335836 + 2015-07-01 + + 2015-07-16 + 2015-07-16 + 6DoOoooOooOOoOooOoOoOoOOOoOoOooo + + 515.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1613415 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-07-31 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026646 + + + CRX + CHF + + OPEN + I + V0400 + CAGE9 + 40126141 + + C/5 336201 + 2015-07-08 + + 2015-07-16 + 2015-07-16 + 74ooOoOooooooooOoOOOoOoOooOoooOO + + 515.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1728915 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-07 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026647 + + + CRX + CHF + + OPEN + I + V0400 + CAGEA + 40126141 + + C/5 336035 + 2015-07-06 + + 2015-07-16 + 2015-07-16 + 86OoooOOoooOoooOOoOooOoooOOoOoOo + + 515.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1612615 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-05 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026648 + + + CRX + CHF + + OPEN + I + V0400 + CAGEB + 40126141 + + C/5 336034 + 2015-07-06 + + 2015-07-16 + 2015-07-16 + 99OOooooooOooOooooOooOooOoOOoOoo + + 835.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1445115 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-05 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026649 + + + CRX + CHF + + OPEN + I + V0400 + CAGEC + 40126141 + + C/5 335834 + 2015-07-01 + + 2015-07-16 + 2015-07-16 + D8OOoooOOOooooOOoooOOoOoooOoOOOO + + 835.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1445315 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-07-31 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026650 + + + CRX + CHF + + OPEN + I + V0429 + 30090682 + + 351732 + 2015-07-06 + + 2015-07-16 + 2015-07-16 + 4BooOooooOOOoOOOOooo + + 192.8 + 0.0 + 0.0 + 0.0 + + 4V + 0.0 + + + + P + P0448015 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-05 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + 22026651 + + + CRX + CHF + + CLOSED + I + V0429 + 30090682 + + 351730 + 2015-07-06 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 69ooOoOooooooooooOoOooOOOOoooOoO + + 57.25 + 17.784 + 15.0 + 0.0 + + 4V + 4.24 + + + + P + P0451715 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-05 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + F + FREIGHT + N + N + + 400122 + + 7000 + 7000 + + + 7.02 + 7.02 + + 4V + 4V + 0.5616 + + + D + + + + 22026652 + + + CRX + CHF + + OPEN + I + V0429 + 30090682 + + 351731 + 2015-07-06 + + 2015-07-16 + 2015-07-16 + A9oooooooOoOooOOOoOO + + 100.05 + 0.0 + 0.0 + 0.0 + + 4V + 0.0 + + + + P + P0448015 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-05 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + 22026653 + + + CRX + CHF + + OPEN + I + V0028 + CAGED + 40096899 + + 05/91014407 + 2015-07-07 + + 2015-07-16 + 2015-07-16 + 22oooOooooOooOooOOoOooOoooooOooO + + 225.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1727915 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-06 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026654 + + + CRX + CHF + + OPEN + I + V0028 + CAGEE + 40096899 + + 05/91015508 + 2015-07-07 + + 2015-07-16 + 2015-07-16 + 24OooooOOoOooOoOoOoOoooOOoOOooOo + + 225.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1728015 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-06 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026655 + + + CRX + CHF + + CLOSED + I + V0028 + CAGEF + 40096899 + + 05/91015531 + 2015-07-01 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 76oOOOOooOoOooooOOoOoOOooOooOoOO + + 768.45 + 359.6346 + 0.0 + 0.0 + + V0 + 0.0 + + + + W + W0054415 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-07-31 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026656 + + + CRX + CHF + + OPEN + I + V0651 + 40126601 + + SI156008034 + 2015-07-08 + + 2015-07-16 + 2015-07-16 + 96OooooOoOoooOOOoooOOoooOoOOOOoO + + 261.79 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0479215 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-07 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026657 + + + CRX + CHF + + CLOSED + I + V0028 + CAGEG + 40096899 + + 05/91015509 + 2015-07-09 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 99ooOoOOoooooOooooOOOOoooOOoOOoO + + 705.35 + 330.1038 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1625015 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-08 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026662 + + + CRX + CHF + + OPEN + I + V0495 + CAGEH + 40091085 + + 55941607 + 2015-07-13 + + 2015-07-16 + 2015-07-16 + 4BOoooOOOoOoooooOoOOooOooooOoOoo + + 725.6 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0486115 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-12 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026663 + + + CRX + CHF + + CLOSED + I + V0604 + 30094003 + + 100-120606 + 2015-07-08 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 0boooooooooooooooooooooooooooooo + + 4229.5 + 1347.84 + 1036.2 + 0.0 + + TAX + 313.3 + + + + P + P0474115 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-07 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + H + HANDLING CHARGE + N + N + + 400158 + + 7000 + 7000 + + + 430.56 + 430.56 + + 4V + 4V + 34.4448 + + + D + + + + F + FREIGHT + N + N + + 400122 + + 7000 + 7000 + + + 54.3816 + 54.3816 + + 4V + 4V + 4.3524 + + + D + + + + 22026664 + + + CRX + CHF + + CLOSED + I + V0634 + 30092269 + + 13143106 + 2015-07-07 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 6eoooooooooooooooooooooooooooooo + + 318.65 + 124.0434 + 30.0 + 0.0 + + 4V + 23.599999999999998 + + + + P + P0468115 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-06 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + F + FREIGHT + N + N + + 400122 + + 7000 + 7000 + + + 14.04 + 14.04 + + 4V + 4V + 1.1232 + + + D + + + + 22026665 + + + CRX + CHF + + OPEN + I + V0316 + CAGEI + 40099751 + + TL152315 + 2015-07-09 + + 2015-07-16 + 2015-07-16 + 74oooooooooooooooooooooooooooooo + + 1983.9 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0431815 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-08 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026667 + + + CRX + CHF + + OPEN + I + V0642 + 40129316 + + 11321 + 2015-07-10 + + 2015-07-16 + 2015-07-16 + caoooooooooooooooooooooooooooooo + + 840.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0471915 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-09 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 76278995 + + + CRX + CHF + + CLOSED + I + V0166 + CAGEJ + VERB05001 + + 76278995 + 2015-04-01 + 2015-04-17 + 2015-04-17 + 2015-04-17 + + 7833.33 + 3394.4414 + 0.0 + 0.0 + + V0 + 580.25 + + + + S + S0026415 + + + 2016-02-12 + + Y + + + + + + + + + + 2015-04-01 + 0 + Y + + + 04 + 2015 + + + EUR + CHF + 1.05531 + + + + + 90149059 + + + CRX + CHF + + CLOSED + I + V0016 + 30124373 + + M90149059 + 2011-02-09 + 2011-02-18 + 2011-02-18 + 2011-02-18 + + 1077.3 + 504.1764 + 0.0 + 0.0 + + TAX + 0.0 + + + + S + S0080410 + + + 2016-02-12 + + N + + + + 5 + + + + + + 2011-02-09 + 0 + N + + + 03 + 2011 + + + CHF + CHF + 1.0 + + + + + 90149062 + + + CRX + CHF + + CLOSED + I + V0016 + 30124374 + + 90149062 + 2011-02-09 + 2011-02-21 + 2011-02-21 + 2011-02-21 + + 2185.78 + 1022.945 + 0.0 + 0.0 + + TAX + 0.0 + + + + S + S0125011 + + + 2016-02-12 + + N + + + + 6 + + + + + + 2011-02-09 + 0 + N + + + 03 + 2011 + + + USD + CHF + 0.95702 + + + + + diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.xsl b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.xsl new file mode 100644 index 00000000000..3fd6282b3de --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.xsl @@ -0,0 +1,1935 @@ + + + + + + + + + +0 +fto-erech +200 +amos-batch +00000000 +X + + +FB01 +TP +EWF + + +566 +950 + + +2w + +V0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + +KA +EA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/ + + + +/ +/ +/ +/ +/ +X +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + +2 +BBSEG + +31 +21 + +/ +/ +/ + + + + +/ +/ +/ + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + + + + + +/ +/ + + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + +2 +BBSEG + +40 +50 + +/ +/ +/ + + + + +/ +/ +/ + + + +/ +/ +/ +/ + + + + + + + + + + +/ + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + +/ +/ + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + +2 +BBSEG + +40 +50 + +/ +/ +/ + + + +/ +/ +/ + + + +/ +/ +/ +/ + + + + + + + + + + +/ + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + +/ +/ + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + +2 +BBSEG + +40 +50 + +/ +/ +/ + + + + +/ +/ +/ + + + +/ +/ +/ +/ + + + + + + + + + + +/ + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + +/ +/ + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +INVALID ALIGN + + + + \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java b/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java index 18229dc28c9..2e01c5dbe59 100644 --- a/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,13 @@ package transform; +import com.sun.org.apache.xml.internal.serialize.OutputFormat; +import com.sun.org.apache.xml.internal.serialize.XMLSerializer; + +import java.io.BufferedReader; import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; @@ -55,56 +61,67 @@ import org.xml.sax.XMLReader; import org.xml.sax.helpers.AttributesImpl; /* - * @summary Test Transformer. + * @summary Transformer Tests + * @bug 6272879 6305029 6505031 8150704 */ public class TransformerTest { - - private static final String LINE_SEPARATOR = System.getProperty("line.separator"); - - private static final String XML_DOCUMENT = "" + ""; - - //Test for JDK-6305029 - @Test - public final void testTransform() throws TransformerException { - - // test SAXSource - SAXSource saxSource = new SAXSource(new MyXMLReader(), new InputSource()); - - StringWriter builder = new StringWriter(); - TransformerFactory.newInstance().newTransformer().transform(saxSource, new StreamResult(builder)); - - AssertJUnit.assertEquals("Identity transform of SAXSource", XML_DOCUMENT, builder.toString()); - - // test StreamSource - StreamSource streamSource = new StreamSource(new StringReader(XML_DOCUMENT)); - - StringWriter streamResult = new StringWriter(); - - TransformerFactory.newInstance().newTransformer().transform(streamSource, new StreamResult(streamResult)); - - AssertJUnit.assertEquals("Identity transform of StreamSource", XML_DOCUMENT, streamResult.toString()); + private Transformer createTransformer() throws TransformerException { + return TransformerFactory.newInstance().newTransformer(); } - private static class MyXMLReader implements XMLReader { + private Transformer createTransformerFromInputstream(InputStream xslStream) throws TransformerException { + return TransformerFactory.newInstance().newTransformer(new StreamSource(xslStream)); + } + private Transformer createTransformerFromResource(String xslResource) throws TransformerException { + return TransformerFactory.newInstance().newTransformer(new StreamSource(getClass().getResource(xslResource).toString())); + } + + private Document transformInputStreamToDocument(Transformer transformer, InputStream sourceStream) throws TransformerException { + DOMResult response = new DOMResult(); + transformer.transform(new StreamSource(sourceStream), response); + return (Document)response.getNode(); + } + + private StringWriter transformResourceToStringWriter(Transformer transformer, String xmlResource) throws TransformerException { + StringWriter sw = new StringWriter(); + transformer.transform(new StreamSource(getClass().getResource(xmlResource).toString()), new StreamResult(sw)); + return sw; + } + + /** + * Reads the contents of the given file into a string. + * WARNING: this method adds a final line feed even if the last line of the file doesn't contain one. + * + * @param f + * The file to read + * @return The content of the file as a string, with line terminators as \"n" + * for all platforms + * @throws IOException + * If there was an error reading + */ + private String getFileContentAsString(File f) throws IOException { + try (BufferedReader reader = new BufferedReader(new FileReader(f))) { + String line; + StringBuilder sb = new StringBuilder(); + while ((line = reader.readLine()) != null) { + sb.append(line).append("\n"); + } + return sb.toString(); + } + } + + private class XMLReaderFor6305029 implements XMLReader { private static final String NAMESPACES = "http://xml.org/sax/features/namespaces"; - private static final String NAMESPACE_PREFIXES = "http://xml.org/sax/features/namespace-prefixes"; - private boolean namespaces = true; - private boolean namespacePrefixes = false; - private EntityResolver resolver; - private DTDHandler dtdHandler; - private ContentHandler contentHandler; - private ErrorHandler errorHandler; public boolean getFeature(final String name) throws SAXNotRecognizedException, SAXNotSupportedException { - if (name.equals(NAMESPACES)) { return namespaces; } else if (name.equals(NAMESPACE_PREFIXES)) { @@ -115,7 +132,6 @@ public class TransformerTest { } public void setFeature(final String name, final boolean value) throws SAXNotRecognizedException, SAXNotSupportedException { - if (name.equals(NAMESPACES)) { namespaces = value; } else if (name.equals(NAMESPACE_PREFIXES)) { @@ -165,12 +181,10 @@ public class TransformerTest { } public void parse(final InputSource input) throws IOException, SAXException { - parse(); } public void parse(final String systemId) throws IOException, SAXException { - parse(); } @@ -190,30 +204,50 @@ public class TransformerTest { } } + /* + * @bug 6272879 + * @summary Test for JDK-6272879 + */ @Test - public final void testCR6272879() { + public final void testBug6272879() throws IOException, TransformerException { + final String LINE_SEPARATOR = System.getProperty("line.separator"); - final String xsl = "" + LINE_SEPARATOR - + "" + LINE_SEPARATOR - + "" + LINE_SEPARATOR + "" + LINE_SEPARATOR - + "" + LINE_SEPARATOR + " " + LINE_SEPARATOR - + " " + LINE_SEPARATOR + " " + LINE_SEPARATOR - + " " + LINE_SEPARATOR + " " + LINE_SEPARATOR - + " " + LINE_SEPARATOR + " " + LINE_SEPARATOR + " " - + LINE_SEPARATOR + " " + LINE_SEPARATOR + " " + LINE_SEPARATOR + "" + LINE_SEPARATOR - + "" + LINE_SEPARATOR + ""; + final String xsl = + "" + LINE_SEPARATOR + + "" + LINE_SEPARATOR + + "" + LINE_SEPARATOR + + "" + LINE_SEPARATOR + + "" + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + "" + LINE_SEPARATOR + + "" + LINE_SEPARATOR + + ""; - final String sourceXml = "" - + LINE_SEPARATOR + final String sourceXml = + "" + LINE_SEPARATOR + // "" + LINE_SEPARATOR + // "" + LINE_SEPARATOR + // "" + LINE_SEPARATOR + // "]>" + // LINE_SEPARATOR + - + "" + LINE_SEPARATOR + " " + LINE_SEPARATOR + " Valeur 1" + LINE_SEPARATOR - + " " + LINE_SEPARATOR + " " + LINE_SEPARATOR + " Valeur 2" + LINE_SEPARATOR - + " " + LINE_SEPARATOR + ""; + "" + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " Valeur 1" + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " Valeur 2" + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + ""; Document document; Node node; @@ -230,9 +264,12 @@ public class TransformerTest { System.out.println("Source file after transformation:"); System.out.println("================================="); - document = getTransformation(xsl, sourceXml); - - System.out.println(document); + document = transformInputStreamToDocument(createTransformerFromInputstream(new ByteArrayInputStream(xsl.getBytes())), + new ByteArrayInputStream(sourceXml.getBytes())); + OutputFormat format = new OutputFormat(); + format.setIndenting(true); + new XMLSerializer(System.out, format).serialize(document); + System.out.println(); System.out.println("Node content for element valeur2:"); System.out.println("================================="); @@ -248,25 +285,60 @@ public class TransformerTest { } } - private static Document getTransformation(final String xsl, final String sourceXml) { + /* + * @bug 6305029 + * @summary Test for JDK-6305029 + */ + @Test + public final void testBug6305029() throws TransformerException { + final String XML_DOCUMENT = "" + ""; - Transformer transformer; - DOMResult reponse; - Document document = null; + // test SAXSource + SAXSource saxSource = new SAXSource(new XMLReaderFor6305029(), new InputSource()); + StringWriter resultWriter = new StringWriter(); + createTransformer().transform(saxSource, new StreamResult(resultWriter)); + AssertJUnit.assertEquals("Identity transform of SAXSource", XML_DOCUMENT, resultWriter.toString()); - try { - InputStream in = new ByteArrayInputStream(xsl.getBytes()); - transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(in)); + // test StreamSource + StreamSource streamSource = new StreamSource(new StringReader(XML_DOCUMENT)); + resultWriter = new StringWriter(); + createTransformer().transform(streamSource, new StreamResult(resultWriter)); + AssertJUnit.assertEquals("Identity transform of StreamSource", XML_DOCUMENT, resultWriter.toString()); + } - reponse = new DOMResult(); - transformer.transform(new StreamSource(new ByteArrayInputStream(sourceXml.getBytes())), reponse); - document = (Document) reponse.getNode(); - } catch (Exception e) { - String msg = "Exception in getTransformation: " + e; - System.err.println(msg); - Assert.fail(msg); - } + /* + * @bug 6505031 + * @summary Test transformer parses keys and their values coming from different xml documents. + */ + @Test + public final void testBug6505031() throws TransformerException { + Transformer transformer = createTransformerFromResource("transform.xsl"); + transformer.setParameter("config", getClass().getResource("config.xml").toString()); + transformer.setParameter("mapsFile", getClass().getResource("maps.xml").toString()); + String s = transformResourceToStringWriter(transformer, "template.xml").toString(); + Assert.assertTrue(s.contains("map1key1value") && s.contains("map2key1value")); + } - return (document); + /* + * @bug 8150704 + * @summary Test that XSL transformation with lots of temporary result trees will not run out of DTM IDs. + */ + @Test + public final void testBug8150704() throws TransformerException, IOException { + System.out.println("Testing transformation of Bug8150704-1.xml..."); + Transformer transformer = createTransformerFromResource("Bug8150704-1.xsl"); + StringWriter result = transformResourceToStringWriter(transformer, "Bug8150704-1.xml"); + String resultstring = result.toString().replaceAll("\\r\\n", "\n").replaceAll("\\r", "\n"); + String reference = getFileContentAsString(new File(getClass().getResource("Bug8150704-1.ref").getPath())); + Assert.assertEquals(resultstring, reference, "Output of transformation of Bug8150704-1.xml does not match reference"); + System.out.println("Passed."); + + System.out.println("Testing transformation of Bug8150704-2.xml..."); + transformer = createTransformerFromResource("Bug8150704-2.xsl"); + result = transformResourceToStringWriter(transformer, "Bug8150704-2.xml"); + resultstring = result.toString().replaceAll("\\r\\n", "\n").replaceAll("\\r", "\n"); + reference = getFileContentAsString(new File(getClass().getResource("Bug8150704-2.ref").getPath())); + Assert.assertEquals(resultstring, reference, "Output of transformation of Bug8150704-2.xml does not match reference"); + System.out.println("Passed."); } } From de4fe8115c1332fb132d42a699c3aea4ce57cf6a Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 10 Mar 2016 09:28:08 -0800 Subject: [PATCH 113/129] Added tag jdk-9+109 for changeset 7fe73c768138 --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 528a64a3e8c..831d5d6213f 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -351,3 +351,4 @@ be58b02c11f90b88c67e4d0e2cb5e4cf2d9b3c57 jdk-9+105 54575d8783b3a39a2d710c28cda675d44261f9d9 jdk-9+106 4d65eba233a8730f913734a6804910b842d2cb54 jdk-9+107 c7be2a78c31b3b6132f2f5e9e4b3d3bb1c20245c jdk-9+108 +1787bdaabb2b6f4193406e25a50cb0419ea8e8f3 jdk-9+109 From 98f09c95ee424b730f287ba48677b1f005efd75d Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 10 Mar 2016 09:28:09 -0800 Subject: [PATCH 114/129] Added tag jdk-9+109 for changeset 896a46cbffee --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index 43b212133c8..5c2b765d93d 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -351,3 +351,4 @@ e385e95e6101711d5c63e7b1a827e99b6ec7a1cc jdk-9+104 8ec4f97943fe56f93e4621f622b56b7144c0181a jdk-9+106 49202432b69445164a42be7cbdf74ed5fce98157 jdk-9+107 84f2862a25eb3232ff36c376b4e2bf2a83dfced3 jdk-9+108 +b75afa17aefe480c23c616a6a2497063312f7189 jdk-9+109 From e9a96608e0413a336cd1bf5a41f0889f40ad6e80 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 10 Mar 2016 09:28:10 -0800 Subject: [PATCH 115/129] Added tag jdk-9+109 for changeset 9ea881b5873b --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index c77700ff598..cbe0b715f78 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -511,3 +511,4 @@ c5f55130b1b69510d9a6f4a3105b58e21cd7ffe1 jdk-9+103 7232de4c17c37f60aecec4f3191090bd3d41d334 jdk-9+106 c5146d4da417f76edfc43097d2e2ced042a65b4e jdk-9+107 934f6793f5f7dca44f69b4559d525fa64b31840d jdk-9+108 +7e7e50ac4faf19899fc811569e32cfa478759ebb jdk-9+109 From 5da9e80b884c1b35dffc1890e0b945f66874b8e2 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 10 Mar 2016 09:28:13 -0800 Subject: [PATCH 116/129] Added tag jdk-9+109 for changeset 94d8adc2f94d --- jaxp/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index b070406ac71..9a01ef541fc 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -351,3 +351,4 @@ bdbf2342b21bd8ecad1b4e6499a0dfb314952bd7 jdk-9+103 65d615f71e81bae46dcb4d053e590582e5705879 jdk-9+106 781b83dadcae89b8ae7545bb4044ddc62c6fa006 jdk-9+107 3b9fa8b1491479f7ae18131a34036b58b647493e jdk-9+108 +24e247ee1fffaa625d480b2a4eef2d3a8a59f5cb jdk-9+109 From 9dda52e2c5685753100b47c3b180efdb18fe23c5 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 10 Mar 2016 09:28:14 -0800 Subject: [PATCH 117/129] Added tag jdk-9+109 for changeset 67e5c45fdf9a --- jaxws/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 64b08144ae1..d02e1de4e0c 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -354,3 +354,4 @@ eb5e005a17e50d7d8340daaf21a5c3c5ae358d68 jdk-9+103 c072c572d14948563ef5d86e1921699b3a2396ab jdk-9+106 fafd694e801f0f5a7c737fb08630ced3ca8f772c jdk-9+107 513eb2e432f64f85992442da9acdfcfbb36555d9 jdk-9+108 +4b0697e4ce8940b1599af274ff02296d7f59aded jdk-9+109 From aef516391e5f61dc76a7b0912451545868e653bf Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 10 Mar 2016 09:28:20 -0800 Subject: [PATCH 118/129] Added tag jdk-9+109 for changeset 2ab100ef7bb0 --- nashorn/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/nashorn/.hgtags b/nashorn/.hgtags index 265117bfdc0..98a913b7fce 100644 --- a/nashorn/.hgtags +++ b/nashorn/.hgtags @@ -342,3 +342,4 @@ a618d3e89fdea5361895ef142a59074fe7ae3d98 jdk-9+104 cfb3167456932b14c16a6d4cffd5fe295fbe01ff jdk-9+106 8042e81b530e480dfdad41fd53a7a26f69ebba26 jdk-9+107 58409eff7e3e0c07f12f543341769964619c0acf jdk-9+108 +70f0c397021116d7dbd79b01c6711c5d2e68dab4 jdk-9+109 From bb8ef1b3c61ddf39814dbc8eee214a347fdc567d Mon Sep 17 00:00:00 2001 From: Yuji Kubota Date: Fri, 11 Mar 2016 09:27:56 +0100 Subject: [PATCH 119/129] 8151685: Fix the version of required jdk in configure help text Reviewed-by: erikj --- common/autoconf/generated-configure.sh | 6 +++--- common/autoconf/help.m4 | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 35744afa3fe..58beee04e52 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -4005,7 +4005,7 @@ apt_help() { devkit) PKGHANDLER_COMMAND="sudo apt-get install build-essential" ;; openjdk) - PKGHANDLER_COMMAND="sudo apt-get install openjdk-7-jdk" ;; + PKGHANDLER_COMMAND="sudo apt-get install openjdk-8-jdk" ;; alsa) PKGHANDLER_COMMAND="sudo apt-get install libasound2-dev" ;; cups) @@ -4026,7 +4026,7 @@ yum_help() { devkit) PKGHANDLER_COMMAND="sudo yum groupinstall \"Development Tools\"" ;; openjdk) - PKGHANDLER_COMMAND="sudo yum install java-1.7.0-openjdk" ;; + PKGHANDLER_COMMAND="sudo yum install java-1.8.0-openjdk-devel" ;; alsa) PKGHANDLER_COMMAND="sudo yum install alsa-lib-devel" ;; cups) @@ -4862,7 +4862,7 @@ VS_SDK_PLATFORM_NAME_2013= #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1457518447 +DATE_WHEN_GENERATED=1457684806 ############################################################################### # diff --git a/common/autoconf/help.m4 b/common/autoconf/help.m4 index e266dbf414b..d0892c56256 100644 --- a/common/autoconf/help.m4 +++ b/common/autoconf/help.m4 @@ -106,7 +106,7 @@ apt_help() { devkit) PKGHANDLER_COMMAND="sudo apt-get install build-essential" ;; openjdk) - PKGHANDLER_COMMAND="sudo apt-get install openjdk-7-jdk" ;; + PKGHANDLER_COMMAND="sudo apt-get install openjdk-8-jdk" ;; alsa) PKGHANDLER_COMMAND="sudo apt-get install libasound2-dev" ;; cups) @@ -127,7 +127,7 @@ yum_help() { devkit) PKGHANDLER_COMMAND="sudo yum groupinstall \"Development Tools\"" ;; openjdk) - PKGHANDLER_COMMAND="sudo yum install java-1.7.0-openjdk" ;; + PKGHANDLER_COMMAND="sudo yum install java-1.8.0-openjdk-devel" ;; alsa) PKGHANDLER_COMMAND="sudo yum install alsa-lib-devel" ;; cups) From a261b38d274a7938eee27abae1f6369f179a77aa Mon Sep 17 00:00:00 2001 From: Srinivas Dama Date: Fri, 11 Mar 2016 11:35:20 +0100 Subject: [PATCH 120/129] 8138906: [TEST_BUG] Test test/script/trusted/JDK-8087292.js intermittently fails Reviewed-by: hannesw, mhaupt --- nashorn/test/script/trusted/JDK-8087292.js | 50 ++++++++++--- nashorn/test/script/trusted/JDK-util.js | 85 ++++++++++++++++++++++ 2 files changed, 126 insertions(+), 9 deletions(-) create mode 100644 nashorn/test/script/trusted/JDK-util.js diff --git a/nashorn/test/script/trusted/JDK-8087292.js b/nashorn/test/script/trusted/JDK-8087292.js index 41869ed68dc..fec9efb37c4 100644 --- a/nashorn/test/script/trusted/JDK-8087292.js +++ b/nashorn/test/script/trusted/JDK-8087292.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,26 +29,58 @@ * @run */ +load(__DIR__ + "JDK-util.js") + +var jHomePath = System.getenv("JAVA_HOME") +var jLauncher = "${jHomePath}/bin/java" +var altjLauncher = which('java') + +if (windows) { + if(winCyg) { + jLauncher = "${jHomePath}" + "/bin/java.exe" + jLauncher = cygpath(jLauncher,outPath.windows) + } + else { + jLauncher = "${jHomePath}" + "\\bin\\java.exe" + altjLauncher = which('java.exe') + altjLauncher = cygpath(altjLauncher,outPath.windows) + } +} + +function exists(f) { + return Files.exists(Paths.get(f)) +} + +var javaLauncher = exists(jLauncher) ? jLauncher : altjLauncher + + +if (!exists(javaLauncher)) { + throw "no java launcher found; tried ${jLauncher} and ${altjLauncher}" +} + function tryExec() { try { - `java` + $EXEC("${javaLauncher}") } catch (e) { - print(e); + print(e) } // make sure we got non-zero ("failure") exit code! if ($EXIT == 0) { - print("Error: expected $EXIT code to be non-zero"); + print("Error: expected $EXIT code to be non-zero") } } +//convert windows paths to cygwin +if (windows) + javaLauncher = (winCyg) ? cygpath(javaLauncher,outPath.mixed).trim() : cygpath(javaLauncher,outPath.windows).trim() // no exception now! -tryExec(); +tryExec() // turn on error with non-zero exit code -$ENV.JJS_THROW_ON_EXIT = "1"; -tryExec(); +$ENV.JJS_THROW_ON_EXIT = "1" +tryExec() // no exception after this -$ENV.JJS_THROW_ON_EXIT = "0"; -tryExec(); +$ENV.JJS_THROW_ON_EXIT = "0" +tryExec() diff --git a/nashorn/test/script/trusted/JDK-util.js b/nashorn/test/script/trusted/JDK-util.js new file mode 100644 index 00000000000..f2a118315ce --- /dev/null +++ b/nashorn/test/script/trusted/JDK-util.js @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * This file contains utility functions used by other tests. + * @subtest + */ + +var Files = Java.type('java.nio.file.Files'), + Paths = Java.type('java.nio.file.Paths'), + System = Java.type('java.lang.System') + +var File = java.io.File +var windows = System.getProperty("os.name").startsWith("Windows") +var winCyg = false + +var outPath = { + windows:0, //C:\dir + mixed:1 //C:/dir +} + +if (windows) { + //Is there any better way to diffrentiate between cygwin/command prompt on windows + var term = System.getenv("TERM") + winCyg = term ? true:false +} + +/** + * Returns which command is selected from PATH + * @param cmd name of the command searched from PATH + */ +function which(cmd) { + var path = System.getenv("PATH") + var st = new java.util.StringTokenizer(path, File.pathSeparator) + while (st.hasMoreTokens()) { + var file = new File(st.nextToken(), cmd) + if (file.exists()) { + return (file.getAbsolutePath()) + } + } +} + +/** + * Unix cygpath implementation + * Supports only two outputs,windows(C:\dir\) and mixed(C:/dir/) + */ +function cygpath(path,mode) { + + var newpath = path + if(path.startsWith("/cygdrive/")){ + var str = path.substring(10) + var index = str.indexOf('/',0) + var drv = str.substring(0,index) + var rstr = drv.toUpperCase() + ":" + newpath = str.replaceFirst(drv,rstr) + } + if (mode == outPath.windows) + return Paths.get(newpath).toString() + else { + newpath = newpath.replaceAll('\\\\','/') + return newpath + } + +} + From eee69db96dd84eda04f703719f25db4ccf36aa25 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 11 Mar 2016 13:00:33 +0100 Subject: [PATCH 121/129] 8151570: jtreg tests leave tty in bad state Use unsupported terminal when running tests, to avoid setting tty to a raw mode. Reviewed-by: rfield --- .../classes/jdk/internal/jshell/tool/ConsoleIOContext.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java index 53df5fe0221..d86319f7254 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java @@ -48,6 +48,7 @@ import java.util.function.Supplier; import jdk.internal.jline.NoInterruptUnixTerminal; import jdk.internal.jline.Terminal; import jdk.internal.jline.TerminalFactory; +import jdk.internal.jline.UnsupportedTerminal; import jdk.internal.jline.WindowsTerminal; import jdk.internal.jline.console.ConsoleReader; import jdk.internal.jline.console.KeyMap; @@ -68,7 +69,9 @@ class ConsoleIOContext extends IOContext { this.repl = repl; this.input = new StopDetectingInputStream(() -> repl.state.stop(), ex -> repl.hard("Error on input: %s", ex)); Terminal term; - if (System.getProperty("os.name").toLowerCase(Locale.US).contains(TerminalFactory.WINDOWS)) { + if (System.getProperty("test.jdk") != null) { + term = new UnsupportedTerminal(); + } else if (System.getProperty("os.name").toLowerCase(Locale.US).contains(TerminalFactory.WINDOWS)) { term = new JShellWindowsTerminal(input); } else { term = new JShellUnixTerminal(input); From f876e4bbd253ebb5658d9c5985caf615d3147206 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 11 Mar 2016 14:07:03 -0800 Subject: [PATCH 122/129] 8151691: [Findbugs]jdk.internal.math.FormattedFloatingDecimal.getExponent() may expose internal rep The reference to the internal array is never leaked via the public API but some internal API clarification is added. Reviewed-by: rriggs --- .../math/FormattedFloatingDecimal.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/jdk/src/java.base/share/classes/jdk/internal/math/FormattedFloatingDecimal.java b/jdk/src/java.base/share/classes/jdk/internal/math/FormattedFloatingDecimal.java index 0a560dc11e5..88cd1feaf8f 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/math/FormattedFloatingDecimal.java +++ b/jdk/src/java.base/share/classes/jdk/internal/math/FormattedFloatingDecimal.java @@ -106,10 +106,28 @@ public class FormattedFloatingDecimal{ return decExponentRounded - 1; } + /** + * Returns the mantissa as a {@code char[]}. Note that the returned value + * is a reference to the internal {@code char[]} containing the mantissa, + * therefore code invoking this method should not pass the return value to + * external code but should in that case make a copy. + * + * @return a reference to the internal {@code char[]} representing the + * mantissa. + */ public char[] getMantissa(){ return mantissa; } + /** + * Returns the exponent as a {@code char[]}. Note that the returned value + * is a reference to the internal {@code char[]} containing the exponent, + * therefore code invoking this method should not pass the return value to + * external code but should in that case make a copy. + * + * @return a reference to the internal {@code char[]} representing the + * exponent. + */ public char[] getExponent(){ return exponent; } From 27c0bb6266f64edefecbe5bce0c3c681bfd9a613 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Tue, 15 Mar 2016 06:53:45 -0700 Subject: [PATCH 123/129] 8151858: update ASM 5.1 to accept V53.0 classfiles Reviewed-by: forax, sundar --- .../classes/jdk/internal/org/objectweb/asm/ClassReader.java | 2 +- .../share/classes/jdk/internal/org/objectweb/asm/Opcodes.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java index 523851fd70a..90593f58fc3 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java @@ -195,7 +195,7 @@ public class ClassReader { public ClassReader(final byte[] b, final int off, final int len) { this.b = b; // checks the class version - if (readShort(off + 6) > Opcodes.V1_8) { + if (readShort(off + 6) > Opcodes.V1_9) { throw new IllegalArgumentException(); } // parses the constant pool diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java index 286853352d2..d40facdafa4 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java @@ -87,6 +87,7 @@ public interface Opcodes { int V1_6 = 0 << 16 | 50; int V1_7 = 0 << 16 | 51; int V1_8 = 0 << 16 | 52; + int V1_9 = 0 << 16 | 53; // access flags From 96678b62c680977b1cbc6932a7702f6d1657b52b Mon Sep 17 00:00:00 2001 From: "J. Duke" Date: Wed, 5 Jul 2017 21:25:36 +0200 Subject: [PATCH 124/129] Added tag jdk-9+109 for changeset c870cb782aca --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 989f02b425a..96eac58d20e 100644 --- a/.hgtags +++ b/.hgtags @@ -351,3 +351,4 @@ db483b34fa7148d257a429acddbde9c13687dcae jdk-9+105 6c644cca3f3fc2763e2ff7d669849a75d34543ba jdk-9+106 1c076468bf7dad5b8f2ee5dcf66e2279caa3e208 jdk-9+107 257b579d813201682931d6b42f0445ffe5b4210d jdk-9+108 +c870cb782aca71093d2584376f27f0cfbfec0e3a jdk-9+109 From 64497fa471ab7c23ca28af652f61d7e982d8d972 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Tue, 15 Mar 2016 13:48:26 -0700 Subject: [PATCH 125/129] Added tag jdk-9+110 for changeset 91e6d9d79973 --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index 8d4f94f1f2c..49cf4dd5ea8 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -352,3 +352,4 @@ eee1ced1d8e78293f2a004af818ca474387dbebf jdk-9+103 8701b2bb1d2e1b9abc2a9be0933993c7150a9dbe jdk-9+107 42794e648cfe9fd67461dcbe8b7594241a84bcff jdk-9+108 1c7bad0798900fe58f4db01ae7ffdc84f5baee8c jdk-9+109 +9417e1bcded6af5532c3b26235437ab227758877 jdk-9+110 From 829d62738ceb569ab20d5bf66983efe39c09f773 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Wed, 16 Mar 2016 13:16:14 -0400 Subject: [PATCH 126/129] 8085887: java.time.format.FormatStyle.LONG or FULL causes unchecked exception 8076528: LocalTime.format() throws exception when FormatStyle is LONG or FULL Reviewed-by: sherman, scolebourne --- .../java/time/format/DateTimeFormatter.java | 9 ++ .../time/format/DateTimeFormatterBuilder.java | 3 + .../time/format/DateTimePrintContext.java | 10 +- .../java/time/temporal/TemporalQueries.java | 102 ++++++++++++++---- .../time/format/TestDateTimeFormatter.java | 76 +++++++++++++ 5 files changed, 178 insertions(+), 22 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java index 01498d340a5..80895c8a8a2 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java @@ -619,6 +619,9 @@ public final class DateTimeFormatter { * The returned formatter has a chronology of ISO set to ensure dates in * other calendar systems are correctly converted. * It has no override zone and uses the {@link ResolverStyle#SMART SMART} resolver style. + * The {@code FULL} and {@code LONG} styles typically require a time-zone. + * When formatting using these styles, a {@code ZoneId} must be available, + * either by using {@code ZonedDateTime} or {@link DateTimeFormatter#withZone}. * * @param timeStyle the formatter style to obtain, not null * @return the time formatter, not null @@ -647,6 +650,9 @@ public final class DateTimeFormatter { * The returned formatter has a chronology of ISO set to ensure dates in * other calendar systems are correctly converted. * It has no override zone and uses the {@link ResolverStyle#SMART SMART} resolver style. + * The {@code FULL} and {@code LONG} styles typically require a time-zone. + * When formatting using these styles, a {@code ZoneId} must be available, + * either by using {@code ZonedDateTime} or {@link DateTimeFormatter#withZone}. * * @param dateTimeStyle the formatter style to obtain, not null * @return the date-time formatter, not null @@ -675,6 +681,9 @@ public final class DateTimeFormatter { * The returned formatter has a chronology of ISO set to ensure dates in * other calendar systems are correctly converted. * It has no override zone and uses the {@link ResolverStyle#SMART SMART} resolver style. + * The {@code FULL} and {@code LONG} styles typically require a time-zone. + * When formatting using these styles, a {@code ZoneId} must be available, + * either by using {@code ZonedDateTime} or {@link DateTimeFormatter#withZone}. * * @param dateStyle the date formatter style to obtain, not null * @param timeStyle the time formatter style to obtain, not null diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index 441ac711110..17d9759f51f 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -1256,6 +1256,9 @@ public final class DateTimeFormatterBuilder { * During formatting, the chronology is obtained from the temporal object * being formatted, which may have been overridden by * {@link DateTimeFormatter#withChronology(Chronology)}. + * The {@code FULL} and {@code LONG} styles typically require a time-zone. + * When formatting using these styles, a {@code ZoneId} must be available, + * either by using {@code ZonedDateTime} or {@link DateTimeFormatter#withZone}. *

    * During parsing, if a chronology has already been parsed, then it is used. * Otherwise the default from {@code DateTimeFormatter.withChronology(Chronology)} diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimePrintContext.java b/jdk/src/java.base/share/classes/java/time/format/DateTimePrintContext.java index 310f6598fc9..811bd5b2ee1 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimePrintContext.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimePrintContext.java @@ -218,6 +218,13 @@ final class DateTimePrintContext { } return query.queryFrom(this); } + + @Override + public String toString() { + return temporal + + (effectiveChrono != null ? " with chronology " + effectiveChrono : "") + + (effectiveZone != null ? " with zone " + effectiveZone : ""); + } }; } @@ -279,7 +286,8 @@ final class DateTimePrintContext { R getValue(TemporalQuery query) { R result = temporal.query(query); if (result == null && optional == 0) { - throw new DateTimeException("Unable to extract value: " + temporal.getClass()); + throw new DateTimeException("Unable to extract " + + query + " from temporal " + temporal); } return result; } diff --git a/jdk/src/java.base/share/classes/java/time/temporal/TemporalQueries.java b/jdk/src/java.base/share/classes/java/time/temporal/TemporalQueries.java index 6b1777a9471..9df66bb7cd2 100644 --- a/jdk/src/java.base/share/classes/java/time/temporal/TemporalQueries.java +++ b/jdk/src/java.base/share/classes/java/time/temporal/TemporalQueries.java @@ -341,58 +341,118 @@ public final class TemporalQueries { /** * A strict query for the {@code ZoneId}. */ - static final TemporalQuery ZONE_ID = (temporal) -> - temporal.query(TemporalQueries.ZONE_ID); + static final TemporalQuery ZONE_ID = new TemporalQuery<>() { + @Override + public ZoneId queryFrom(TemporalAccessor temporal) { + return temporal.query(TemporalQueries.ZONE_ID); + } + + @Override + public String toString() { + return "ZoneId"; + } + }; /** * A query for the {@code Chronology}. */ - static final TemporalQuery CHRONO = (temporal) -> - temporal.query(TemporalQueries.CHRONO); + static final TemporalQuery CHRONO = new TemporalQuery<>() { + @Override + public Chronology queryFrom(TemporalAccessor temporal) { + return temporal.query(TemporalQueries.CHRONO); + } + + @Override + public String toString() { + return "Chronology"; + } + }; + /** * A query for the smallest supported unit. */ - static final TemporalQuery PRECISION = (temporal) -> - temporal.query(TemporalQueries.PRECISION); + static final TemporalQuery PRECISION = new TemporalQuery<>() { + @Override + public TemporalUnit queryFrom(TemporalAccessor temporal) { + return temporal.query(TemporalQueries.PRECISION); + } + + @Override + public String toString() { + return "Precision"; + } + }; //----------------------------------------------------------------------- /** * A query for {@code ZoneOffset} returning null if not found. */ - static final TemporalQuery OFFSET = (temporal) -> { - if (temporal.isSupported(OFFSET_SECONDS)) { - return ZoneOffset.ofTotalSeconds(temporal.get(OFFSET_SECONDS)); + static final TemporalQuery OFFSET = new TemporalQuery<>() { + @Override + public ZoneOffset queryFrom(TemporalAccessor temporal) { + if (temporal.isSupported(OFFSET_SECONDS)) { + return ZoneOffset.ofTotalSeconds(temporal.get(OFFSET_SECONDS)); + } + return null; + } + + @Override + public String toString() { + return "ZoneOffset"; } - return null; }; /** * A lenient query for the {@code ZoneId}, falling back to the {@code ZoneOffset}. */ - static final TemporalQuery ZONE = (temporal) -> { - ZoneId zone = temporal.query(ZONE_ID); - return (zone != null ? zone : temporal.query(OFFSET)); + static final TemporalQuery ZONE = new TemporalQuery<>() { + @Override + public ZoneId queryFrom(TemporalAccessor temporal) { + ZoneId zone = temporal.query(ZONE_ID); + return (zone != null ? zone : temporal.query(OFFSET)); + } + + @Override + public String toString() { + return "Zone"; + } }; /** * A query for {@code LocalDate} returning null if not found. */ - static final TemporalQuery LOCAL_DATE = (temporal) -> { - if (temporal.isSupported(EPOCH_DAY)) { - return LocalDate.ofEpochDay(temporal.getLong(EPOCH_DAY)); + static final TemporalQuery LOCAL_DATE = new TemporalQuery<>() { + @Override + public LocalDate queryFrom(TemporalAccessor temporal) { + if (temporal.isSupported(EPOCH_DAY)) { + return LocalDate.ofEpochDay(temporal.getLong(EPOCH_DAY)); + } + return null; + } + + @Override + public String toString() { + return "LocalDate"; } - return null; }; /** * A query for {@code LocalTime} returning null if not found. */ - static final TemporalQuery LOCAL_TIME = (temporal) -> { - if (temporal.isSupported(NANO_OF_DAY)) { - return LocalTime.ofNanoOfDay(temporal.getLong(NANO_OF_DAY)); + static final TemporalQuery LOCAL_TIME = new TemporalQuery<>() { + @Override + public LocalTime queryFrom(TemporalAccessor temporal) { + if (temporal.isSupported(NANO_OF_DAY)) { + return LocalTime.ofNanoOfDay(temporal.getLong(NANO_OF_DAY)); + } + return null; + } + + @Override + public String toString() { + return "LocalTime"; } - return null; }; } diff --git a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java index 1bfa4799320..c9c513fa542 100644 --- a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java @@ -79,19 +79,24 @@ import java.time.YearMonth; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.chrono.Chronology; import java.time.chrono.ThaiBuddhistChronology; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DecimalStyle; import java.time.format.SignStyle; +import java.time.format.TextStyle; +import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.util.Locale; import java.util.function.Function; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * Test DateTimeFormatter. + * @bug 8085887 */ @Test public class TestDateTimeFormatter { @@ -196,4 +201,75 @@ public class TestDateTimeFormatter { assertTrue(msg.contains("11:30:56"), msg); } + @DataProvider(name="nozone_exception_cases") + Object[][] exceptionCases() { + return new Object[][] { + {LocalDateTime.of(2000, 1, 1, 1, 1), "z", "ZoneId"}, + {OffsetDateTime.of(2000, 1, 1, 3, 3, 3, 0, ZoneOffset.ofTotalSeconds(60)), "z", "ZoneId"}, + }; + } + + // Test cases that should throw an exception with a cogent message + // containing the Type being queried and the Temporal being queried. + @Test(dataProvider="nozone_exception_cases") + public void test_throws_message(Temporal temporal, String pattern, String queryName) { + DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern); + try { + fmt.format(temporal); + fail("Format using \"" + pattern + "\" with " + + temporal + " should have failed"); + } catch (DateTimeException dte) { + String msg = dte.getMessage(); + // Verify message contains the type that is missing and the temporal value + assertTrue(msg.contains(queryName), + String.format("\"%s\" missing from %s", queryName, msg)); + String s = temporal.toString(); + assertTrue(msg.contains(s), + String.format("\"%s\" missing from %s", s, msg)); + } + + } + + // Test cases that should throw an exception with a cogent message when missing the Chronology + @Test + public void test_throws_message_chrono() { + Chronology chrono = ThaiBuddhistChronology.INSTANCE; + DateTimeFormatter fmt = new DateTimeFormatterBuilder().appendZoneId().toFormatter() + .withChronology(chrono); + LocalTime now = LocalTime.now(); + try { + fmt.format(now); + fail("Format using appendZoneId() should have failed"); + } catch (DateTimeException dte) { + String msg = dte.getMessage(); + // Verify message contains the type that is missing and the temporal value + assertTrue(msg.contains("ZoneId"), + String.format("\"%s\" missing from %s", "ZoneId", msg)); + assertTrue(msg.contains(chrono.toString()), + String.format("\"%s\" missing from %s", chrono.toString(), msg)); + } + + } + + // Test cases that should throw an exception with a cogent message when missing the ZoneId + @Test + public void test_throws_message_zone() { + ZoneId zone = ZoneId.of("Pacific/Honolulu"); + DateTimeFormatter fmt = new DateTimeFormatterBuilder().appendChronologyId().toFormatter() + .withZone(zone); + LocalTime now = LocalTime.now(); + try { + fmt.format(now); + fail("Format using appendChronologyId() should have failed"); + } catch (DateTimeException dte) { + String msg = dte.getMessage(); + // Verify message contains the type that is missing and the temporal value + assertTrue(msg.contains("Chronology"), + String.format("\"%s\" missing from %s", "Chronology", msg)); + assertTrue(msg.contains(zone.toString()), + String.format("\"%s\" missing from %s", zone.toString(), msg)); + } + + } + } From bda07f129a3aaa99e5ed6d4e590ac45e897a45bf Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Wed, 16 Mar 2016 14:04:12 -0700 Subject: [PATCH 127/129] 8151233: Unify CopySwap and CopyMemory tests Reviewed-by: dholmes --- .../jdk/internal/misc/Unsafe/CopyCommon.java | 607 ++++++++++++++++++ .../jdk/internal/misc/Unsafe/CopyMemory.java | 537 +--------------- .../jdk/internal/misc/Unsafe/CopySwap.java | 552 +--------------- 3 files changed, 615 insertions(+), 1081 deletions(-) create mode 100644 jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java b/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java new file mode 100644 index 00000000000..65e2b587388 --- /dev/null +++ b/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java @@ -0,0 +1,607 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.internal.misc.Unsafe; +import java.lang.reflect.Field; + +/** + * Helper class to support testing of Unsafe.copyMemory and Unsafe.copySwapMemory + */ +public class CopyCommon { + private static final boolean DEBUG = Boolean.getBoolean("CopyCommon.DEBUG"); + + public static final long KB = 1024; + public static final long MB = KB * 1024; + public static final long GB = MB * 1024; + + static final int SMALL_COPY_SIZE = 32; + static final int BASE_ALIGNMENT = 16; + + protected static final Unsafe UNSAFE; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + } + + static long alignDown(long value, long alignment) { + return value & ~(alignment - 1); + } + + static long alignUp(long value, long alignment) { + return (value + alignment - 1) & ~(alignment - 1); + } + + static boolean isAligned(long value, long alignment) { + return value == alignDown(value, alignment); + } + + CopyCommon() { + } + + /** + * Generate verification data for a given offset + * + * The verification data is used to verify that the correct bytes + * have indeed been copied and byte swapped. + * + * The data is generated based on the offset (in bytes) into the + * source buffer. For a native buffer the offset is relative to + * the base pointer. For a heap array it is relative to the + * address of the first array element. + * + * This method will return the result of doing an elementSize byte + * read starting at offset (in bytes). + * + * @param offset offset into buffer + * @param elemSize size (in bytes) of the element + * + * @return the verification data, only the least significant + * elemSize*8 bits are set, zero extended + */ + private long getVerificationDataForOffset(long offset, long elemSize) { + byte[] bytes = new byte[(int)elemSize]; + + for (long i = 0; i < elemSize; i++) { + bytes[(int)i] = (byte)(offset + i); + } + + long o = UNSAFE.arrayBaseOffset(byte[].class); + + switch ((int)elemSize) { + case 1: return Byte.toUnsignedLong(UNSAFE.getByte(bytes, o)); + case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(bytes, o)); + case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(bytes, o)); + case 8: return UNSAFE.getLongUnaligned(bytes, o); + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Verify byte swapped data + * + * @param ptr the data to verify + * @param srcOffset the srcOffset (in bytes) from which the copy started, + * used as key to regenerate the verification data + * @param dstOffset the offset (in bytes) in the array at which to start + * the verification, relative to the first element in the array + * @param size size (in bytes) of data to to verify + * @param elemSize size (in bytes) of the individual array elements + * + * @throws RuntimeException if an error is found + */ + private void verifySwappedData(GenericPointer ptr, long srcOffset, long dstOffset, long size, long elemSize) { + for (long offset = 0; offset < size; offset += elemSize) { + long expectedUnswapped = getVerificationDataForOffset(srcOffset + offset, elemSize); + long expected = byteSwap(expectedUnswapped, elemSize); + + long actual = getArrayElem(ptr, dstOffset + offset, elemSize); + + if (expected != actual) { + throw new RuntimeException("srcOffset: 0x" + Long.toHexString(srcOffset) + + " dstOffset: 0x" + Long.toHexString(dstOffset) + + " size: 0x" + Long.toHexString(size) + + " offset: 0x" + Long.toHexString(offset) + + " expectedUnswapped: 0x" + Long.toHexString(expectedUnswapped) + + " expected: 0x" + Long.toHexString(expected) + + " != actual: 0x" + Long.toHexString(actual)); + } + } + } + + /** + * Initialize an array with verification friendly data + * + * @param ptr pointer to the data to initialize + * @param size size (in bytes) of the data + * @param elemSize size (in bytes) of the individual elements + */ + private void initVerificationData(GenericPointer ptr, long size, long elemSize) { + for (long offset = 0; offset < size; offset++) { + byte data = (byte)getVerificationDataForOffset(offset, 1); + + if (ptr.isOnHeap()) { + UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data); + } else { + UNSAFE.putByte(ptr.getOffset() + offset, data); + } + } + } + + /** + * Allocate a primitive array + * + * @param size size (in bytes) of all the array elements (elemSize * length) + * @param elemSize the size of the array elements + * + * @return a newly allocated primitive array + */ + Object allocArray(long size, long elemSize) { + int length = (int)(size / elemSize); + + switch ((int)elemSize) { + case 1: return new byte[length]; + case 2: return new short[length]; + case 4: return new int[length]; + case 8: return new long[length]; + default: + throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Get the value of a primitive array entry + * + * @param ptr pointer to the data + * @param offset offset (in bytes) of the array element, relative to the first element in the array + * + * @return the array element, as an unsigned long + */ + private long getArrayElem(GenericPointer ptr, long offset, long elemSize) { + if (ptr.isOnHeap()) { + Object o = ptr.getObject(); + int index = (int)(offset / elemSize); + + if (o instanceof short[]) { + short[] arr = (short[])o; + return Short.toUnsignedLong(arr[index]); + } else if (o instanceof int[]) { + int[] arr = (int[])o; + return Integer.toUnsignedLong(arr[index]); + } else if (o instanceof long[]) { + long[] arr = (long[])o; + return arr[index]; + } else { + throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); + } + } else { + long addr = ptr.getOffset() + offset; + + switch ((int)elemSize) { + case 1: return Byte.toUnsignedLong(UNSAFE.getByte(addr)); + case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(null, addr)); + case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(null, addr)); + case 8: return UNSAFE.getLongUnaligned(null, addr); + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + } + + private void putValue(long addr, long elemSize, long value) { + switch ((int)elemSize) { + case 1: UNSAFE.putByte(addr, (byte)value); break; + case 2: UNSAFE.putShortUnaligned(null, addr, (short)value); break; + case 4: UNSAFE.putIntUnaligned(null, addr, (int)value); break; + case 8: UNSAFE.putLongUnaligned(null, addr, value); break; + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Get the size of the elements for an array + * + * @param o a primitive heap array + * + * @return the size (in bytes) of the individual array elements + */ + private long getArrayElemSize(Object o) { + if (o instanceof short[]) { + return 2; + } else if (o instanceof int[]) { + return 4; + } else if (o instanceof long[]) { + return 8; + } else { + throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); + } + } + + /** + * Byte swap a value + * + * @param value the value to swap, only the bytes*8 least significant bits are used + * @param size size (in bytes) of the value + * + * @return the byte swapped value in the bytes*8 least significant bits + */ + private long byteSwap(long value, long size) { + switch ((int)size) { + case 2: return Short.toUnsignedLong(Short.reverseBytes((short)value)); + case 4: return Integer.toUnsignedLong(Integer.reverseBytes((int)value)); + case 8: return Long.reverseBytes(value); + default: throw new IllegalArgumentException("Invalid element size: " + size); + } + } + + /** + * Verify data which has *not* been byte swapped + * + * @param ptr the data to verify + * @param startOffset the offset (in bytes) at which to start the verification + * @param size size (in bytes) of the data to verify + * + * @throws RuntimeException if an error is found + */ + private void verifyUnswappedData(GenericPointer ptr, long startOffset, long srcOffset, long size) { + for (long i = 0; i < size; i++) { + byte expected = (byte)getVerificationDataForOffset(srcOffset + i, 1); + + byte actual; + if (ptr.isOnHeap()) { + actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + startOffset + i); + } else { + actual = UNSAFE.getByte(ptr.getOffset() + startOffset + i); + } + + if (expected != actual) { + throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) + + " srcOffset: 0x" + Long.toHexString(srcOffset) + + " size: 0x" + Long.toHexString(size) + + " i: 0x" + Long.toHexString(i) + + " expected: 0x" + Long.toHexString(expected) + + " != actual: 0x" + Long.toHexString(actual)); + } + } + } + + + /** + * Copy and byte swap data from the source to the destination + * + * This method will pre-populate the whole source and destination + * buffers with verification friendly data. It will then copy data + * to fill part of the destination buffer with data from the + * source, optionally byte swapping the copied elements on the + * fly. Some space (padding) will be left before and after the + * data in the destination buffer, which should not be + * touched/overwritten by the copy call. + * + * Note: Both source and destination buffers will be overwritten! + * + * @param src source buffer to copy from + * @param srcOffset the offset (in bytes) in the source buffer, relative to + * the first array element, at which to start reading data + * @param dst destination buffer to copy to + * @param dstOffset the offset (in bytes) in the destination + * buffer, relative to the first array element, at which to + * start writing data + * @param bufSize the size (in bytes) of the src and dst arrays + * @param copyBytes the size (in bytes) of the copy to perform, + * must be a multiple of elemSize + * @param elemSize the size (in bytes) of the elements + * @param swap true if elements should be byte swapped + * + * @throws RuntimeException if an error is found + */ + void testCopyGeneric(GenericPointer src, long srcOffset, + GenericPointer dst, long dstOffset, + long bufSize, long copyBytes, long elemSize, boolean swap) { + if (swap) { + if (!isAligned(copyBytes, elemSize)) { + throw new IllegalArgumentException( + "copyBytes (" + copyBytes + ") must be a multiple of elemSize (" + elemSize + ")"); + } + if (src.isOnHeap() && !isAligned(srcOffset, elemSize)) { + throw new IllegalArgumentException( + "srcOffset (" + srcOffset + ") must be a multiple of elemSize (" + elemSize + ")"); + } + if (dst.isOnHeap() && !isAligned(dstOffset, elemSize)) { + throw new IllegalArgumentException( + "dstOffset (" + dstOffset + ") must be a multiple of elemSize (" + elemSize + ")"); + } + } + + if (srcOffset + copyBytes > bufSize) { + throw new IllegalArgumentException( + "srcOffset (" + srcOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); + } + if (dstOffset + copyBytes > bufSize) { + throw new IllegalArgumentException( + "dstOffset (" + dstOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); + } + + // Initialize the whole source buffer with a verification friendly pattern (no 0x00 bytes) + initVerificationData(src, bufSize, elemSize); + if (!src.equals(dst)) { + initVerificationData(dst, bufSize, elemSize); + } + + if (DEBUG) { + System.out.println("===before==="); + for (int offset = 0; offset < bufSize; offset += elemSize) { + long srcValue = getArrayElem(src, offset, elemSize); + long dstValue = getArrayElem(dst, offset, elemSize); + + System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + + " src=0x" + Long.toHexString(srcValue) + + " dst=0x" + Long.toHexString(dstValue)); + } + } + + if (swap) { + // Copy & swap data into the middle of the destination buffer + UNSAFE.copySwapMemory(src.getObject(), + src.getOffset() + srcOffset, + dst.getObject(), + dst.getOffset() + dstOffset, + copyBytes, + elemSize); + } else { + // Copy & swap data into the middle of the destination buffer + UNSAFE.copyMemory(src.getObject(), + src.getOffset() + srcOffset, + dst.getObject(), + dst.getOffset() + dstOffset, + copyBytes); + } + + if (DEBUG) { + System.out.println("===after==="); + for (int offset = 0; offset < bufSize; offset += elemSize) { + long srcValue = getArrayElem(src, offset, elemSize); + long dstValue = getArrayElem(dst, offset, elemSize); + + System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + + " src=0x" + Long.toHexString(srcValue) + + " dst=0x" + Long.toHexString(dstValue)); + } + } + + // Verify the the front padding is unchanged + verifyUnswappedData(dst, 0, 0, dstOffset); + + if (swap) { + // Verify swapped data + verifySwappedData(dst, srcOffset, dstOffset, copyBytes, elemSize); + } else { + // Verify copied/unswapped data + verifyUnswappedData(dst, dstOffset, srcOffset, copyBytes); + } + + // Verify that the back padding is unchanged + long frontAndCopyBytes = dstOffset + copyBytes; + long trailingBytes = bufSize - frontAndCopyBytes; + verifyUnswappedData(dst, frontAndCopyBytes, frontAndCopyBytes, trailingBytes); + } + + /** + * Test various configurations of copying and optionally swapping data + * + * @param src the source buffer to copy from + * @param dst the destination buffer to copy to + * @param size size (in bytes) of the buffers + * @param elemSize size (in bytes) of the individual elements + * + * @throws RuntimeException if an error is found + */ + public void testBufferPair(GenericPointer src, GenericPointer dst, long size, long elemSize, boolean swap) { + // offset in source from which to start reading data + for (long srcOffset = 0; srcOffset < size; srcOffset += (src.isOnHeap() ? elemSize : 1)) { + + // offset in destination at which to start writing data + for (int dstOffset = 0; dstOffset < size; dstOffset += (dst.isOnHeap() ? elemSize : 1)) { + + // number of bytes to copy + long maxCopyBytes = Math.min(size - srcOffset, size - dstOffset); + for (long copyBytes = 0; copyBytes < maxCopyBytes; copyBytes += elemSize) { + try { + testCopyGeneric(src, srcOffset, dst, dstOffset, size, copyBytes, elemSize, swap); + } catch (RuntimeException e) { + // Wrap the exception in another exception to catch the relevant configuration data + throw new RuntimeException("testBufferPair: " + + "src=" + src + + " dst=" + dst + + " elemSize=0x" + Long.toHexString(elemSize) + + " copyBytes=0x" + Long.toHexString(copyBytes) + + " srcOffset=0x" + Long.toHexString(srcOffset) + + " dstOffset=0x" + Long.toHexString(dstOffset) + + " swap=" + swap, + e); + } + } + } + } + } + + /** + * Test copying between various permutations of buffers + * + * @param buffers buffers to permute (src x dst) + * @param size size (in bytes) of buffers + * @param elemSize size (in bytes) of individual elements + * + * @throws RuntimeException if an error is found + */ + public void testPermuteBuffers(GenericPointer[] buffers, long size, long elemSize, boolean swap) { + System.out.println("testPermuteBuffers(buffers, " + size + ", " + elemSize + ", " + swap + ")"); + for (int srcIndex = 0; srcIndex < buffers.length; srcIndex++) { + for (int dstIndex = 0; dstIndex < buffers.length; dstIndex++) { + testBufferPair(buffers[srcIndex], buffers[dstIndex], size, elemSize, swap); + } + } + } + + /** + * Test copying of a specific element size + * + * @param size size (in bytes) of buffers to allocate + * @param elemSize size (in bytes) of individual elements + * + * @throws RuntimeException if an error is found + */ + private void testElemSize(long size, long elemSize, boolean swap) { + long buf1Raw = 0; + long buf2Raw = 0; + + try { + buf1Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + long buf1 = alignUp(buf1Raw, BASE_ALIGNMENT); + + buf2Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + long buf2 = alignUp(buf2Raw, BASE_ALIGNMENT); + + GenericPointer[] buffers = { + new GenericPointer(buf1), + new GenericPointer(buf2), + new GenericPointer(allocArray(size, elemSize)), + new GenericPointer(allocArray(size, elemSize)) + }; + + testPermuteBuffers(buffers, size, elemSize, swap); + } finally { + if (buf1Raw != 0) { + UNSAFE.freeMemory(buf1Raw); + } + if (buf2Raw != 0) { + UNSAFE.freeMemory(buf2Raw); + } + } + } + + /** + * Verify that small copies work + */ + void testSmallCopy(boolean swap) { + int smallBufSize = SMALL_COPY_SIZE; + int minElemSize = swap ? 2 : 1; + int maxElemSize = swap ? 8 : 1; + + // Test various element types and heap/native combinations + for (long elemSize = minElemSize; elemSize <= maxElemSize; elemSize <<= 1) { + testElemSize(smallBufSize, elemSize, swap); + } + } + + + /** + * Verify that large copies work + */ + void testLargeCopy(boolean swap) { + long size = 2 * GB + 8; + long bufRaw = 0; + + // Check that a large native copy succeeds + try { + try { + bufRaw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + } catch (OutOfMemoryError e) { + // Accept failure, skip test + return; + } + + long buf = alignUp(bufRaw, BASE_ALIGNMENT); + + if (swap) { + UNSAFE.copySwapMemory(null, buf, null, buf, size, 8); + } else { + UNSAFE.copyMemory(null, buf, null, buf, size); + } + } catch (Exception e) { + throw new RuntimeException("copy of large buffer failed (swap=" + swap + ")"); + } finally { + if (bufRaw != 0) { + UNSAFE.freeMemory(bufRaw); + } + } + } + + /** + * Helper class to represent a "pointer" - either a heap array or + * a pointer to a native buffer. + * + * In the case of a native pointer, the Object is null and the offset is + * the absolute address of the native buffer. + * + * In the case of a heap object, the Object is a primitive array, and + * the offset will be set to the base offset to the first element, meaning + * the object and the offset together form a double-register pointer. + */ + static class GenericPointer { + private final Object o; + private final long offset; + + private GenericPointer(Object o, long offset) { + this.o = o; + this.offset = offset; + } + + public String toString() { + return "GenericPointer(o={" + o + "}, offset=0x" + Long.toHexString(offset) + ")"; + } + + public boolean equals(Object other) { + if (!(other instanceof GenericPointer)) { + return false; + } + + GenericPointer otherp = (GenericPointer)other; + + return o == otherp.o && offset == otherp.offset; + } + + GenericPointer(Object o) { + this(o, UNSAFE.arrayBaseOffset(o.getClass())); + } + + GenericPointer(long offset) { + this(null, offset); + } + + public boolean isOnHeap() { + return o != null; + } + + public Object getObject() { + return o; + } + + public long getOffset() { + return offset; + } + } +} diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java b/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java index c87bb1b6895..d4879e603f1 100644 --- a/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java +++ b/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java @@ -29,492 +29,18 @@ import java.lang.reflect.Field; * @summary Test Unsafe.copyMemory * @modules java.base/jdk.internal.misc */ -public class CopyMemory { - private static final boolean DEBUG = Boolean.getBoolean("CopyMemory.DEBUG"); - - public static final long KB = 1024; - public static final long MB = KB * 1024; - public static final long GB = MB * 1024; - - private static final Unsafe UNSAFE; - private static final int SMALL_COPY_SIZE = 32; - private static final int BASE_ALIGNMENT = 16; - - static { - try { - Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); - } catch (Exception e) { - throw new RuntimeException("Unable to get Unsafe instance.", e); - } - } - - private static long alignDown(long value, long alignment) { - return value & ~(alignment - 1); - } - - private static long alignUp(long value, long alignment) { - return (value + alignment - 1) & ~(alignment - 1); - } - - private static boolean isAligned(long value, long alignment) { - return value == alignDown(value, alignment); - } - +public class CopyMemory extends CopyCommon { private CopyMemory() { } - /** - * Generate verification data for a given offset - * - * The verification data is used to verify that the correct bytes - * have indeed been copied and byte swapped. - * - * The data is generated based on the offset (in bytes) into the - * source buffer. For a native buffer the offset is relative to - * the base pointer. For a heap array it is relative to the - * address of the first array element. - * - * This method will return the result of doing an elementSize byte - * read starting at offset (in bytes). - * - * @param offset offset into buffer - * @param elemSize size (in bytes) of the element - * - * @return the verification data, only the least significant - * elemSize*8 bits are set, zero extended - */ - private long getVerificationDataForOffset(long offset, long elemSize) { - byte[] bytes = new byte[(int)elemSize]; - - for (long i = 0; i < elemSize; i++) { - bytes[(int)i] = (byte)(offset + i); - } - - long o = UNSAFE.arrayBaseOffset(byte[].class); - - switch ((int)elemSize) { - case 1: return Byte.toUnsignedLong(UNSAFE.getByte(bytes, o)); - case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(bytes, o)); - case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(bytes, o)); - case 8: return UNSAFE.getLongUnaligned(bytes, o); - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Verify byte swapped data - * - * @param ptr the data to verify - * @param srcOffset the srcOffset (in bytes) from which the copy started, - * used as key to regenerate the verification data - * @param dstOffset the offset (in bytes) in the array at which to start - * the verification, relative to the first element in the array - * @param size size (in bytes) of data to to verify - * @param elemSize size (in bytes) of the individual array elements - * - * @throws RuntimeException if an error is found - */ - private void verifySwappedData(GenericPointer ptr, long srcOffset, long dstOffset, long size, long elemSize) { - for (long offset = 0; offset < size; offset += elemSize) { - long expectedUnswapped = getVerificationDataForOffset(srcOffset + offset, elemSize); - long expected = byteSwap(expectedUnswapped, elemSize); - - long actual = getArrayElem(ptr, dstOffset + offset, elemSize); - - if (expected != actual) { - throw new RuntimeException("srcOffset: 0x" + Long.toHexString(srcOffset) + - " dstOffset: 0x" + Long.toHexString(dstOffset) + - " size: 0x" + Long.toHexString(size) + - " offset: 0x" + Long.toHexString(offset) + - " expectedUnswapped: 0x" + Long.toHexString(expectedUnswapped) + - " expected: 0x" + Long.toHexString(expected) + - " != actual: 0x" + Long.toHexString(actual)); - } - } - } - - /** - * Initialize an array with verification friendly data - * - * @param ptr pointer to the data to initialize - * @param size size (in bytes) of the data - * @param elemSize size (in bytes) of the individual elements - */ - private void initVerificationData(GenericPointer ptr, long size, long elemSize) { - for (long offset = 0; offset < size; offset++) { - byte data = (byte)getVerificationDataForOffset(offset, 1); - - if (ptr.isOnHeap()) { - UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data); - } else { - UNSAFE.putByte(ptr.getOffset() + offset, data); - } - } - } - - /** - * Allocate a primitive array - * - * @param size size (in bytes) of all the array elements (elemSize * length) - * @param elemSize the size of the array elements - * - * @return a newly allocated primitive array - */ - Object allocArray(long size, long elemSize) { - int length = (int)(size / elemSize); - - switch ((int)elemSize) { - case 1: return new byte[length]; - case 2: return new short[length]; - case 4: return new int[length]; - case 8: return new long[length]; - default: - throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Get the value of a primitive array entry - * - * @param ptr pointer to the data - * @param offset offset (in bytes) of the array element, relative to the first element in the array - * - * @return the array element, as an unsigned long - */ - private long getArrayElem(GenericPointer ptr, long offset, long elemSize) { - if (ptr.isOnHeap()) { - Object o = ptr.getObject(); - int index = (int)(offset / elemSize); - - if (o instanceof short[]) { - short[] arr = (short[])o; - return Short.toUnsignedLong(arr[index]); - } else if (o instanceof int[]) { - int[] arr = (int[])o; - return Integer.toUnsignedLong(arr[index]); - } else if (o instanceof long[]) { - long[] arr = (long[])o; - return arr[index]; - } else { - throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); - } - } else { - long addr = ptr.getOffset() + offset; - - switch ((int)elemSize) { - case 1: return Byte.toUnsignedLong(UNSAFE.getByte(addr)); - case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(null, addr)); - case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(null, addr)); - case 8: return UNSAFE.getLongUnaligned(null, addr); - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - } - - private void putValue(long addr, long elemSize, long value) { - switch ((int)elemSize) { - case 1: UNSAFE.putByte(addr, (byte)value); break; - case 2: UNSAFE.putShortUnaligned(null, addr, (short)value); break; - case 4: UNSAFE.putIntUnaligned(null, addr, (int)value); break; - case 8: UNSAFE.putLongUnaligned(null, addr, value); break; - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Get the size of the elements for an array - * - * @param o a primitive heap array - * - * @return the size (in bytes) of the individual array elements - */ - private long getArrayElemSize(Object o) { - if (o instanceof short[]) { - return 2; - } else if (o instanceof int[]) { - return 4; - } else if (o instanceof long[]) { - return 8; - } else { - throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); - } - } - - /** - * Byte swap a value - * - * @param value the value to swap, only the bytes*8 least significant bits are used - * @param size size (in bytes) of the value - * - * @return the byte swapped value in the bytes*8 least significant bits - */ - private long byteSwap(long value, long size) { - switch ((int)size) { - case 2: return Short.toUnsignedLong(Short.reverseBytes((short)value)); - case 4: return Integer.toUnsignedLong(Integer.reverseBytes((int)value)); - case 8: return Long.reverseBytes(value); - default: throw new IllegalArgumentException("Invalid element size: " + size); - } - } - - /** - * Verify data which has *not* been byte swapped - * - * @param ptr the data to verify - * @param startOffset the offset (in bytes) at which to start the verification - * @param size size (in bytes) of the data to verify - * - * @throws RuntimeException if an error is found - */ - private void verifyUnswappedData(GenericPointer ptr, long startOffset, long srcOffset, long size) { - for (long i = 0; i < size; i++) { - byte expected = (byte)getVerificationDataForOffset(srcOffset + i, 1); - - byte actual; - if (ptr.isOnHeap()) { - actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + startOffset + i); - } else { - actual = UNSAFE.getByte(ptr.getOffset() + startOffset + i); - } - - if (expected != actual) { - throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) + - " srcOffset: 0x" + Long.toHexString(srcOffset) + - " size: 0x" + Long.toHexString(size) + - " i: 0x" + Long.toHexString(i) + - " expected: 0x" + Long.toHexString(expected) + - " != actual: 0x" + Long.toHexString(actual)); - } - } - } - - - /** - * Copy and byte swap data from the source to the destination - * - * This method will pre-populate the whole source and destination - * buffers with verification friendly data. It will then use - * copypMemory to fill part of the destination buffer with - * data from the source. Some space (padding) will be - * left before and after the data in the destination buffer, which - * should not be touched/overwritten by the copy call. - * - * Note: Both source and destination buffers will be overwritten! - * - * @param src source buffer to copy from - * @param srcOffset the offset (in bytes) in the source buffer, relative to - * the first array element, at which to start reading data - * @param dst destination buffer to copy to - * @param dstOffset the offset (in bytes) in the destination - * buffer, relative to the first array element, at which to - * start writing data - * @param bufSize the size (in bytes) of the src and dst arrays - * @param copyBytes the size (in bytes) of the copy to perform, - * must be a multiple of elemSize - * - * @throws RuntimeException if an error is found - */ - private void testCopy(GenericPointer src, long srcOffset, - GenericPointer dst, long dstOffset, - long bufSize, long copyBytes) { - if (srcOffset + copyBytes > bufSize) { - throw new IllegalArgumentException( - "srcOffset (" + srcOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); - } - if (dstOffset + copyBytes > bufSize) { - throw new IllegalArgumentException( - "dstOffset (" + dstOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); - } - - // Initialize the whole source buffer with a verification friendly pattern (no 0x00 bytes) - initVerificationData(src, bufSize, 1); - if (!src.equals(dst)) { - initVerificationData(dst, bufSize, 1); - } - - if (DEBUG) { - System.out.println("===before==="); - for (int offset = 0; offset < bufSize; offset++) { - long srcValue = getArrayElem(src, offset, 1); - long dstValue = getArrayElem(dst, offset, 1); - - System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + - " src=0x" + Long.toHexString(srcValue) + - " dst=0x" + Long.toHexString(dstValue)); - } - } - - // Copy & swap data into the middle of the destination buffer - UNSAFE.copyMemory(src.getObject(), - src.getOffset() + srcOffset, - dst.getObject(), - dst.getOffset() + dstOffset, - copyBytes); - - if (DEBUG) { - System.out.println("===after==="); - for (int offset = 0; offset < bufSize; offset++) { - long srcValue = getArrayElem(src, offset, 1); - long dstValue = getArrayElem(dst, offset, 1); - - System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + - " src=0x" + Long.toHexString(srcValue) + - " dst=0x" + Long.toHexString(dstValue)); - } - } - - // Verify the the front padding is unchanged - verifyUnswappedData(dst, 0, 0, dstOffset); - - // Verify copied data - verifyUnswappedData(dst, dstOffset, srcOffset, copyBytes); - - // Verify that the back back padding is unchanged - long frontAndDataBytes = dstOffset + copyBytes; - long trailingBytes = bufSize - frontAndDataBytes; - verifyUnswappedData(dst, frontAndDataBytes, frontAndDataBytes, trailingBytes); - } - - /** - * Test various configurations copying from one buffer to the other - * - * @param src the source buffer to copy from - * @param dst the destination buffer to copy to - * @param size size (in bytes) of the buffers - * @param elemSize size (in bytes) of the individual elements - * - * @throws RuntimeException if an error is found - */ - public void testBufferPair(GenericPointer src, GenericPointer dst, long size, long elemSize) { - // offset in source from which to start reading data - for (long srcOffset = 0; srcOffset < size; srcOffset += (src.isOnHeap() ? elemSize : 1)) { - - // offset in destination at which to start writing data - for (int dstOffset = 0; dstOffset < size; dstOffset += (dst.isOnHeap() ? elemSize : 1)) { - - // number of bytes to copy - long maxCopyBytes = Math.min(size - srcOffset, size - dstOffset); - for (long copyBytes = 0; copyBytes < maxCopyBytes; copyBytes += elemSize) { - try { - testCopy(src, srcOffset, dst, dstOffset, size, copyBytes); - } catch (RuntimeException e) { - // Wrap the exception in another exception to catch the relevant configuration data - throw new RuntimeException("testBufferPair: " + - "src=" + src + - " dst=" + dst + - " elemSize=0x" + Long.toHexString(elemSize) + - " copyBytes=0x" + Long.toHexString(copyBytes) + - " srcOffset=0x" + Long.toHexString(srcOffset) + - " dstOffset=0x" + Long.toHexString(dstOffset), - e); - } - } - } - } - } - - /** - * Test copying between various permutations of buffers - * - * @param buffers buffers to permute (src x dst) - * @param size size (in bytes) of buffers - * @param elemSize size (in bytes) of individual elements - * - * @throws RuntimeException if an error is found - */ - public void testPermuteBuffers(GenericPointer[] buffers, long size, long elemSize) { - for (int srcIndex = 0; srcIndex < buffers.length; srcIndex++) { - for (int dstIndex = 0; dstIndex < buffers.length; dstIndex++) { - testBufferPair(buffers[srcIndex], buffers[dstIndex], size, elemSize); - } - } - } - - /** - * Test copying of a specific element size - * - * @param size size (in bytes) of buffers to allocate - * @param elemSize size (in bytes) of individual elements - * - * @throws RuntimeException if an error is found - */ - private void testElemSize(long size, long elemSize) { - long buf1Raw = 0; - long buf2Raw = 0; - - try { - buf1Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - long buf1 = alignUp(buf1Raw, BASE_ALIGNMENT); - - buf2Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - long buf2 = alignUp(buf2Raw, BASE_ALIGNMENT); - - GenericPointer[] buffers = { - new GenericPointer(buf1), - new GenericPointer(buf2), - new GenericPointer(allocArray(size, elemSize)), - new GenericPointer(allocArray(size, elemSize)) - }; - - testPermuteBuffers(buffers, size, elemSize); - } finally { - if (buf1Raw != 0) { - UNSAFE.freeMemory(buf1Raw); - } - if (buf2Raw != 0) { - UNSAFE.freeMemory(buf2Raw); - } - } - } - - /** - * Verify that small copies work - */ - private void testSmallCopy() { - int smallBufSize = SMALL_COPY_SIZE; - - testElemSize(smallBufSize, 1); - } - - - /** - * Verify that large copies work - */ - private void testLargeCopy() { - long size = 2 * GB + 8; - long bufRaw = 0; - - // Check that a large native copy succeeds - try { - try { - bufRaw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - } catch (OutOfMemoryError e) { - // Accept failure, skip test - return; - } - - long buf = alignUp(bufRaw, BASE_ALIGNMENT); - - UNSAFE.copyMemory(null, buf, null, buf, size); - } catch (Exception e) { - throw new RuntimeException("copyMemory of large buffer failed"); - } finally { - if (bufRaw != 0) { - UNSAFE.freeMemory(bufRaw); - } - } - } - /** * Run positive tests * * @throws RuntimeException if an error is found */ private void testPositive() { - testSmallCopy(); - testLargeCopy(); + testSmallCopy(false); + testLargeCopy(false); } /** @@ -527,7 +53,7 @@ public class CopyMemory { try { bufRaw = UNSAFE.allocateMemory(1024); - long buf = alignUp(bufRaw, BASE_ALIGNMENT); + long buf = CopyCommon.alignUp(bufRaw, CopyCommon.BASE_ALIGNMENT); short[] arr = new short[16]; // Check illegal sizes @@ -609,59 +135,4 @@ public class CopyMemory { CopyMemory cs = new CopyMemory(); cs.test(); } - - /** - * Helper class to represent a "pointer" - either a heap array or - * a pointer to a native buffer. - * - * In the case of a native pointer, the Object is null and the offset is - * the absolute address of the native buffer. - * - * In the case of a heap object, the Object is a primitive array, and - * the offset will be set to the base offset to the first element, meaning - * the object and the offset together form a double-register pointer. - */ - static class GenericPointer { - private final Object o; - private final long offset; - - private GenericPointer(Object o, long offset) { - this.o = o; - this.offset = offset; - } - - public String toString() { - return "GenericPointer(o={" + o + "}, offset=0x" + Long.toHexString(offset) + ")"; - } - - public boolean equals(Object other) { - if (!(other instanceof GenericPointer)) { - return false; - } - - GenericPointer otherp = (GenericPointer)other; - - return o == otherp.o && offset == otherp.offset; - } - - GenericPointer(Object o) { - this(o, UNSAFE.arrayBaseOffset(o.getClass())); - } - - GenericPointer(long offset) { - this(null, offset); - } - - public boolean isOnHeap() { - return o != null; - } - - public Object getObject() { - return o; - } - - public long getOffset() { - return offset; - } - } } diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java index bb94c200765..4cbd8b709d2 100644 --- a/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java +++ b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java @@ -29,507 +29,18 @@ import java.lang.reflect.Field; * @summary Test Unsafe.copySwapMemory * @modules java.base/jdk.internal.misc */ -public class CopySwap { - private static final boolean DEBUG = Boolean.getBoolean("CopySwap.DEBUG"); - - public static final long KB = 1024; - public static final long MB = KB * 1024; - public static final long GB = MB * 1024; - - private static final Unsafe UNSAFE; - private static final int SMALL_COPY_SIZE = 32; - private static final int BASE_ALIGNMENT = 16; - - static { - try { - Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); - } catch (Exception e) { - throw new RuntimeException("Unable to get Unsafe instance.", e); - } - } - - private static long alignDown(long value, long alignment) { - return value & ~(alignment - 1); - } - - private static long alignUp(long value, long alignment) { - return (value + alignment - 1) & ~(alignment - 1); - } - - private static boolean isAligned(long value, long alignment) { - return value == alignDown(value, alignment); - } - +public class CopySwap extends CopyCommon { private CopySwap() { } - /** - * Generate verification data for a given offset - * - * The verification data is used to verify that the correct bytes - * have indeed been copied and byte swapped. - * - * The data is generated based on the offset (in bytes) into the - * source buffer. For a native buffer the offset is relative to - * the base pointer. For a heap array it is relative to the - * address of the first array element. - * - * This method will return the result of doing an elementSize byte - * read starting at offset (in bytes). - * - * @param offset offset into buffer - * @param elemSize size (in bytes) of the element - * - * @return the verification data, only the least significant - * elemSize*8 bits are set, zero extended - */ - private long getVerificationDataForOffset(long offset, long elemSize) { - byte[] bytes = new byte[(int)elemSize]; - - for (long i = 0; i < elemSize; i++) { - bytes[(int)i] = (byte)(offset + i); - } - - long o = UNSAFE.arrayBaseOffset(byte[].class); - - switch ((int)elemSize) { - case 1: return Byte.toUnsignedLong(UNSAFE.getByte(bytes, o)); - case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(bytes, o)); - case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(bytes, o)); - case 8: return UNSAFE.getLongUnaligned(bytes, o); - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Verify byte swapped data - * - * @param ptr the data to verify - * @param srcOffset the srcOffset (in bytes) from which the copy started, - * used as key to regenerate the verification data - * @param dstOffset the offset (in bytes) in the array at which to start - * the verification, relative to the first element in the array - * @param size size (in bytes) of data to to verify - * @param elemSize size (in bytes) of the individual array elements - * - * @throws RuntimeException if an error is found - */ - private void verifySwappedData(GenericPointer ptr, long srcOffset, long dstOffset, long size, long elemSize) { - for (long offset = 0; offset < size; offset += elemSize) { - long expectedUnswapped = getVerificationDataForOffset(srcOffset + offset, elemSize); - long expected = byteSwap(expectedUnswapped, elemSize); - - long actual = getArrayElem(ptr, dstOffset + offset, elemSize); - - if (expected != actual) { - throw new RuntimeException("srcOffset: 0x" + Long.toHexString(srcOffset) + - " dstOffset: 0x" + Long.toHexString(dstOffset) + - " size: 0x" + Long.toHexString(size) + - " offset: 0x" + Long.toHexString(offset) + - " expectedUnswapped: 0x" + Long.toHexString(expectedUnswapped) + - " expected: 0x" + Long.toHexString(expected) + - " != actual: 0x" + Long.toHexString(actual)); - } - } - } - - /** - * Initialize an array with verification friendly data - * - * @param ptr pointer to the data to initialize - * @param size size (in bytes) of the data - * @param elemSize size (in bytes) of the individual elements - */ - private void initVerificationData(GenericPointer ptr, long size, long elemSize) { - for (long offset = 0; offset < size; offset++) { - byte data = (byte)getVerificationDataForOffset(offset, 1); - - if (ptr.isOnHeap()) { - UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data); - } else { - UNSAFE.putByte(ptr.getOffset() + offset, data); - } - } - } - - /** - * Allocate a primitive array - * - * @param size size (in bytes) of all the array elements (elemSize * length) - * @param elemSize the size of the array elements - * - * @return a newly allocated primitive array - */ - Object allocArray(long size, long elemSize) { - int length = (int)(size / elemSize); - - switch ((int)elemSize) { - case 2: return new short[length]; - case 4: return new int[length]; - case 8: return new long[length]; - default: - throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Get the value of a primitive array entry - * - * @param ptr pointer to the data - * @param offset offset (in bytes) of the array element, relative to the first element in the array - * - * @return the array element, as an unsigned long - */ - private long getArrayElem(GenericPointer ptr, long offset, long elemSize) { - if (ptr.isOnHeap()) { - Object o = ptr.getObject(); - int index = (int)(offset / elemSize); - - if (o instanceof short[]) { - short[] arr = (short[])o; - return Short.toUnsignedLong(arr[index]); - } else if (o instanceof int[]) { - int[] arr = (int[])o; - return Integer.toUnsignedLong(arr[index]); - } else if (o instanceof long[]) { - long[] arr = (long[])o; - return arr[index]; - } else { - throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); - } - } else { - long addr = ptr.getOffset() + offset; - - switch ((int)elemSize) { - case 1: return Byte.toUnsignedLong(UNSAFE.getByte(addr)); - case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(null, addr)); - case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(null, addr)); - case 8: return UNSAFE.getLongUnaligned(null, addr); - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - } - - private void putValue(long addr, long elemSize, long value) { - switch ((int)elemSize) { - case 1: UNSAFE.putByte(addr, (byte)value); break; - case 2: UNSAFE.putShortUnaligned(null, addr, (short)value); break; - case 4: UNSAFE.putIntUnaligned(null, addr, (int)value); break; - case 8: UNSAFE.putLongUnaligned(null, addr, value); break; - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Get the size of the elements for an array - * - * @param o a primitive heap array - * - * @return the size (in bytes) of the individual array elements - */ - private long getArrayElemSize(Object o) { - if (o instanceof short[]) { - return 2; - } else if (o instanceof int[]) { - return 4; - } else if (o instanceof long[]) { - return 8; - } else { - throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); - } - } - - /** - * Byte swap a value - * - * @param value the value to swap, only the bytes*8 least significant bits are used - * @param size size (in bytes) of the value - * - * @return the byte swapped value in the bytes*8 least significant bits - */ - private long byteSwap(long value, long size) { - switch ((int)size) { - case 2: return Short.toUnsignedLong(Short.reverseBytes((short)value)); - case 4: return Integer.toUnsignedLong(Integer.reverseBytes((int)value)); - case 8: return Long.reverseBytes(value); - default: throw new IllegalArgumentException("Invalid element size: " + size); - } - } - - /** - * Verify data in a heap array which has *not* been byte swapped - * - * @param ptr the data to verify - * @param startOffset the offset (in bytes) at which to start the verification - * @param size size (in bytes) of the data to verify - * - * @throws RuntimeException if an error is found - */ - private void verifyUnswappedData(GenericPointer ptr, long startOffset, long size) { - for (long elemOffset = startOffset; elemOffset < startOffset + size; elemOffset++) { - byte expected = (byte)getVerificationDataForOffset(elemOffset, 1); - - byte actual; - if (ptr.isOnHeap()) { - actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + elemOffset); - } else { - actual = UNSAFE.getByte(ptr.getOffset() + elemOffset); - } - - if (expected != actual) { - throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) + - " size: 0x" + Long.toHexString(size) + - " elemOffset: 0x" + Long.toHexString(elemOffset) + - " expected: 0x" + Long.toHexString(expected) + - " != actual: 0x" + Long.toHexString(actual)); - } - } - } - - - /** - * Copy and byte swap data from the source to the destination - * - * This method will pre-populate the whole source and destination - * buffers with verification friendly data. It will then use - * copySwapMemory to fill part of the destination buffer with - * swapped data from the source. Some space (padding) will be - * left before and after the data in the destination buffer, which - * should not be touched/overwritten by the copy call. - * - * Note: Both source and destination buffers will be overwritten! - * - * @param src source buffer to copy from - * @param srcOffset the offset (in bytes) in the source buffer, relative to - * the first array element, at which to start reading data - * @param dst destination buffer to copy to - * @param dstOffset the offset (in bytes) in the destination - * buffer, relative to the first array element, at which to - * start writing data - * @param bufSize the size (in bytes) of the src and dst arrays - * @param copyBytes the size (in bytes) of the copy to perform, - * must be a multiple of elemSize - * @param elemSize the size (in bytes) of the elements to byte swap - * - * @throws RuntimeException if an error is found - */ - private void testCopySwap(GenericPointer src, long srcOffset, - GenericPointer dst, long dstOffset, - long bufSize, long copyBytes, long elemSize) { - if (!isAligned(copyBytes, elemSize)) { - throw new IllegalArgumentException( - "copyBytes (" + copyBytes + ") must be a multiple of elemSize (" + elemSize + ")"); - } - if (src.isOnHeap() && !isAligned(srcOffset, elemSize)) { - throw new IllegalArgumentException( - "srcOffset (" + srcOffset + ") must be a multiple of elemSize (" + elemSize + ")"); - } - if (dst.isOnHeap() && !isAligned(dstOffset, elemSize)) { - throw new IllegalArgumentException( - "dstOffset (" + dstOffset + ") must be a multiple of elemSize (" + elemSize + ")"); - } - if (srcOffset + copyBytes > bufSize) { - throw new IllegalArgumentException( - "srcOffset (" + srcOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); - } - if (dstOffset + copyBytes > bufSize) { - throw new IllegalArgumentException( - "dstOffset (" + dstOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); - } - - // Initialize the whole source buffer with a verification friendly pattern (no 0x00 bytes) - initVerificationData(src, bufSize, elemSize); - if (!src.equals(dst)) { - initVerificationData(dst, bufSize, elemSize); - } - - if (DEBUG) { - System.out.println("===before==="); - for (int offset = 0; offset < bufSize; offset += elemSize) { - long srcValue = getArrayElem(src, offset, elemSize); - long dstValue = getArrayElem(dst, offset, elemSize); - - System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + - " src=0x" + Long.toHexString(srcValue) + - " dst=0x" + Long.toHexString(dstValue)); - } - } - - // Copy & swap data into the middle of the destination buffer - UNSAFE.copySwapMemory(src.getObject(), - src.getOffset() + srcOffset, - dst.getObject(), - dst.getOffset() + dstOffset, - copyBytes, - elemSize); - - if (DEBUG) { - System.out.println("===after==="); - for (int offset = 0; offset < bufSize; offset += elemSize) { - long srcValue = getArrayElem(src, offset, elemSize); - long dstValue = getArrayElem(dst, offset, elemSize); - - System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + - " src=0x" + Long.toHexString(srcValue) + - " dst=0x" + Long.toHexString(dstValue)); - } - } - - // Verify the the front padding is unchanged - verifyUnswappedData(dst, 0, dstOffset); - - // Verify swapped data - verifySwappedData(dst, srcOffset, dstOffset, copyBytes, elemSize); - - // Verify that the back back padding is unchanged - long frontAndDataBytes = dstOffset + copyBytes; - long trailingBytes = bufSize - frontAndDataBytes; - verifyUnswappedData(dst, frontAndDataBytes, trailingBytes); - } - - /** - * Test various configurations copy-swapping from one buffer to the other - * - * @param src the source buffer to copy from - * @param dst the destination buffer to copy to - * @param size size (in bytes) of the buffers - * @param elemSize size (in bytes) of the individual elements - * - * @throws RuntimeException if an error is found - */ - public void testBufferPair(GenericPointer src, GenericPointer dst, long size, long elemSize) { - // offset in source from which to start reading data - for (long srcOffset = 0; srcOffset < size; srcOffset += (src.isOnHeap() ? elemSize : 1)) { - - // offset in destination at which to start writing data - for (int dstOffset = 0; dstOffset < size; dstOffset += (dst.isOnHeap() ? elemSize : 1)) { - - // number of bytes to copy - long maxCopyBytes = Math.min(size - srcOffset, size - dstOffset); - for (long copyBytes = 0; copyBytes < maxCopyBytes; copyBytes += elemSize) { - try { - testCopySwap(src, srcOffset, dst, dstOffset, size, copyBytes, elemSize); - } catch (RuntimeException e) { - // Wrap the exception in another exception to catch the relevant configuration data - throw new RuntimeException("testBufferPair: " + - "src=" + src + - " dst=" + dst + - " elemSize=0x" + Long.toHexString(elemSize) + - " copyBytes=0x" + Long.toHexString(copyBytes) + - " srcOffset=0x" + Long.toHexString(srcOffset) + - " dstOffset=0x" + Long.toHexString(dstOffset), - e); - } - } - } - } - } - - /** - * Test copying between various permutations of buffers - * - * @param buffers buffers to permute (src x dst) - * @param size size (in bytes) of buffers - * @param elemSize size (in bytes) of individual elements - * - * @throws RuntimeException if an error is found - */ - public void testPermuteBuffers(GenericPointer[] buffers, long size, long elemSize) { - for (int srcIndex = 0; srcIndex < buffers.length; srcIndex++) { - for (int dstIndex = 0; dstIndex < buffers.length; dstIndex++) { - testBufferPair(buffers[srcIndex], buffers[dstIndex], size, elemSize); - } - } - } - - /** - * Test copying of a specific element size - * - * @param size size (in bytes) of buffers to allocate - * @param elemSize size (in bytes) of individual elements - * - * @throws RuntimeException if an error is found - */ - private void testElemSize(long size, long elemSize) { - long buf1Raw = 0; - long buf2Raw = 0; - - try { - buf1Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - long buf1 = alignUp(buf1Raw, BASE_ALIGNMENT); - - buf2Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - long buf2 = alignUp(buf2Raw, BASE_ALIGNMENT); - - GenericPointer[] buffers = { - new GenericPointer(buf1), - new GenericPointer(buf2), - new GenericPointer(allocArray(size, elemSize)), - new GenericPointer(allocArray(size, elemSize)) - }; - - testPermuteBuffers(buffers, size, elemSize); - } finally { - if (buf1Raw != 0) { - UNSAFE.freeMemory(buf1Raw); - } - if (buf2Raw != 0) { - UNSAFE.freeMemory(buf2Raw); - } - } - } - - /** - * Verify that small copy swaps work - */ - private void testSmallCopy() { - int smallBufSize = SMALL_COPY_SIZE; - - // Test various element types and heap/native combinations - for (long elemSize = 2; elemSize <= 8; elemSize <<= 1) { - testElemSize(smallBufSize, elemSize); - } - } - - - /** - * Verify that large copy swaps work - */ - private void testLargeCopy() { - long size = 2 * GB + 8; - long bufRaw = 0; - - // Check that a large native copy succeeds - try { - try { - bufRaw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - } catch (OutOfMemoryError e) { - // Accept failure, skip test - return; - } - - long buf = alignUp(bufRaw, BASE_ALIGNMENT); - - UNSAFE.copySwapMemory(null, buf, null, buf, size, 8); - } catch (Exception e) { - throw new RuntimeException("copySwapMemory of large buffer failed"); - } finally { - if (bufRaw != 0) { - UNSAFE.freeMemory(bufRaw); - } - } - } - /** * Run positive tests * * @throws RuntimeException if an error is found */ private void testPositive() { - testSmallCopy(); - testLargeCopy(); + testSmallCopy(true); + testLargeCopy(true); } /** @@ -542,7 +53,7 @@ public class CopySwap { try { bufRaw = UNSAFE.allocateMemory(1024); - long buf = alignUp(bufRaw, BASE_ALIGNMENT); + long buf = CopyCommon.alignUp(bufRaw, CopyCommon.BASE_ALIGNMENT); short[] arr = new short[16]; // Check various illegal element sizes @@ -637,59 +148,4 @@ public class CopySwap { CopySwap cs = new CopySwap(); cs.test(); } - - /** - * Helper class to represent a "pointer" - either a heap array or - * a pointer to a native buffer. - * - * In the case of a native pointer, the Object is null and the offset is - * the absolute address of the native buffer. - * - * In the case of a heap object, the Object is a primitive array, and - * the offset will be set to the base offset to the first element, meaning - * the object and the offset together form a double-register pointer. - */ - static class GenericPointer { - private final Object o; - private final long offset; - - private GenericPointer(Object o, long offset) { - this.o = o; - this.offset = offset; - } - - public String toString() { - return "GenericPointer(o={" + o + "}, offset=0x" + Long.toHexString(offset) + ")"; - } - - public boolean equals(Object other) { - if (!(other instanceof GenericPointer)) { - return false; - } - - GenericPointer otherp = (GenericPointer)other; - - return o == otherp.o && offset == otherp.offset; - } - - GenericPointer(Object o) { - this(o, UNSAFE.arrayBaseOffset(o.getClass())); - } - - GenericPointer(long offset) { - this(null, offset); - } - - public boolean isOnHeap() { - return o != null; - } - - public Object getObject() { - return o; - } - - public long getOffset() { - return offset; - } - } } From 9a55e05cfb4cf1ea7812dc0ab549e11ea65883e2 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 17 Mar 2016 08:47:46 -0700 Subject: [PATCH 128/129] 8152043: (fs) Remove dynamic loopup of Win32 API functions in WindowsNativeDispatcher needed to support Windows XP and Server 2003 Remove dynamic lookup of Win32 functions which was required to support Windows XP and Windows Server 2003. Reviewed-by: alanb --- .../libnio/fs/WindowsNativeDispatcher.c | 70 ++----------------- 1 file changed, 6 insertions(+), 64 deletions(-) diff --git a/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c b/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c index 8075d046763..eeb6456ae6a 100644 --- a/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c +++ b/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,6 @@ * questions. */ -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif - #include #include #include @@ -77,21 +73,6 @@ static jfieldID backupResult_bytesTransferred; static jfieldID backupResult_context; -/** - * Win32 APIs not available in Windows XP - */ -typedef HANDLE (WINAPI* FindFirstStream_Proc)(LPCWSTR, STREAM_INFO_LEVELS, LPVOID, DWORD); -typedef BOOL (WINAPI* FindNextStream_Proc)(HANDLE, LPVOID); - -typedef BOOLEAN (WINAPI* CreateSymbolicLinkProc) (LPCWSTR, LPCWSTR, DWORD); -typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD); - -static FindFirstStream_Proc FindFirstStream_func; -static FindNextStream_Proc FindNextStream_func; - -static CreateSymbolicLinkProc CreateSymbolicLink_func; -static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func; - static void throwWindowsException(JNIEnv* env, DWORD lastError) { jobject x = JNU_NewObjectByName(env, "sun/nio/fs/WindowsException", "(I)V", lastError); @@ -108,7 +89,6 @@ JNIEXPORT void JNICALL Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this) { jclass clazz; - HMODULE h; clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstFile"); CHECK_NULL(clazz); @@ -175,24 +155,6 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this) CHECK_NULL(backupResult_bytesTransferred); backupResult_context = (*env)->GetFieldID(env, clazz, "context", "J"); CHECK_NULL(backupResult_context); - - // get handle to kernel32 - if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT), - (LPCWSTR)&CreateFileW, &h) != 0) - { - // requires Windows Server 2003 or newer - FindFirstStream_func = - (FindFirstStream_Proc)GetProcAddress(h, "FindFirstStreamW"); - FindNextStream_func = - (FindNextStream_Proc)GetProcAddress(h, "FindNextStreamW"); - - // requires Windows Vista or newer - CreateSymbolicLink_func = - (CreateSymbolicLinkProc)GetProcAddress(h, "CreateSymbolicLinkW"); - GetFinalPathNameByHandle_func = - (GetFinalPathNameByHandleProc)GetProcAddress(h, "GetFinalPathNameByHandleW"); - } } JNIEXPORT jlong JNICALL @@ -404,12 +366,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstStream0(JNIEnv* env, jclass thi LPCWSTR lpFileName = jlong_to_ptr(address); HANDLE handle; - if (FindFirstStream_func == NULL) { - JNU_ThrowInternalError(env, "Should not get here"); - return; - } - - handle = (*FindFirstStream_func)(lpFileName, FindStreamInfoStandard, &data, 0); + handle = FindFirstStreamW(lpFileName, FindStreamInfoStandard, &data, 0); if (handle != INVALID_HANDLE_VALUE) { jstring name = (*env)->NewString(env, data.cStreamName, (jsize)wcslen(data.cStreamName)); if (name == NULL) @@ -433,12 +390,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindNextStream(JNIEnv* env, jclass this, WIN32_FIND_STREAM_DATA data; HANDLE h = (HANDLE)jlong_to_ptr(handle); - if (FindNextStream_func == NULL) { - JNU_ThrowInternalError(env, "Should not get here"); - return NULL; - } - - if ((*FindNextStream_func)(h, &data) != 0) { + if (FindNextStreamW(h, &data) != 0) { return (*env)->NewString(env, data.cStreamName, (jsize)wcslen(data.cStreamName)); } else { if (GetLastError() != ERROR_HANDLE_EOF) @@ -1087,13 +1039,8 @@ Java_sun_nio_fs_WindowsNativeDispatcher_CreateSymbolicLink0(JNIEnv* env, LPCWSTR link = jlong_to_ptr(linkAddress); LPCWSTR target = jlong_to_ptr(targetAddress); - if (CreateSymbolicLink_func == NULL) { - JNU_ThrowInternalError(env, "Should not get here"); - return; - } - /* On Windows 64-bit this appears to succeed even when there is insufficient privileges */ - if ((*CreateSymbolicLink_func)(link, target, (DWORD)flags) == 0) + if (CreateSymbolicLinkW(link, target, (DWORD)flags) == 0) throwWindowsException(env, GetLastError()); } @@ -1155,12 +1102,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetFinalPathNameByHandle(JNIEnv* env, HANDLE h = (HANDLE)jlong_to_ptr(handle); DWORD len; - if (GetFinalPathNameByHandle_func == NULL) { - JNU_ThrowInternalError(env, "Should not get here"); - return NULL; - } - - len = (*GetFinalPathNameByHandle_func)(h, path, MAX_PATH, 0); + len = GetFinalPathNameByHandleW(h, path, MAX_PATH, 0); if (len > 0) { if (len < MAX_PATH) { rv = (*env)->NewString(env, (const jchar *)path, (jsize)len); @@ -1168,7 +1110,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetFinalPathNameByHandle(JNIEnv* env, len += 1; /* return length does not include terminator */ lpBuf = (WCHAR*)malloc(len * sizeof(WCHAR)); if (lpBuf != NULL) { - len = (*GetFinalPathNameByHandle_func)(h, lpBuf, len, 0); + len = GetFinalPathNameByHandleW(h, lpBuf, len, 0); if (len > 0) { rv = (*env)->NewString(env, (const jchar *)lpBuf, (jsize)len); } else { From 872d60701a342adebf363579edfdbace682e12f6 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Fri, 18 Mar 2016 13:14:53 +0000 Subject: [PATCH 129/129] 8149169: SSLSocketInputRecord.decodeInputRecord buffer overflow Reviewed-by: xuelei --- .../sun/security/ssl/SSLSocketImpl.java | 27 +-- .../LargePacketAfterHandshakeTest.java | 183 ++++++++++++++++++ 2 files changed, 197 insertions(+), 13 deletions(-) create mode 100644 jdk/test/sun/security/ssl/SSLSocketImpl/LargePacketAfterHandshakeTest.java diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java index 86b772c09da..412c3ec8544 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -365,17 +365,6 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl { /* Class and subclass dynamic debugging support */ private static final Debug debug = Debug.getInstance("ssl"); - /* - * Is it the first application record to write? - */ - private boolean isFirstAppOutputRecord = true; - - /* - * If AppOutputStream needs to delay writes of small packets, we - * will use this to store the data until we actually do the write. - */ - private ByteArrayOutputStream heldRecordBuffer = null; - /* * Whether local cipher suites preference in server side should be * honored during handshaking? @@ -998,9 +987,21 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl { Plaintext plainText = null; while (((state = getConnectionState()) != cs_CLOSED) && (state != cs_ERROR) && (state != cs_APP_CLOSED)) { - // clean the buffer + + /* + * clean the buffer and check if it is too small, e.g. because + * the AppInputStream did not have the chance to see the + * current packet length but rather something like that of the + * handshake before. In that case we return 0 at this point to + * give the caller the chance to adjust the buffer. + */ if (buffer != null) { buffer.clear(); + + if (buffer.remaining() < + inputRecord.bytesInCompletePacket(sockInput)) { + return 0; + } } /* diff --git a/jdk/test/sun/security/ssl/SSLSocketImpl/LargePacketAfterHandshakeTest.java b/jdk/test/sun/security/ssl/SSLSocketImpl/LargePacketAfterHandshakeTest.java new file mode 100644 index 00000000000..fd7ae8fa3c9 --- /dev/null +++ b/jdk/test/sun/security/ssl/SSLSocketImpl/LargePacketAfterHandshakeTest.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; + +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +/* + * @test + * @bug 8149169 + * @summary Test for BufferOverflowException during read from SSLSocket when + * large packet is coming from server after server initiated handshake + * @run main/othervm LargePacketAfterHandshakeTest + */ +public class LargePacketAfterHandshakeTest { + static String pathToStores = "../../../../javax/net/ssl/etc"; + static String keyStoreFile = "keystore"; + static String trustStoreFile = "truststore"; + static String passwd = "passphrase"; + + volatile static int serverport = -1; + volatile static boolean serverReady = false; + volatile static boolean clientDone = false; + volatile static Exception serverException = null; + + public static void runServer() { + try { + System.out.println("Server: Started server thread."); + SSLServerSocketFactory ssf = + (SSLServerSocketFactory)SSLServerSocketFactory.getDefault(); + SSLServerSocket s = (SSLServerSocket)ssf.createServerSocket(0); + serverport = s.getLocalPort(); + System.out.println("Server: Started, listening on port " + + serverport + "."); + serverReady = true; + SSLSocket c = (SSLSocket)s.accept(); + s.close(); + System.out.println( + "Server: Accepted client connection and closed server socket."); + BufferedReader r = new BufferedReader( + new InputStreamReader(c.getInputStream())); + BufferedWriter w = new BufferedWriter( + new OutputStreamWriter(c.getOutputStream())); + String echostring = r.readLine(); + System.out.println("Server: Read " + echostring.length() + + " chars of input data."); + c.startHandshake(); + System.out.println("Server: Kicked new handshake."); + w.write(echostring); + w.newLine(); + w.flush(); + System.out.println("Server: Echoed " + echostring.length() + + " chars of input data."); + while (!clientDone) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + System.out.println("Server: Caught InterruptedException."); + } + } + r.close(); + w.close(); + c.close(); + System.out.println( + "Server: Closed streams and client socket, exiting."); + } catch (Exception e) { + System.out.println("Server: Caught Exception."); + e.printStackTrace(); + serverReady = true; + serverException = e; + } + } + + public static void runClient() throws IOException { + try { + SSLSocketFactory f = + (SSLSocketFactory)SSLSocketFactory.getDefault(); + System.out.println("Client: Initialized."); + while (!serverReady) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + System.out.println("Client: Caught InterruptedException."); + } + } + SSLSocket c = (SSLSocket)f.createSocket("localhost", serverport); + BufferedWriter w = new BufferedWriter( + new OutputStreamWriter(c.getOutputStream())); + BufferedReader r = new BufferedReader( + new InputStreamReader(c.getInputStream())); + System.out.println("Client: Connected."); + String echoPattern = "Otto"; + StringBuilder echoBuilder = + new StringBuilder(4500 + echoPattern.length()); + while (echoBuilder.length() < 4500) { + echoBuilder.append(echoPattern); + } + String echostring = echoBuilder.toString(); + w.write(echostring); + w.newLine(); + w.flush(); + System.out.println("Client: Sent " + echostring.length() + + " chars of data."); + String echoresponse = r.readLine(); + clientDone = true; + System.out.println("Client: Read " + echoresponse.length() + + " chars of data."); + w.close(); + r.close(); + c.close(); + System.out.println("Client: Closed streams and socket, exiting."); + } catch (IOException e) { + System.out.println("Client: Caught Exception."); + e.printStackTrace(); + clientDone = true; + throw e; + } + } + + public static void main(String[] args) throws Exception { + String keyFilename = System.getProperty("test.src", "./") + "/" + + pathToStores + "/" + keyStoreFile; + String trustFilename = System.getProperty("test.src", "./") + "/" + + pathToStores + "/" + trustStoreFile; + + System.setProperty("javax.net.ssl.keyStore", keyFilename); + System.setProperty("javax.net.ssl.keyStorePassword", passwd); + System.setProperty("javax.net.ssl.trustStore", trustFilename); + System.setProperty("javax.net.ssl.trustStorePassword", passwd); + + Thread serverThread = new Thread() { + @Override + public void run() { + runServer(); + } + }; + serverThread.start(); + runClient(); + while (serverThread.isAlive()) { + try { + serverThread.join(); + } catch (InterruptedException e) { + System.out.println("Main: Caught InterruptedException " + + " waiting for server Thread."); + } + } + if (serverException != null) { + throw serverException; + } + } +}