# HG changeset patch # User asaha # Date 1414090928 25200 # Node ID c2844108a7085f7ed4a7450da08d0b7865e44dab # Parent 8538a606a105b92d273899b640bc8b5e9b6f4fdb# Parent e620c670a9a743d56e32152f36b01bc3460f320b Merge diff -r 8538a606a105 -r c2844108a708 .hgtags --- a/.hgtags Wed Oct 22 11:18:17 2014 -0700 +++ b/.hgtags Thu Oct 23 12:02:08 2014 -0700 @@ -501,6 +501,8 @@ 00cf2b6f51b9560b01030e8f4c28c466f0b21fe3 hs25.20-b23 19408d5fd31c25ce60c43dd33e92b96e8df4a4ea jdk8u20-b25 eaa4074a7e3975cd33ec55e6b584586e2ac681bd jdk8u20-b26 +7c9925f21c2529a88eb64b8039cc080f60b85e01 jdk8u20-b31 +7edb04063a423e278fe34a0006d25fee198f495e jdk8u20-b32 4828415ebbf11e205dcc08e97ad5ae7dd03522f9 jdk8u40-b00 d952af8cf67dd1e7ab5fec9a299c6c6dafd1863e hs25.40-b01 f0afba33c928ddaa2d5f003b90d683c143f78ea3 hs25.40-b02 @@ -544,6 +546,13 @@ 6467bdd4d22d8b140844dc847c43b9ba7cb0bbd1 jdk8u25-b16 28b50d07f6f8c5a567b6a25e95a423948114a004 jdk8u25-b17 639abc668bfe995dba811dd35411b9ea8a9041cd jdk8u25-b18 +c3528699fb33fe3eb1d117504184ae7ab2507aa1 jdk8u25-b31 +5bb683bbe2c74876d585b5c3232fc3aab7b23e97 jdk8u31-b00 +5bb686ae3b89f8aa1c74331b2d24e2a5ebd43448 jdk8u31-b01 +087678da96603c9705b38b6cc4a6569ac7b4420a jdk8u31-b02 +401cbaa475b4efe53153119ab87a82b217980a7f jdk8u31-b03 +060cdf93040c1bfa5fdf580da5e9999042632cc8 jdk8u31-b04 +6e56d7f1634f6c4cd4196e699c06e6ca2e6d6efb jdk8u31-b05 1b3abbeee961dee49780c0e4af5337feb918c555 jdk8u40-b10 f10fe402dfb1543723b4b117a7cba3ea3d4159f1 hs25.40-b15 99372b2fee0eb8b3452f47230e84aa6e97003184 jdk8u40-b11 diff -r 8538a606a105 -r c2844108a708 make/hotspot_version --- a/make/hotspot_version Wed Oct 22 11:18:17 2014 -0700 +++ b/make/hotspot_version Thu Oct 23 12:02:08 2014 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ # # Don't put quotes (fail windows build). -HOTSPOT_VM_COPYRIGHT=Copyright 2014 +HOTSPOT_VM_COPYRIGHT=Copyright 2015 HS_MAJOR_VER=25 HS_MINOR_VER=40 diff -r 8538a606a105 -r c2844108a708 src/share/vm/ci/bcEscapeAnalyzer.cpp --- a/src/share/vm/ci/bcEscapeAnalyzer.cpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/ci/bcEscapeAnalyzer.cpp Thu Oct 23 12:02:08 2014 -0700 @@ -89,8 +89,8 @@ public: ArgumentMap *_vars; ArgumentMap *_stack; - short _stack_height; - short _max_stack; + int _stack_height; + int _max_stack; bool _initialized; ArgumentMap empty_map; diff -r 8538a606a105 -r c2844108a708 src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/classfile/systemDictionary.cpp Thu Oct 23 12:02:08 2014 -0700 @@ -1908,11 +1908,12 @@ InstanceKlass::cast(WK_KLASS(Reference_klass))->set_reference_type(REF_OTHER); InstanceRefKlass::update_nonstatic_oop_maps(WK_KLASS(Reference_klass)); - initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(PhantomReference_klass), scan, CHECK); + initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Cleaner_klass), scan, CHECK); InstanceKlass::cast(WK_KLASS(SoftReference_klass))->set_reference_type(REF_SOFT); InstanceKlass::cast(WK_KLASS(WeakReference_klass))->set_reference_type(REF_WEAK); InstanceKlass::cast(WK_KLASS(FinalReference_klass))->set_reference_type(REF_FINAL); InstanceKlass::cast(WK_KLASS(PhantomReference_klass))->set_reference_type(REF_PHANTOM); + InstanceKlass::cast(WK_KLASS(Cleaner_klass))->set_reference_type(REF_CLEANER); // JSR 292 classes WKID jsr292_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass); diff -r 8538a606a105 -r c2844108a708 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/classfile/systemDictionary.hpp Thu Oct 23 12:02:08 2014 -0700 @@ -128,6 +128,7 @@ do_klass(WeakReference_klass, java_lang_ref_WeakReference, Pre ) \ do_klass(FinalReference_klass, java_lang_ref_FinalReference, Pre ) \ do_klass(PhantomReference_klass, java_lang_ref_PhantomReference, Pre ) \ + do_klass(Cleaner_klass, sun_misc_Cleaner, Pre ) \ do_klass(Finalizer_klass, java_lang_ref_Finalizer, Pre ) \ \ do_klass(Thread_klass, java_lang_Thread, Pre ) \ diff -r 8538a606a105 -r c2844108a708 src/share/vm/classfile/verifier.cpp --- a/src/share/vm/classfile/verifier.cpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/classfile/verifier.cpp Thu Oct 23 12:02:08 2014 -0700 @@ -1553,14 +1553,14 @@ case Bytecodes::_invokespecial : case Bytecodes::_invokestatic : verify_invoke_instructions( - &bcs, code_length, ¤t_frame, - &this_uninit, return_type, cp, CHECK_VERIFY(this)); + &bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max), + &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_invokeinterface : case Bytecodes::_invokedynamic : verify_invoke_instructions( - &bcs, code_length, ¤t_frame, - &this_uninit, return_type, cp, CHECK_VERIFY(this)); + &bcs, code_length, ¤t_frame, (bci >= ex_min && bci < ex_max), + &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_new : { @@ -2408,8 +2408,9 @@ void ClassVerifier::verify_invoke_init( RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type, - StackMapFrame* current_frame, u4 code_length, bool *this_uninit, - constantPoolHandle cp, TRAPS) { + StackMapFrame* current_frame, u4 code_length, bool in_try_block, + bool *this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table, + TRAPS) { u2 bci = bcs->bci(); VerificationType type = current_frame->pop_stack( VerificationType::reference_check(), CHECK_VERIFY(this)); @@ -2425,28 +2426,36 @@ return; } - // Check if this call is done from inside of a TRY block. If so, make - // sure that all catch clause paths end in a throw. Otherwise, this - // can result in returning an incomplete object. - ExceptionTable exhandlers(_method()); - int exlength = exhandlers.length(); - for(int i = 0; i < exlength; i++) { - u2 start_pc = exhandlers.start_pc(i); - u2 end_pc = exhandlers.end_pc(i); + // If this invokespecial call is done from inside of a TRY block then make + // sure that all catch clause paths end in a throw. Otherwise, this can + // result in returning an incomplete object. + if (in_try_block) { + ExceptionTable exhandlers(_method()); + int exlength = exhandlers.length(); + for(int i = 0; i < exlength; i++) { + u2 start_pc = exhandlers.start_pc(i); + u2 end_pc = exhandlers.end_pc(i); - if (bci >= start_pc && bci < end_pc) { - if (!ends_in_athrow(exhandlers.handler_pc(i))) { - verify_error(ErrorContext::bad_code(bci), - "Bad method call from after the start of a try block"); - return; - } else if (VerboseVerification) { - ResourceMark rm; - tty->print_cr( - "Survived call to ends_in_athrow(): %s", - current_class()->name()->as_C_string()); + if (bci >= start_pc && bci < end_pc) { + if (!ends_in_athrow(exhandlers.handler_pc(i))) { + verify_error(ErrorContext::bad_code(bci), + "Bad method call from after the start of a try block"); + return; + } else if (VerboseVerification) { + ResourceMark rm; + tty->print_cr( + "Survived call to ends_in_athrow(): %s", + current_class()->name()->as_C_string()); + } } } - } + + // Check the exception handler target stackmaps with the locals from the + // incoming stackmap (before initialize_object() changes them to outgoing + // state). + verify_exception_handler_targets(bci, true, current_frame, + stackmap_table, CHECK_VERIFY(this)); + } // in_try_block current_frame->initialize_object(type, current_type()); *this_uninit = true; @@ -2500,6 +2509,13 @@ } } } + // Check the exception handler target stackmaps with the locals from the + // incoming stackmap (before initialize_object() changes them to outgoing + // state). + if (in_try_block) { + verify_exception_handler_targets(bci, *this_uninit, current_frame, + stackmap_table, CHECK_VERIFY(this)); + } current_frame->initialize_object(type, new_class_type); } else { verify_error(ErrorContext::bad_type(bci, current_frame->stack_top_ctx()), @@ -2528,8 +2544,8 @@ void ClassVerifier::verify_invoke_instructions( RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame, - bool *this_uninit, VerificationType return_type, - constantPoolHandle cp, TRAPS) { + bool in_try_block, bool *this_uninit, VerificationType return_type, + constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS) { // Make sure the constant pool item is the right type u2 index = bcs->get_index_u2(); Bytecodes::Code opcode = bcs->raw_code(); @@ -2699,7 +2715,8 @@ opcode != Bytecodes::_invokedynamic) { if (method_name == vmSymbols::object_initializer_name()) { // method verify_invoke_init(bcs, index, ref_class_type, current_frame, - code_length, this_uninit, cp, CHECK_VERIFY(this)); + code_length, in_try_block, this_uninit, cp, stackmap_table, + CHECK_VERIFY(this)); } else { // other methods // Ensures that target class is assignable to method class. if (opcode == Bytecodes::_invokespecial) { diff -r 8538a606a105 -r c2844108a708 src/share/vm/classfile/verifier.hpp --- a/src/share/vm/classfile/verifier.hpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/classfile/verifier.hpp Thu Oct 23 12:02:08 2014 -0700 @@ -301,8 +301,9 @@ void verify_invoke_init( RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type, - StackMapFrame* current_frame, u4 code_length, bool* this_uninit, - constantPoolHandle cp, TRAPS); + StackMapFrame* current_frame, u4 code_length, bool in_try_block, + bool* this_uninit, constantPoolHandle cp, StackMapTable* stackmap_table, + TRAPS); // Used by ends_in_athrow() to push all handlers that contain bci onto // the handler_stack, if the handler is not already on the stack. @@ -316,8 +317,8 @@ void verify_invoke_instructions( RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame, - bool* this_uninit, VerificationType return_type, - constantPoolHandle cp, TRAPS); + bool in_try_block, bool* this_uninit, VerificationType return_type, + constantPoolHandle cp, StackMapTable* stackmap_table, TRAPS); VerificationType get_newarray_type(u2 index, u2 bci, TRAPS); void verify_anewarray(u2 bci, u2 index, constantPoolHandle cp, diff -r 8538a606a105 -r c2844108a708 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/classfile/vmSymbols.hpp Thu Oct 23 12:02:08 2014 -0700 @@ -79,6 +79,7 @@ template(java_lang_ref_WeakReference, "java/lang/ref/WeakReference") \ template(java_lang_ref_FinalReference, "java/lang/ref/FinalReference") \ template(java_lang_ref_PhantomReference, "java/lang/ref/PhantomReference") \ + template(sun_misc_Cleaner, "sun/misc/Cleaner") \ template(java_lang_ref_Finalizer, "java/lang/ref/Finalizer") \ template(java_lang_reflect_AccessibleObject, "java/lang/reflect/AccessibleObject") \ template(java_lang_reflect_Method, "java/lang/reflect/Method") \ diff -r 8538a606a105 -r c2844108a708 src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp diff -r 8538a606a105 -r c2844108a708 src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp diff -r 8538a606a105 -r c2844108a708 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Oct 23 12:02:08 2014 -0700 @@ -738,7 +738,7 @@ // Support for parallelizing survivor space rescan if ((CMSParallelRemarkEnabled && CMSParallelSurvivorRemarkEnabled) || CMSParallelInitialMarkEnabled) { const size_t max_plab_samples = - ((DefNewGeneration*)_young_gen)->max_survivor_size()/MinTLABSize; + ((DefNewGeneration*)_young_gen)->max_survivor_size() / plab_sample_minimum_size(); _survivor_plab_array = NEW_C_HEAP_ARRAY(ChunkArray, ParallelGCThreads, mtGC); _survivor_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, 2*max_plab_samples, mtGC); @@ -796,6 +796,12 @@ _inter_sweep_timer.start(); // start of time } +size_t CMSCollector::plab_sample_minimum_size() { + // The default value of MinTLABSize is 2k, but there is + // no way to get the default value if the flag has been overridden. + return MAX2(ThreadLocalAllocBuffer::min_size() * HeapWordSize, 2 * K); +} + const char* ConcurrentMarkSweepGeneration::name() const { return "concurrent mark-sweep generation"; } diff -r 8538a606a105 -r c2844108a708 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Thu Oct 23 12:02:08 2014 -0700 @@ -764,6 +764,10 @@ size_t* _cursor; ChunkArray* _survivor_plab_array; + // A bounded minimum size of PLABs, should not return too small values since + // this will affect the size of the data structures used for parallel young gen rescan + size_t plab_sample_minimum_size(); + // Support for marking stack overflow handling bool take_from_overflow_list(size_t num, CMSMarkStack* to_stack); bool par_take_from_overflow_list(size_t num, diff -r 8538a606a105 -r c2844108a708 src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp --- a/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Thu Oct 23 12:02:08 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,13 @@ // active field set to true. PtrQueue(qset_, perm, true /* active */) { } + // Flush before destroying; queue may be used to capture pending work while + // doing something else, with auto-flush on completion. + ~DirtyCardQueue() { if (!is_permanent()) flush(); } + + // Process queue entries and release resources. + void flush() { flush_impl(); } + // Apply the closure to all elements, and reset the index to make the // buffer empty. If a closure application returns "false", return // "false" immediately, halting the iteration. If "consume" is true, diff -r 8538a606a105 -r c2844108a708 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp diff -r 8538a606a105 -r c2844108a708 src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp diff -r 8538a606a105 -r c2844108a708 src/share/vm/gc_implementation/g1/ptrQueue.cpp --- a/src/share/vm/gc_implementation/g1/ptrQueue.cpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.cpp Thu Oct 23 12:02:08 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,11 +31,15 @@ #include "runtime/thread.inline.hpp" PtrQueue::PtrQueue(PtrQueueSet* qset, bool perm, bool active) : - _qset(qset), _buf(NULL), _index(0), _active(active), + _qset(qset), _buf(NULL), _index(0), _sz(0), _active(active), _perm(perm), _lock(NULL) {} -void PtrQueue::flush() { +PtrQueue::~PtrQueue() { + assert(_perm || (_buf == NULL), "queue must be flushed before delete"); +} + +void PtrQueue::flush_impl() { if (!_perm && _buf != NULL) { if (_index == _sz) { // No work to do. diff -r 8538a606a105 -r c2844108a708 src/share/vm/gc_implementation/g1/ptrQueue.hpp --- a/src/share/vm/gc_implementation/g1/ptrQueue.hpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.hpp Thu Oct 23 12:02:08 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,15 +65,18 @@ Mutex* _lock; PtrQueueSet* qset() { return _qset; } + bool is_permanent() const { return _perm; } + + // Process queue entries and release resources, if not permanent. + void flush_impl(); public: // Initialize this queue to contain a null buffer, and be part of the // given PtrQueueSet. PtrQueue(PtrQueueSet* qset, bool perm = false, bool active = false); - // Release any contained resources. - virtual void flush(); - // Calls flush() when destroyed. - ~PtrQueue() { flush(); } + + // Requires queue flushed or permanent. + ~PtrQueue(); // Associate a lock with a ptr queue. void set_lock(Mutex* lock) { _lock = lock; } diff -r 8538a606a105 -r c2844108a708 src/share/vm/gc_implementation/g1/satbQueue.cpp --- a/src/share/vm/gc_implementation/g1/satbQueue.cpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/satbQueue.cpp Thu Oct 23 12:02:08 2014 -0700 @@ -39,7 +39,7 @@ // first before we flush it, otherwise we might end up with an // enqueued buffer with refs into the CSet which breaks our invariants. filter(); - PtrQueue::flush(); + flush_impl(); } // This method removes entries from an SATB buffer that will not be diff -r 8538a606a105 -r c2844108a708 src/share/vm/gc_implementation/g1/satbQueue.hpp --- a/src/share/vm/gc_implementation/g1/satbQueue.hpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/satbQueue.hpp Thu Oct 23 12:02:08 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,9 +60,8 @@ // field to true. This is done in JavaThread::initialize_queues(). PtrQueue(qset, perm, false /* active */) { } - // Overrides PtrQueue::flush() so that it can filter the buffer - // before it is flushed. - virtual void flush(); + // Process queue entries and free resources. + void flush(); // Overrides PtrQueue::should_enqueue_buffer(). See the method's // definition for more information. diff -r 8538a606a105 -r c2844108a708 src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp --- a/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp Thu Oct 23 12:02:08 2014 -0700 @@ -63,7 +63,8 @@ virtual ~ParGCAllocBuffer() {} static const size_t min_size() { - return ThreadLocalAllocBuffer::min_size(); + // Make sure that we return something that is larger than AlignmentReserve + return align_object_size(MAX2(MinTLABSize / HeapWordSize, (uintx)oopDesc::header_size())) + AlignmentReserve; } static const size_t max_size() { diff -r 8538a606a105 -r c2844108a708 src/share/vm/memory/referenceProcessor.cpp --- a/src/share/vm/memory/referenceProcessor.cpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/memory/referenceProcessor.cpp Thu Oct 23 12:02:08 2014 -0700 @@ -118,6 +118,7 @@ _discoveredWeakRefs = &_discoveredSoftRefs[_max_num_q]; _discoveredFinalRefs = &_discoveredWeakRefs[_max_num_q]; _discoveredPhantomRefs = &_discoveredFinalRefs[_max_num_q]; + _discoveredCleanerRefs = &_discoveredPhantomRefs[_max_num_q]; // Initialize all entries to NULL for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { @@ -246,6 +247,13 @@ phantom_count = process_discovered_reflist(_discoveredPhantomRefs, NULL, false, is_alive, keep_alive, complete_gc, task_executor); + + // Process cleaners, but include them in phantom statistics. We expect + // Cleaner references to be temporary, and don't want to deal with + // possible incompatibilities arising from making it more visible. + phantom_count += + process_discovered_reflist(_discoveredCleanerRefs, NULL, false, + is_alive, keep_alive, complete_gc, task_executor); } // Weak global JNI references. It would make more sense (semantically) to @@ -883,6 +891,7 @@ balance_queues(_discoveredWeakRefs); balance_queues(_discoveredFinalRefs); balance_queues(_discoveredPhantomRefs); + balance_queues(_discoveredCleanerRefs); } size_t @@ -1042,6 +1051,9 @@ case REF_PHANTOM: list = &_discoveredPhantomRefs[id]; break; + case REF_CLEANER: + list = &_discoveredCleanerRefs[id]; + break; case REF_NONE: // we should not reach here if we are an InstanceRefKlass default: @@ -1307,6 +1319,17 @@ preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive, keep_alive, complete_gc, yield); } + + // Cleaner references. Included in timing for phantom references. We + // expect Cleaner references to be temporary, and don't want to deal with + // possible incompatibilities arising from making it more visible. + for (uint i = 0; i < _max_num_q; i++) { + if (yield->should_return()) { + return; + } + preclean_discovered_reflist(_discoveredCleanerRefs[i], is_alive, + keep_alive, complete_gc, yield); + } } } @@ -1375,6 +1398,7 @@ case 1: return "WeakRef"; case 2: return "FinalRef"; case 3: return "PhantomRef"; + case 4: return "CleanerRef"; } ShouldNotReachHere(); return NULL; diff -r 8538a606a105 -r c2844108a708 src/share/vm/memory/referenceProcessor.hpp --- a/src/share/vm/memory/referenceProcessor.hpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/memory/referenceProcessor.hpp Thu Oct 23 12:02:08 2014 -0700 @@ -264,9 +264,10 @@ DiscoveredList* _discoveredWeakRefs; DiscoveredList* _discoveredFinalRefs; DiscoveredList* _discoveredPhantomRefs; + DiscoveredList* _discoveredCleanerRefs; public: - static int number_of_subclasses_of_ref() { return (REF_PHANTOM - REF_OTHER); } + static int number_of_subclasses_of_ref() { return (REF_CLEANER - REF_OTHER); } uint num_q() { return _num_q; } uint max_num_q() { return _max_num_q; } diff -r 8538a606a105 -r c2844108a708 src/share/vm/memory/referenceType.hpp --- a/src/share/vm/memory/referenceType.hpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/memory/referenceType.hpp Thu Oct 23 12:02:08 2014 -0700 @@ -35,7 +35,8 @@ REF_SOFT, // Subclass of java/lang/ref/SoftReference REF_WEAK, // Subclass of java/lang/ref/WeakReference REF_FINAL, // Subclass of java/lang/ref/FinalReference - REF_PHANTOM // Subclass of java/lang/ref/PhantomReference + REF_PHANTOM, // Subclass of java/lang/ref/PhantomReference + REF_CLEANER // Subclass of sun/misc/Cleaner }; #endif // SHARE_VM_MEMORY_REFRERENCETYPE_HPP diff -r 8538a606a105 -r c2844108a708 src/share/vm/memory/threadLocalAllocBuffer.cpp --- a/src/share/vm/memory/threadLocalAllocBuffer.cpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/memory/threadLocalAllocBuffer.cpp Thu Oct 23 12:02:08 2014 -0700 @@ -235,22 +235,19 @@ } size_t ThreadLocalAllocBuffer::initial_desired_size() { - size_t init_sz; + size_t init_sz = 0; if (TLABSize > 0) { - init_sz = MIN2(TLABSize / HeapWordSize, max_size()); - } else if (global_stats() == NULL) { - // Startup issue - main thread initialized before heap initialized. - init_sz = min_size(); - } else { + init_sz = TLABSize / HeapWordSize; + } else if (global_stats() != NULL) { // Initial size is a function of the average number of allocating threads. unsigned nof_threads = global_stats()->allocating_threads_avg(); init_sz = (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize) / (nof_threads * target_refills()); init_sz = align_object_size(init_sz); - init_sz = MIN2(MAX2(init_sz, min_size()), max_size()); } + init_sz = MIN2(MAX2(init_sz, min_size()), max_size()); return init_sz; } diff -r 8538a606a105 -r c2844108a708 src/share/vm/memory/threadLocalAllocBuffer.hpp --- a/src/share/vm/memory/threadLocalAllocBuffer.hpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/memory/threadLocalAllocBuffer.hpp Thu Oct 23 12:02:08 2014 -0700 @@ -105,7 +105,7 @@ // do nothing. tlabs must be inited by initialize() calls } - static const size_t min_size() { return align_object_size(MinTLABSize / HeapWordSize); } + static const size_t min_size() { return align_object_size(MinTLABSize / HeapWordSize) + alignment_reserve(); } static const size_t max_size() { assert(_max_size != 0, "max_size not set up"); return _max_size; } static void set_max_size(size_t max_size) { _max_size = max_size; } diff -r 8538a606a105 -r c2844108a708 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/runtime/vmStructs.cpp Thu Oct 23 12:02:08 2014 -0700 @@ -671,6 +671,7 @@ static_field(SystemDictionary, WK_KLASS(WeakReference_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(FinalReference_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(PhantomReference_klass), Klass*) \ + static_field(SystemDictionary, WK_KLASS(Cleaner_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(Finalizer_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(Thread_klass), Klass*) \ static_field(SystemDictionary, WK_KLASS(ThreadGroup_klass), Klass*) \ diff -r 8538a606a105 -r c2844108a708 src/share/vm/utilities/defaultStream.hpp --- a/src/share/vm/utilities/defaultStream.hpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/utilities/defaultStream.hpp Thu Oct 23 12:02:08 2014 -0700 @@ -41,6 +41,8 @@ void init(); void init_log(); + fileStream* open_file(const char* log_name); + void start_log(); void finish_log(); void finish_log_on_error(char *buf, int buflen); public: diff -r 8538a606a105 -r c2844108a708 src/share/vm/utilities/ostream.cpp --- a/src/share/vm/utilities/ostream.cpp Wed Oct 22 11:18:17 2014 -0700 +++ b/src/share/vm/utilities/ostream.cpp Thu Oct 23 12:02:08 2014 -0700 @@ -370,7 +370,6 @@ #define EXTRACHARLEN 32 #define CURRENTAPPX ".current" -#define FILENAMEBUFLEN 1024 // convert YYYY-MM-DD HH:MM:SS to YYYY-MM-DD_HH-MM-SS char* get_datetime_string(char *buf, size_t len) { os::local_time_string(buf, len); @@ -404,7 +403,6 @@ buffer_length = strlen(log_name) + 1; } - // const char* star = strchr(basename, '*'); const char* pts = strstr(basename, "%p"); int pid_pos = (pts == NULL) ? -1 : (pts - nametail); @@ -419,6 +417,11 @@ buffer_length += strlen(tms); } + // File name is too long. + if (buffer_length > JVM_MAXPATHLEN) { + return NULL; + } + // Create big enough buffer. char *buf = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal); @@ -492,46 +495,88 @@ void test_loggc_filename() { int pid; char tms[32]; - char i_result[FILENAMEBUFLEN]; + char i_result[JVM_MAXPATHLEN]; const char* o_result; get_datetime_string(tms, sizeof(tms)); pid = os::current_process_id(); // test.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test.log", tms); + jio_snprintf(i_result, JVM_MAXPATHLEN, "test.log", tms); o_result = make_log_name_internal("test.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // test-%t-%p.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test-%s-pid%u.log", tms, pid); + jio_snprintf(i_result, JVM_MAXPATHLEN, "test-%s-pid%u.log", tms, pid); o_result = make_log_name_internal("test-%t-%p.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t-%%p.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // test-%t%p.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test-%spid%u.log", tms, pid); + jio_snprintf(i_result, JVM_MAXPATHLEN, "test-%spid%u.log", tms, pid); o_result = make_log_name_internal("test-%t%p.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t%%p.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // %p%t.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "pid%u%s.log", pid, tms); + jio_snprintf(i_result, JVM_MAXPATHLEN, "pid%u%s.log", pid, tms); o_result = make_log_name_internal("%p%t.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p%%t.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // %p-test.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "pid%u-test.log", pid); + jio_snprintf(i_result, JVM_MAXPATHLEN, "pid%u-test.log", pid); o_result = make_log_name_internal("%p-test.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p-test.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); // %t.log - jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "%s.log", tms); + jio_snprintf(i_result, JVM_MAXPATHLEN, "%s.log", tms); o_result = make_log_name_internal("%t.log", NULL, pid, tms); assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%t.log\", NULL)"); FREE_C_HEAP_ARRAY(char, o_result, mtInternal); + + { + // longest filename + char longest_name[JVM_MAXPATHLEN]; + memset(longest_name, 'a', sizeof(longest_name)); + longest_name[JVM_MAXPATHLEN - 1] = '\0'; + o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); + assert(strcmp(longest_name, o_result) == 0, err_msg("longest name does not match. expected '%s' but got '%s'", longest_name, o_result)); + FREE_C_HEAP_ARRAY(char, o_result, mtInternal); + } + + { + // too long file name + char too_long_name[JVM_MAXPATHLEN + 100]; + int too_long_length = sizeof(too_long_name); + memset(too_long_name, 'a', too_long_length); + too_long_name[too_long_length - 1] = '\0'; + o_result = make_log_name_internal((const char*)&too_long_name, NULL, pid, tms); + assert(o_result == NULL, err_msg("Too long file name should return NULL, but got '%s'", o_result)); + } + + { + // too long with timestamp + char longest_name[JVM_MAXPATHLEN]; + memset(longest_name, 'a', JVM_MAXPATHLEN); + longest_name[JVM_MAXPATHLEN - 3] = '%'; + longest_name[JVM_MAXPATHLEN - 2] = 't'; + longest_name[JVM_MAXPATHLEN - 1] = '\0'; + o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); + assert(o_result == NULL, err_msg("Too long file name after timestamp expansion should return NULL, but got '%s'", o_result)); + } + + { + // too long with pid + char longest_name[JVM_MAXPATHLEN]; + memset(longest_name, 'a', JVM_MAXPATHLEN); + longest_name[JVM_MAXPATHLEN - 3] = '%'; + longest_name[JVM_MAXPATHLEN - 2] = 'p'; + longest_name[JVM_MAXPATHLEN - 1] = '\0'; + o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); + assert(o_result == NULL, err_msg("Too long file name after pid expansion should return NULL, but got '%s'", o_result)); + } } #endif // PRODUCT @@ -640,9 +685,16 @@ _bytes_written = 0L; _file_name = make_log_name(file_name, NULL); + if (_file_name == NULL) { + warning("Cannot open file %s: file name is too long.\n", file_name); + _need_close = false; + UseGCLogFileRotation = false; + return; + } + // gc log file rotation if (UseGCLogFileRotation && NumberOfGCLogFiles > 1) { - char tempbuf[FILENAMEBUFLEN]; + char tempbuf[JVM_MAXPATHLEN]; jio_snprintf(tempbuf, sizeof(tempbuf), "%s.%d" CURRENTAPPX, _file_name, _cur_file_num); _file = fopen(tempbuf, "w"); } else { @@ -674,10 +726,10 @@ // concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log // must be synchronized. void gcLogFileStream::rotate_log(bool force, outputStream* out) { - char time_msg[FILENAMEBUFLEN]; + char time_msg[O_BUFLEN]; char time_str[EXTRACHARLEN]; - char current_file_name[FILENAMEBUFLEN]; - char renamed_file_name[FILENAMEBUFLEN]; + char current_file_name[JVM_MAXPATHLEN]; + char renamed_file_name[JVM_MAXPATHLEN]; if (!should_rotate(force)) { return; @@ -716,12 +768,15 @@ // have a form of extended_filename..current where i is the current rotation // file number. After it reaches max file size, the file will be saved and renamed // with .current removed from its tail. - size_t filename_len = strlen(_file_name); if (_file != NULL) { - jio_snprintf(renamed_file_name, filename_len + EXTRACHARLEN, "%s.%d", + jio_snprintf(renamed_file_name, JVM_MAXPATHLEN, "%s.%d", _file_name, _cur_file_num); - jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX, - _file_name, _cur_file_num); + int result = jio_snprintf(current_file_name, JVM_MAXPATHLEN, + "%s.%d" CURRENTAPPX, _file_name, _cur_file_num); + if (result >= JVM_MAXPATHLEN) { + warning("Cannot create new log file name: %s: file name is too long.\n", current_file_name); + return; + } const char* msg = force ? "GC log rotation request has been received." : "GC log file has reached the maximum size."; @@ -760,19 +815,23 @@ _cur_file_num++; if (_cur_file_num > NumberOfGCLogFiles - 1) _cur_file_num = 0; - jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX, + int result = jio_snprintf(current_file_name, JVM_MAXPATHLEN, "%s.%d" CURRENTAPPX, _file_name, _cur_file_num); + if (result >= JVM_MAXPATHLEN) { + warning("Cannot create new log file name: %s: file name is too long.\n", current_file_name); + return; + } + _file = fopen(current_file_name, "w"); if (_file != NULL) { _bytes_written = 0L; _need_close = true; // reuse current_file_name for time_msg - jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, + jio_snprintf(current_file_name, JVM_MAXPATHLEN, "%s.%d", _file_name, _cur_file_num); jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file created %s\n", - os::local_time_string((char *)time_str, sizeof(time_str)), - current_file_name); + os::local_time_string((char *)time_str, sizeof(time_str)), current_file_name); write(time_msg, strlen(time_msg)); if (out != NULL) { @@ -820,32 +879,64 @@ return _log_file != NULL; } +fileStream* defaultStream::open_file(const char* log_name) { + const char* try_name = make_log_name(log_name, NULL); + if (try_name == NULL) { + warning("Cannot open file %s: file name is too long.\n", log_name); + return NULL; + } + + fileStream* file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); + FREE_C_HEAP_ARRAY(char, try_name, mtInternal); + if (file->is_open()) { + return file; + } + + // Try again to open the file in the temp directory. + delete file; + char warnbuf[O_BUFLEN*2]; + jio_snprintf(warnbuf, sizeof(warnbuf), "Warning: Cannot open log file: %s\n", log_name); + // Note: This feature is for maintainer use only. No need for L10N. + jio_print(warnbuf); + try_name = make_log_name(log_name, os::get_temp_directory()); + if (try_name == NULL) { + warning("Cannot open file %s: file name is too long for directory %s.\n", log_name, os::get_temp_directory()); + return NULL; + } + + jio_snprintf(warnbuf, sizeof(warnbuf), + "Warning: Forcing option -XX:LogFile=%s\n", try_name); + jio_print(warnbuf); + + file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); + FREE_C_HEAP_ARRAY(char, try_name, mtInternal); + if (file->is_open()) { + return file; + } + + delete file; + return NULL; +} + void defaultStream::init_log() { // %%% Need a MutexLocker? const char* log_name = LogFile != NULL ? LogFile : "hotspot_%p.log"; - const char* try_name = make_log_name(log_name, NULL); - fileStream* file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); - if (!file->is_open()) { - // Try again to open the file. - char warnbuf[O_BUFLEN*2]; - jio_snprintf(warnbuf, sizeof(warnbuf), - "Warning: Cannot open log file: %s\n", try_name); - // Note: This feature is for maintainer use only. No need for L10N. - jio_print(warnbuf); - FREE_C_HEAP_ARRAY(char, try_name, mtInternal); - try_name = make_log_name(log_name, os::get_temp_directory()); - jio_snprintf(warnbuf, sizeof(warnbuf), - "Warning: Forcing option -XX:LogFile=%s\n", try_name); - jio_print(warnbuf); - delete file; - file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); + fileStream* file = open_file(log_name); + + if (file != NULL) { + _log_file = file; + _outer_xmlStream = new(ResourceObj::C_HEAP, mtInternal) xmlStream(file); + start_log(); + } else { + // and leave xtty as NULL + LogVMOutput = false; + DisplayVMOutput = true; + LogCompilation = false; } - FREE_C_HEAP_ARRAY(char, try_name, mtInternal); +} - if (file->is_open()) { - _log_file = file; - xmlStream* xs = new(ResourceObj::C_HEAP, mtInternal) xmlStream(file); - _outer_xmlStream = xs; +void defaultStream::start_log() { + xmlStream*xs = _outer_xmlStream; if (this == tty) xtty = xs; // Write XML header. xs->print_cr(""); @@ -900,13 +991,6 @@ xs->head("tty"); // All further non-markup text gets copied to the tty: xs->_text = this; // requires friend declaration! - } else { - delete(file); - // and leave xtty as NULL - LogVMOutput = false; - DisplayVMOutput = true; - LogCompilation = false; - } } // finish_log() is called during normal VM shutdown. finish_log_on_error() is