# HG changeset patch # User jwilhelm # Date 1547668389 -3600 # Node ID 58e25974ede4522bdfe5c26077e4e77872c0435c # Parent a47b8125b7cc9ef59619745c163975fe935b57ed# Parent cb4212fda8e41d2df4d1814c4606217c2e0acd21 Merge diff -r a47b8125b7cc -r 58e25974ede4 src/hotspot/share/code/codeHeapState.cpp --- a/src/hotspot/share/code/codeHeapState.cpp Wed Jan 16 19:09:16 2019 +0000 +++ b/src/hotspot/share/code/codeHeapState.cpp Wed Jan 16 20:53:09 2019 +0100 @@ -1,6 +1,6 @@ /* * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2018 SAP SE. All rights reserved. + * Copyright (c) 2018, 2019 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 @@ -40,15 +40,17 @@ // contain enough detail to gain initial insight while keeping the // internal structure sizes in check. // -// The CodeHeap is a living thing. Therefore, the aggregate is collected -// under the CodeCache_lock. The subsequent print steps are only locked -// against concurrent aggregations. That keeps the impact on -// "normal operation" (JIT compiler and sweeper activity) to a minimum. -// // The second part, which consists of several, independent steps, // prints the previously collected information with emphasis on // various aspects. // +// The CodeHeap is a living thing. Therefore, protection against concurrent +// modification (by acquiring the CodeCache_lock) is necessary. It has +// to be provided by the caller of the analysis functions. +// If the CodeCache_lock is not held, the analysis functions may print +// less detailed information or may just do nothing. It is by intention +// that an unprotected invocation is not abnormally terminated. +// // Data collection and printing is done on an "on request" basis. // While no request is being processed, there is no impact on performance. // The CodeHeap state analytics do have some memory footprint. @@ -456,7 +458,7 @@ bool done = false; const int min_granules = 256; const int max_granules = 512*K; // limits analyzable CodeHeap (with segment_granules) to 32M..128M - // results in StatArray size of 20M (= max_granules * 40 Bytes per element) + // results in StatArray size of 24M (= max_granules * 48 Bytes per element) // For a 1GB CodeHeap, the granule size must be at least 2kB to not violate the max_granles limit. const char* heapName = get_heapName(heap); STRINGSTREAM_DECL(ast, out) @@ -495,6 +497,12 @@ return; } + if (!CodeCache_lock->owned_by_self()) { + printBox(ast, '-', "aggregate function called without holding the CodeCache_lock for ", heapName); + STRINGSTREAM_FLUSH("") + return; + } + // Calculate granularity of analysis (and output). // The CodeHeap is managed (allocated) in segments (units) of CodeCacheSegmentSize. // The CodeHeap can become fairly large, in particular in productive real-life systems. @@ -1028,6 +1036,7 @@ STRINGSTREAM_FLUSH("\n") // This loop is intentionally printing directly to "out". + // It should not print anything, anyway. out->print("Verifying collected data..."); size_t granule_segs = granule_size>>log2_seg_size; for (unsigned int ix = 0; ix < granules; ix++) { @@ -1071,6 +1080,7 @@ } // This loop is intentionally printing directly to "out". + // It should not print anything, anyway. if (used_topSizeBlocks > 0) { unsigned int j = 0; if (TopSizeArray[0].len != currMax) { @@ -1166,6 +1176,7 @@ //---< calculate and fill remaining fields >--- if (FreeArray != NULL) { // This loop is intentionally printing directly to "out". + // It should not print anything, anyway. for (unsigned int ix = 0; ix < alloc_freeBlocks-1; ix++) { size_t lenSum = 0; FreeArray[ix].gap = (unsigned int)((address)FreeArray[ix+1].start - ((address)FreeArray[ix].start + FreeArray[ix].len)); @@ -1223,6 +1234,7 @@ //---------------------------- { char* low_bound = heap->low_boundary(); + bool have_CodeCache_lock = CodeCache_lock->owned_by_self(); printBox(ast, '-', "Largest Used Blocks in ", heapName); print_blobType_legend(ast); @@ -1241,12 +1253,19 @@ unsigned int printed_topSizeBlocks = 0; for (unsigned int i = 0; i != tsbStopper; i = TopSizeArray[i].index) { printed_topSizeBlocks++; - CodeBlob* this_blob = (CodeBlob*)(heap->find_start(TopSizeArray[i].start)); nmethod* nm = NULL; - const char* blob_name = "unnamed blob"; - if (this_blob != NULL) { - blob_name = this_blob->name(); - nm = this_blob->as_nmethod_or_null(); + const char* blob_name = "unnamed blob or blob name unavailable"; + // heap->find_start() is safe. Only works on _segmap. + // Returns NULL or void*. Returned CodeBlob may be uninitialized. + HeapBlock* heapBlock = TopSizeArray[i].start; + CodeBlob* this_blob = (CodeBlob*)(heap->find_start(heapBlock)); + bool blob_is_safe = blob_access_is_safe(this_blob, NULL); + if (blob_is_safe) { + //---< access these fields only if we own the CodeCache_lock >--- + if (have_CodeCache_lock) { + blob_name = this_blob->name(); + nm = this_blob->as_nmethod_or_null(); + } //---< blob address >--- ast->print(INTPTR_FORMAT, p2i(this_blob)); ast->fill_to(19); @@ -1262,10 +1281,18 @@ ast->fill_to(33); } - //---< print size, name, and signature (for nMethods) >--- - if ((nm != NULL) && (nm->method() != NULL)) { + // access nmethod and Method fields only if we own the CodeCache_lock. + // This fact is implicitly transported via nm != NULL. + if (CompiledMethod::nmethod_access_is_safe(nm)) { ResourceMark rm; + Method* method = nm->method(); + if (nm->is_in_use()) { + blob_name = method->name_and_sig_as_C_string(); + } + if (nm->is_not_entrant()) { + blob_name = method->name_and_sig_as_C_string(); + } //---< nMethod size in hex >--- unsigned int total_size = nm->total_size(); ast->print(PTR32_FORMAT, total_size); @@ -1280,10 +1307,12 @@ ast->print("%5d", nm->hotness_counter()); //---< name and signature >--- ast->fill_to(67+6); - if (nm->is_in_use()) {blob_name = nm->method()->name_and_sig_as_C_string(); } - if (nm->is_not_entrant()) {blob_name = nm->method()->name_and_sig_as_C_string(); } - if (nm->is_not_installed()) {ast->print("%s", " not (yet) installed method "); } - if (nm->is_zombie()) {ast->print("%s", " zombie method "); } + if (nm->is_not_installed()) { + ast->print(" not (yet) installed method "); + } + if (nm->is_zombie()) { + ast->print(" zombie method "); + } ast->print("%s", blob_name); } else { //---< block size in hex >--- @@ -2083,10 +2112,11 @@ } STRINGSTREAM_DECL(ast, out) - unsigned int granules_per_line = 128; - char* low_bound = heap->low_boundary(); - CodeBlob* last_blob = NULL; - bool name_in_addr_range = true; + unsigned int granules_per_line = 128; + char* low_bound = heap->low_boundary(); + CodeBlob* last_blob = NULL; + bool name_in_addr_range = true; + bool have_CodeCache_lock = CodeCache_lock->owned_by_self(); //---< print at least 128K per block (i.e. between headers) >--- if (granules_per_line*granule_size < 128*K) { @@ -2121,16 +2151,14 @@ StatArray[ix].stub_count + StatArray[ix].dead_count; if (nBlobs > 0 ) { for (unsigned int is = 0; is < granule_size; is+=(unsigned int)seg_size) { - // heap->find_start() is safe. Only working with _segmap. Returns NULL or void*. Returned CodeBlob may be uninitialized. - CodeBlob* this_blob = (CodeBlob *)(heap->find_start(low_bound+ix*granule_size+is)); - bool blob_initialized = (this_blob != NULL) && (this_blob->header_size() >= 0) && (this_blob->relocation_size() >= 0) && - ((address)this_blob + this_blob->header_size() == (address)(this_blob->relocation_begin())) && - ((address)this_blob + CodeBlob::align_code_offset(this_blob->header_size() + this_blob->relocation_size()) == (address)(this_blob->content_begin())) && - os::is_readable_pointer((address)(this_blob->relocation_begin())) && - os::is_readable_pointer(this_blob->content_begin()); + // heap->find_start() is safe. Only works on _segmap. + // Returns NULL or void*. Returned CodeBlob may be uninitialized. + char* this_seg = low_bound + ix*granule_size + is; + CodeBlob* this_blob = (CodeBlob*)(heap->find_start(this_seg)); + bool blob_is_safe = blob_access_is_safe(this_blob, NULL); // blob could have been flushed, freed, and merged. // this_blob < last_blob is an indicator for that. - if (blob_initialized && (this_blob > last_blob)) { + if (blob_is_safe && (this_blob > last_blob)) { last_blob = this_blob; //---< get type and name >--- @@ -2138,12 +2166,22 @@ if (segment_granules) { cbType = (blobType)StatArray[ix].type; } else { - cbType = get_cbType(this_blob); + //---< access these fields only if we own the CodeCache_lock >--- + if (have_CodeCache_lock) { + cbType = get_cbType(this_blob); + } } - // this_blob->name() could return NULL if no name was given to CTOR. Inlined, maybe invisible on stack - const char* blob_name = this_blob->name(); - if ((blob_name == NULL) || !os::is_readable_pointer(blob_name)) { - blob_name = ""; + + //---< access these fields only if we own the CodeCache_lock >--- + const char* blob_name = ""; + nmethod* nm = NULL; + if (have_CodeCache_lock) { + blob_name = this_blob->name(); + nm = this_blob->as_nmethod_or_null(); + // this_blob->name() could return NULL if no name was given to CTOR. Inlined, maybe invisible on stack + if ((blob_name == NULL) || !os::is_readable_pointer(blob_name)) { + blob_name = ""; + } } //---< print table header for new print range >--- @@ -2163,8 +2201,8 @@ ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound)); ast->fill_to(33); - // this_blob->as_nmethod_or_null() is safe. Inlined, maybe invisible on stack. - nmethod* nm = this_blob->as_nmethod_or_null(); + // access nmethod and Method fields only if we own the CodeCache_lock. + // This fact is implicitly transported via nm != NULL. if (CompiledMethod::nmethod_access_is_safe(nm)) { Method* method = nm->method(); ResourceMark rm; @@ -2201,14 +2239,17 @@ } else { ast->print("%s", blob_name); } - } else { + } else if (blob_is_safe) { ast->fill_to(62+6); ast->print("%s", blobTypeName[cbType]); ast->fill_to(82+6); ast->print("%s", blob_name); + } else { + ast->fill_to(62+6); + ast->print(""); } STRINGSTREAM_FLUSH_LOCKED("\n") - } else if (!blob_initialized && (this_blob != last_blob) && (this_blob != NULL)) { + } else if (!blob_is_safe && (this_blob != last_blob) && (this_blob != NULL)) { last_blob = this_blob; STRINGSTREAM_FLUSH_LOCKED("\n") } @@ -2375,16 +2416,31 @@ if (cb->is_method_handles_adapter_blob()) return mh_adapterBlob; if (cb->is_buffer_blob()) return bufferBlob; - nmethod* nm = cb->as_nmethod_or_null(); - if (nm != NULL) { // no is_readable check required, nm = (nmethod*)cb. - if (nm->is_not_installed()) return nMethod_inconstruction; - if (nm->is_zombie()) return nMethod_dead; - if (nm->is_unloaded()) return nMethod_unloaded; - if (nm->is_in_use()) return nMethod_inuse; - if (nm->is_alive() && !(nm->is_not_entrant())) return nMethod_notused; - if (nm->is_alive()) return nMethod_alive; - return nMethod_dead; + //---< access these fields only if we own the CodeCache_lock >--- + // Should be ensured by caller. aggregate() amd print_names() do that. + if (CodeCache_lock->owned_by_self()) { + nmethod* nm = cb->as_nmethod_or_null(); + if (nm != NULL) { // no is_readable check required, nm = (nmethod*)cb. + if (nm->is_not_installed()) return nMethod_inconstruction; + if (nm->is_zombie()) return nMethod_dead; + if (nm->is_unloaded()) return nMethod_unloaded; + if (nm->is_in_use()) return nMethod_inuse; + if (nm->is_alive() && !(nm->is_not_entrant())) return nMethod_notused; + if (nm->is_alive()) return nMethod_alive; + return nMethod_dead; + } } } return noType; } + +bool CodeHeapState::blob_access_is_safe(CodeBlob* this_blob, CodeBlob* prev_blob) { + return (this_blob != NULL) && // a blob must have been found, obviously + ((this_blob == prev_blob) || (prev_blob == NULL)) && // when re-checking, the same blob must have been found + (this_blob->header_size() >= 0) && + (this_blob->relocation_size() >= 0) && + ((address)this_blob + this_blob->header_size() == (address)(this_blob->relocation_begin())) && + ((address)this_blob + CodeBlob::align_code_offset(this_blob->header_size() + this_blob->relocation_size()) == (address)(this_blob->content_begin())) && + os::is_readable_pointer((address)(this_blob->relocation_begin())) && + os::is_readable_pointer(this_blob->content_begin()); +} diff -r a47b8125b7cc -r 58e25974ede4 src/hotspot/share/code/codeHeapState.hpp --- a/src/hotspot/share/code/codeHeapState.hpp Wed Jan 16 19:09:16 2019 +0000 +++ b/src/hotspot/share/code/codeHeapState.hpp Wed Jan 16 20:53:09 2019 +0100 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2018 SAP SE. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019 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 @@ -95,6 +95,7 @@ static void print_line_delim(outputStream* out, bufferedStream *sst, char* low_bound, unsigned int ix, unsigned int gpl); static void print_line_delim(outputStream* out, outputStream *sst, char* low_bound, unsigned int ix, unsigned int gpl); static blobType get_cbType(CodeBlob* cb); + static bool blob_access_is_safe(CodeBlob* this_blob, CodeBlob* prev_blob); public: static void discard(outputStream* out, CodeHeap* heap); diff -r a47b8125b7cc -r 58e25974ede4 src/hotspot/share/compiler/compileBroker.cpp --- a/src/hotspot/share/compiler/compileBroker.cpp Wed Jan 16 19:09:16 2019 +0000 +++ b/src/hotspot/share/compiler/compileBroker.cpp Wed Jan 16 20:53:09 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2672,6 +2672,7 @@ // preventing concurrently printing threads from stalling a long time. void CompileBroker::print_heapinfo(outputStream* out, const char* function, const char* granularity) { TimeStamp ts_total; + TimeStamp ts_global; TimeStamp ts; bool allFun = !strcmp(function, "all"); @@ -2701,35 +2702,43 @@ } // We hold the CodeHeapStateAnalytics_lock all the time, from here until we leave this function. - // That helps us getting a consistent view on the CodeHeap, at least for the "all" function. + // That prevents another thread from destroying our view on the CodeHeap. // When we request individual parts of the analysis via the jcmd interface, it is possible // that in between another thread (another jcmd user or the vm running into CodeCache OOM) // updated the aggregated data. That's a tolerable tradeoff because we can't hold a lock // across user interaction. + // Acquire this lock before acquiring the CodeCache_lock. + // CodeHeapStateAnalytics_lock could be held by a concurrent thread for a long time, + // leading to an unnecessarily long hold time of the CodeCache_lock. ts.update(); // record starting point MutexLockerEx mu1(CodeHeapStateAnalytics_lock, Mutex::_no_safepoint_check_flag); - out->cr(); - out->print_cr("__ CodeHeapStateAnalytics lock wait took %10.3f seconds _________", ts.seconds()); - out->cr(); + out->print_cr("\n__ CodeHeapStateAnalytics lock wait took %10.3f seconds _________\n", ts.seconds()); + + // If we serve an "allFun" call, it is beneficial to hold the CodeCache_lock + // for the entire duration of aggregation and printing. That makes sure + // we see a consistent picture and do not run into issues caused by + // the CodeHeap being altered concurrently. + Monitor* global_lock = allFun ? CodeCache_lock : NULL; + Monitor* function_lock = allFun ? NULL : CodeCache_lock; + ts_global.update(); // record starting point + MutexLockerEx mu2(global_lock, Mutex::_no_safepoint_check_flag); + if (global_lock != NULL) { + out->print_cr("\n__ CodeCache (global) lock wait took %10.3f seconds _________\n", ts_global.seconds()); + ts_global.update(); // record starting point + } if (aggregate) { - // It is sufficient to hold the CodeCache_lock only for the aggregate step. - // All other functions operate on aggregated data - except MethodNames, but that should be safe. - // The separate CodeHeapStateAnalytics_lock protects the printing functions against - // concurrent aggregate steps. Acquire this lock before acquiring the CodeCache_lock. - // CodeHeapStateAnalytics_lock could be held by a concurrent thread for a long time, - // leading to an unnecessarily long hold time of the CodeCache_lock. ts.update(); // record starting point - MutexLockerEx mu2(CodeCache_lock, Mutex::_no_safepoint_check_flag); - out->cr(); - out->print_cr("__ CodeCache lock wait took %10.3f seconds _________", ts.seconds()); - out->cr(); + MutexLockerEx mu3(function_lock, Mutex::_no_safepoint_check_flag); + if (function_lock != NULL) { + out->print_cr("\n__ CodeCache (function) lock wait took %10.3f seconds _________\n", ts.seconds()); + } ts.update(); // record starting point CodeCache::aggregate(out, granularity); - out->cr(); - out->print_cr("__ CodeCache lock hold took %10.3f seconds _________", ts.seconds()); - out->cr(); + if (function_lock != NULL) { + out->print_cr("\n__ CodeCache (function) lock hold took %10.3f seconds _________\n", ts.seconds()); + } } if (usedSpace) CodeCache::print_usedSpace(out); @@ -2737,10 +2746,16 @@ if (methodCount) CodeCache::print_count(out); if (methodSpace) CodeCache::print_space(out); if (methodAge) CodeCache::print_age(out); - if (methodNames) CodeCache::print_names(out); + if (methodNames) { + // print_names() has shown to be sensitive to concurrent CodeHeap modifications. + // Therefore, request the CodeCache_lock before calling... + MutexLockerEx mu3(function_lock, Mutex::_no_safepoint_check_flag); + CodeCache::print_names(out); + } if (discard) CodeCache::discard(out); - out->cr(); - out->print_cr("__ CodeHeapStateAnalytics total duration %10.3f seconds _________", ts_total.seconds()); - out->cr(); + if (global_lock != NULL) { + out->print_cr("\n__ CodeCache (global) lock hold took %10.3f seconds _________\n", ts_global.seconds()); + } + out->print_cr("\n__ CodeHeapStateAnalytics total duration %10.3f seconds _________\n", ts_total.seconds()); } diff -r a47b8125b7cc -r 58e25974ede4 src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp --- a/src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp Wed Jan 16 19:09:16 2019 +0000 +++ b/src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp Wed Jan 16 20:53:09 2019 +0100 @@ -62,9 +62,8 @@ } // Check if enough time has passed since the last GC. - uintx time_since_last_gc; - if ((G1PeriodicGCInterval == 0) || - ((time_since_last_gc = (uintx)Universe::heap()->millis_since_last_gc()) < G1PeriodicGCInterval)) { + uintx time_since_last_gc = (uintx)Universe::heap()->millis_since_last_gc(); + if ((time_since_last_gc < G1PeriodicGCInterval)) { log_debug(gc, periodic)("Last GC occurred " UINTX_FORMAT "ms before which is below threshold " UINTX_FORMAT "ms. Skipping.", time_since_last_gc, G1PeriodicGCInterval); return false; @@ -83,6 +82,10 @@ } void G1YoungRemSetSamplingThread::check_for_periodic_gc(){ + // If disabled, just return. + if (G1PeriodicGCInterval == 0) { + return; + } if ((os::elapsedTime() - _last_periodic_gc_attempt_s) > (G1PeriodicGCInterval / 1000.0)) { log_debug(gc, periodic)("Checking for periodic GC."); if (should_start_periodic_gc()) { @@ -95,6 +98,13 @@ void G1YoungRemSetSamplingThread::run_service() { double vtime_start = os::elapsedVTime(); + // Print a message about periodic GC configuration. + if (G1PeriodicGCInterval != 0) { + log_info(gc)("Periodic GC enabled with interval " UINTX_FORMAT "ms", G1PeriodicGCInterval); + } else { + log_info(gc)("Periodic GC disabled"); + } + while (!should_terminate()) { sample_young_list_rs_lengths(); diff -r a47b8125b7cc -r 58e25974ede4 src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp Wed Jan 16 19:09:16 2019 +0000 +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp Wed Jan 16 20:53:09 2019 +0100 @@ -97,7 +97,7 @@ return false; } - if (n->is_CallJava() || n->Opcode() == Op_CallLeafNoFP) { + if (n->is_Call()) { return true; } @@ -2659,9 +2659,35 @@ wb->pin_and_expand_helper(phase); } + for (uint i = 0; i < enqueue_barriers.size(); i++) { + Node* barrier = enqueue_barriers.at(i); + Node* ctrl = phase->get_ctrl(barrier); + IdealLoopTree* loop = phase->get_loop(ctrl); + if (loop->_head->is_OuterStripMinedLoop()) { + // Expanding a barrier here will break loop strip mining + // verification. Transform the loop so the loop nest doesn't + // appear as strip mined. + OuterStripMinedLoopNode* outer = loop->_head->as_OuterStripMinedLoop(); + hide_strip_mined_loop(outer, outer->unique_ctrl_out()->as_CountedLoop(), phase); + } + } + + for (int i = ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count(); i > 0; i--) { + int cnt = ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count(); + ShenandoahWriteBarrierNode* wb = ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barrier(i-1); + Node* ctrl = phase->get_ctrl(wb); + IdealLoopTree* loop = phase->get_loop(ctrl); + if (loop->_head->is_OuterStripMinedLoop()) { + // Expanding a barrier here will break loop strip mining + // verification. Transform the loop so the loop nest doesn't + // appear as strip mined. + OuterStripMinedLoopNode* outer = loop->_head->as_OuterStripMinedLoop(); + hide_strip_mined_loop(outer, outer->unique_ctrl_out()->as_CountedLoop(), phase); + } + } + MemoryGraphFixer fixer(Compile::AliasIdxRaw, true, phase); Unique_Node_List uses_to_ignore; - Unique_Node_List outer_lsms; for (uint i = 0; i < enqueue_barriers.size(); i++) { Node* barrier = enqueue_barriers.at(i); Node* pre_val = barrier->in(1); @@ -2685,9 +2711,6 @@ Node* init_ctrl = ctrl; IdealLoopTree* loop = phase->get_loop(ctrl); - if (loop->_head->is_OuterStripMinedLoop()) { - outer_lsms.push(loop->_head); - } Node* raw_mem = fixer.find_mem(ctrl, barrier); Node* init_raw_mem = raw_mem; Node* raw_mem_for_ctrl = fixer.find_mem(ctrl, NULL); @@ -2832,9 +2855,6 @@ Node* val = wb->in(ValueIn); Node* wbproj = wb->find_out_with(Op_ShenandoahWBMemProj); IdealLoopTree *loop = phase->get_loop(ctrl); - if (loop->_head->is_OuterStripMinedLoop()) { - outer_lsms.push(loop->_head); - } assert(val->Opcode() != Op_ShenandoahWriteBarrier, "No chain of write barriers"); @@ -3019,14 +3039,6 @@ } assert(ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count() == 0, "all write barrier nodes should have been replaced"); - - for (uint i = 0; i < outer_lsms.size(); i++) { - // Expanding a barrier here will break loop strip mining - // verification. Transform the loop so the loop nest doesn't - // appear as strip mined. - OuterStripMinedLoopNode* outer = outer_lsms.at(i)->as_OuterStripMinedLoop(); - hide_strip_mined_loop(outer, outer->unique_ctrl_out()->as_CountedLoop(), phase); - } } void ShenandoahWriteBarrierNode::move_heap_stable_test_out_of_loop(IfNode* iff, PhaseIdealLoop* phase) { @@ -4274,5 +4286,3 @@ _memory_nodes.map(c->_idx, mem->in(ShenandoahWBMemProjNode::WriteBarrier)->in(ShenandoahBarrierNode::Memory)); } } - - diff -r a47b8125b7cc -r 58e25974ede4 src/hotspot/share/jvmci/jvmciCompilerToVM.cpp --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Wed Jan 16 19:09:16 2019 +0000 +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Wed Jan 16 20:53:09 2019 +0100 @@ -602,6 +602,17 @@ return NULL; } + if (method->name() == vmSymbols::clone_name() && + resolved == SystemDictionary::Object_klass() && + recv_klass->is_array_klass()) { + // Resolution of the clone method on arrays always returns Object.clone even though that method + // has protected access. There's some trickery in the access checking to make this all work out + // so it's necessary to pass in the array class as the resolved class to properly trigger this. + // Otherwise it's impossible to resolve the array clone methods through JVMCI. See + // LinkResolver::check_method_accessability for the matching logic. + resolved = recv_klass; + } + LinkInfo link_info(resolved, h_name, h_signature, caller_klass); methodHandle m; // Only do exact lookup if receiver klass has been linked. Otherwise, diff -r a47b8125b7cc -r 58e25974ede4 src/hotspot/share/opto/loopPredicate.cpp --- a/src/hotspot/share/opto/loopPredicate.cpp Wed Jan 16 19:09:16 2019 +0000 +++ b/src/hotspot/share/opto/loopPredicate.cpp Wed Jan 16 20:53:09 2019 +0100 @@ -160,7 +160,7 @@ // When called from beautify_loops() idom is not constructed yet. if (_idom != NULL) { Node* ridom = idom(rgn); - Node* nrdom = dom_lca(ridom, new_iff); + Node* nrdom = dom_lca_internal(ridom, new_iff); set_idom(rgn, nrdom, dom_depth(rgn)); } diff -r a47b8125b7cc -r 58e25974ede4 src/java.base/share/classes/java/security/spec/PSSParameterSpec.java --- a/src/java.base/share/classes/java/security/spec/PSSParameterSpec.java Wed Jan 16 19:09:16 2019 +0000 +++ b/src/java.base/share/classes/java/security/spec/PSSParameterSpec.java Wed Jan 16 20:53:09 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ package java.security.spec; import java.util.Objects; -import java.security.spec.MGF1ParameterSpec; /** * This class specifies a parameter spec for RSASSA-PSS signature scheme, @@ -218,4 +217,14 @@ public int getTrailerField() { return trailerField; } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("MD: " + mdName + "\n") + .append("MGF: " + mgfSpec + "\n") + .append("SaltLength: " + saltLen + "\n") + .append("TrailerField: " + trailerField + "\n"); + return sb.toString(); + } } diff -r a47b8125b7cc -r 58e25974ede4 src/java.base/share/classes/sun/security/pkcs10/PKCS10.java --- a/src/java.base/share/classes/sun/security/pkcs10/PKCS10.java Wed Jan 16 19:09:16 2019 +0000 +++ b/src/java.base/share/classes/sun/security/pkcs10/PKCS10.java Wed Jan 16 20:53:09 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,6 @@ import java.security.cert.CertificateException; import java.security.*; -import java.security.spec.AlgorithmParameterSpec; import java.util.Base64; @@ -237,10 +236,14 @@ */ AlgorithmId algId = null; try { - algId = AlgorithmId.get(signature.getAlgorithm()); + AlgorithmParameters params = signature.getParameters(); + algId = params == null + ? AlgorithmId.get(signature.getAlgorithm()) + : AlgorithmId.get(params); } catch (NoSuchAlgorithmException nsae) { throw new SignatureException(nsae); } + algId.encode(scratch); // sig algorithm scratch.putBitString(sig); // sig diff -r a47b8125b7cc -r 58e25974ede4 src/java.base/share/classes/sun/security/rsa/PSSParameters.java --- a/src/java.base/share/classes/sun/security/rsa/PSSParameters.java Wed Jan 16 19:09:16 2019 +0000 +++ b/src/java.base/share/classes/sun/security/rsa/PSSParameters.java Wed Jan 16 20:53:09 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,13 +52,7 @@ public final class PSSParameters extends AlgorithmParametersSpi { - private String mdName; - private MGF1ParameterSpec mgfSpec; - private int saltLength; - private int trailerField; - - private static final ObjectIdentifier OID_MGF1 = - ObjectIdentifier.newInternal(new int[] {1,2,840,113549,1,1,8}); + private PSSParameterSpec spec; public PSSParameters() { } @@ -71,9 +65,9 @@ ("Inappropriate parameter specification"); } PSSParameterSpec spec = (PSSParameterSpec) paramSpec; - this.mdName = spec.getDigestAlgorithm(); + String mgfName = spec.getMGFAlgorithm(); - if (!mgfName.equalsIgnoreCase("MGF1")) { + if (!spec.getMGFAlgorithm().equalsIgnoreCase("MGF1")) { throw new InvalidParameterSpecException("Unsupported mgf " + mgfName + "; MGF1 only"); } @@ -82,31 +76,30 @@ throw new InvalidParameterSpecException("Inappropriate mgf " + "parameters; non-null MGF1ParameterSpec only"); } - this.mgfSpec = (MGF1ParameterSpec) mgfSpec; - this.saltLength = spec.getSaltLength(); - this.trailerField = spec.getTrailerField(); + this.spec = spec; } @Override protected void engineInit(byte[] encoded) throws IOException { // first initialize with the DEFAULT values before // retrieving from the encoding bytes - this.mdName = DEFAULT.getDigestAlgorithm(); - this.mgfSpec = (MGF1ParameterSpec) DEFAULT.getMGFParameters(); - this.saltLength = DEFAULT.getSaltLength(); - this.trailerField = DEFAULT.getTrailerField(); + String mdName = DEFAULT.getDigestAlgorithm(); + MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec) DEFAULT.getMGFParameters(); + int saltLength = DEFAULT.getSaltLength(); + int trailerField = DEFAULT.getTrailerField(); DerInputStream der = new DerInputStream(encoded); DerValue[] datum = der.getSequence(4); + for (DerValue d : datum) { if (d.isContextSpecific((byte) 0x00)) { // hash algid - this.mdName = AlgorithmId.parse + mdName = AlgorithmId.parse (d.data.getDerValue()).getName(); } else if (d.isContextSpecific((byte) 0x01)) { // mgf algid AlgorithmId val = AlgorithmId.parse(d.data.getDerValue()); - if (!val.getOID().equals(OID_MGF1)) { + if (!val.getOID().equals(AlgorithmId.mgf1_oid)) { throw new IOException("Only MGF1 mgf is supported"); } AlgorithmId params = AlgorithmId.parse( @@ -114,25 +107,25 @@ String mgfDigestName = params.getName(); switch (mgfDigestName) { case "SHA-1": - this.mgfSpec = MGF1ParameterSpec.SHA1; + mgfSpec = MGF1ParameterSpec.SHA1; break; case "SHA-224": - this.mgfSpec = MGF1ParameterSpec.SHA224; + mgfSpec = MGF1ParameterSpec.SHA224; break; case "SHA-256": - this.mgfSpec = MGF1ParameterSpec.SHA256; + mgfSpec = MGF1ParameterSpec.SHA256; break; case "SHA-384": - this.mgfSpec = MGF1ParameterSpec.SHA384; + mgfSpec = MGF1ParameterSpec.SHA384; break; case "SHA-512": - this.mgfSpec = MGF1ParameterSpec.SHA512; + mgfSpec = MGF1ParameterSpec.SHA512; break; case "SHA-512/224": - this.mgfSpec = MGF1ParameterSpec.SHA512_224; + mgfSpec = MGF1ParameterSpec.SHA512_224; break; case "SHA-512/256": - this.mgfSpec = MGF1ParameterSpec.SHA512_256; + mgfSpec = MGF1ParameterSpec.SHA512_256; break; default: throw new IOException @@ -141,21 +134,24 @@ } } else if (d.isContextSpecific((byte) 0x02)) { // salt length - this.saltLength = d.data.getDerValue().getInteger(); - if (this.saltLength < 0) { + saltLength = d.data.getDerValue().getInteger(); + if (saltLength < 0) { throw new IOException("Negative value for saltLength"); } } else if (d.isContextSpecific((byte) 0x03)) { // trailer field - this.trailerField = d.data.getDerValue().getInteger(); - if (this.trailerField != 1) { + trailerField = d.data.getDerValue().getInteger(); + if (trailerField != 1) { throw new IOException("Unsupported trailerField value " + - this.trailerField); + trailerField); } } else { throw new IOException("Invalid encoded PSSParameters"); } } + + this.spec = new PSSParameterSpec(mdName, "MGF1", mgfSpec, + saltLength, trailerField); } @Override @@ -173,9 +169,7 @@ T engineGetParameterSpec(Class paramSpec) throws InvalidParameterSpecException { if (PSSParameterSpec.class.isAssignableFrom(paramSpec)) { - return paramSpec.cast( - new PSSParameterSpec(mdName, "MGF1", mgfSpec, - saltLength, trailerField)); + return paramSpec.cast(spec); } else { throw new InvalidParameterSpecException ("Inappropriate parameter specification"); @@ -184,54 +178,7 @@ @Override protected byte[] engineGetEncoded() throws IOException { - DerOutputStream tmp = new DerOutputStream(); - DerOutputStream tmp2, tmp3; - - // MD - AlgorithmId mdAlgId; - try { - mdAlgId = AlgorithmId.get(mdName); - } catch (NoSuchAlgorithmException nsae) { - throw new IOException("AlgorithmId " + mdName + - " impl not found"); - } - tmp2 = new DerOutputStream(); - mdAlgId.derEncode(tmp2); - tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0), - tmp2); - - // MGF - tmp2 = new DerOutputStream(); - tmp2.putOID(OID_MGF1); - AlgorithmId mgfDigestId; - try { - mgfDigestId = AlgorithmId.get(mgfSpec.getDigestAlgorithm()); - } catch (NoSuchAlgorithmException nase) { - throw new IOException("AlgorithmId " + - mgfSpec.getDigestAlgorithm() + " impl not found"); - } - mgfDigestId.encode(tmp2); - tmp3 = new DerOutputStream(); - tmp3.write(DerValue.tag_Sequence, tmp2); - tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)1), - tmp3); - - // SaltLength - tmp2 = new DerOutputStream(); - tmp2.putInteger(saltLength); - tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)2), - tmp2); - - // TrailerField - tmp2 = new DerOutputStream(); - tmp2.putInteger(trailerField); - tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)3), - tmp2); - - // Put all together under a SEQUENCE tag - DerOutputStream out = new DerOutputStream(); - out.write(DerValue.tag_Sequence, tmp); - return out.toByteArray(); + return getEncoded(spec); } @Override @@ -245,11 +192,83 @@ @Override protected String engineToString() { - StringBuilder sb = new StringBuilder(); - sb.append("MD: " + mdName + "\n") - .append("MGF: MGF1" + mgfSpec.getDigestAlgorithm() + "\n") - .append("SaltLength: " + saltLength + "\n") - .append("TrailerField: " + trailerField + "\n"); - return sb.toString(); + return spec.toString(); + } + + /** + * Returns the encoding of a {@link PSSParameterSpec} object. This method + * is used in this class and {@link AlgorithmId}. + * + * @param spec a {@code PSSParameterSpec} object + * @return its DER encoding + * @throws IOException if the name of a MessageDigest or MaskGenAlgorithm + * is unsupported + */ + public static byte[] getEncoded(PSSParameterSpec spec) throws IOException { + + AlgorithmParameterSpec mgfSpec = spec.getMGFParameters(); + if (!(mgfSpec instanceof MGF1ParameterSpec)) { + throw new IOException("Cannot encode " + mgfSpec); + } + + MGF1ParameterSpec mgf1Spec = (MGF1ParameterSpec)mgfSpec; + + DerOutputStream tmp = new DerOutputStream(); + DerOutputStream tmp2, tmp3; + + // MD + AlgorithmId mdAlgId; + try { + mdAlgId = AlgorithmId.get(spec.getDigestAlgorithm()); + } catch (NoSuchAlgorithmException nsae) { + throw new IOException("AlgorithmId " + spec.getDigestAlgorithm() + + " impl not found"); + } + if (!mdAlgId.getOID().equals(AlgorithmId.SHA_oid)) { + tmp2 = new DerOutputStream(); + mdAlgId.derEncode(tmp2); + tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0), + tmp2); + } + + // MGF + AlgorithmId mgfDigestId; + try { + mgfDigestId = AlgorithmId.get(mgf1Spec.getDigestAlgorithm()); + } catch (NoSuchAlgorithmException nase) { + throw new IOException("AlgorithmId " + + mgf1Spec.getDigestAlgorithm() + " impl not found"); + } + + if (!mgfDigestId.getOID().equals(AlgorithmId.SHA_oid)) { + tmp2 = new DerOutputStream(); + tmp2.putOID(AlgorithmId.mgf1_oid); + mgfDigestId.encode(tmp2); + tmp3 = new DerOutputStream(); + tmp3.write(DerValue.tag_Sequence, tmp2); + tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 1), + tmp3); + } + + // SaltLength + if (spec.getSaltLength() != 20) { + tmp2 = new DerOutputStream(); + tmp2.putInteger(spec.getSaltLength()); + tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 2), + tmp2); + } + + // TrailerField + if (spec.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) { + tmp2 = new DerOutputStream(); + tmp2.putInteger(spec.getTrailerField()); + tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 3), + tmp2); + } + + // Put all together under a SEQUENCE tag + DerOutputStream out = new DerOutputStream(); + out.write(DerValue.tag_Sequence, tmp); + return out.toByteArray(); } } diff -r a47b8125b7cc -r 58e25974ede4 src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java --- a/src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java Wed Jan 16 19:09:16 2019 +0000 +++ b/src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java Wed Jan 16 20:53:09 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -220,8 +220,8 @@ public byte[] encode() { // Note: the DH public value is encoded as a big-endian integer // and padded to the left with zeros to the size of p in bytes. - byte[] encoded = publicKey.getY().toByteArray(); - int pSize = KeyUtil.getKeySize(publicKey); + byte[] encoded = Utilities.toByteArray(publicKey.getY()); + int pSize = (KeyUtil.getKeySize(publicKey) + 7) >>> 3; if (pSize > 0 && encoded.length < pSize) { byte[] buffer = new byte[pSize]; System.arraycopy(encoded, 0, diff -r a47b8125b7cc -r 58e25974ede4 src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java --- a/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java Wed Jan 16 19:09:16 2019 +0000 +++ b/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java Wed Jan 16 20:53:09 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateEncodingException; import java.security.*; +import java.security.spec.AlgorithmParameterSpec; import java.security.spec.ECGenParameterSpec; import java.security.spec.NamedParameterSpec; import java.util.Date; @@ -37,7 +38,6 @@ import sun.security.pkcs10.PKCS10; import sun.security.x509.*; - /** * Generate a pair of keys, and provide access to them. This class is * provided primarily for ease of use. @@ -282,12 +282,14 @@ new CertificateValidity(firstDate,lastDate); X509CertInfo info = new X509CertInfo(); + AlgorithmParameterSpec params = AlgorithmId + .getDefaultAlgorithmParameterSpec(sigAlg, privateKey); // Add all mandatory attributes info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber( new java.util.Random().nextInt() & 0x7fffffff)); - AlgorithmId algID = AlgorithmId.get(sigAlg); + AlgorithmId algID = AlgorithmId.getWithParameterSpec(sigAlg, params); info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algID)); info.set(X509CertInfo.SUBJECT, myname); @@ -297,13 +299,19 @@ if (ext != null) info.set(X509CertInfo.EXTENSIONS, ext); cert = new X509CertImpl(info); - cert.sign(privateKey, this.sigAlg); + cert.sign(privateKey, + params, + sigAlg, + null); return (X509Certificate)cert; } catch (IOException e) { throw new CertificateEncodingException("getSelfCert: " + e.getMessage()); + } catch (InvalidAlgorithmParameterException e2) { + throw new SignatureException( + "Unsupported PSSParameterSpec: " + e2.getMessage()); } } @@ -329,6 +337,7 @@ * @exception InvalidKeyException on key handling errors. * @exception SignatureException on signature handling errors. */ + // This method is not used inside JDK. Will not update it. public PKCS10 getCertRequest (X500Name myname) throws InvalidKeyException, SignatureException { diff -r a47b8125b7cc -r 58e25974ede4 src/java.base/share/classes/sun/security/tools/keytool/Main.java --- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java Wed Jan 16 19:09:16 2019 +0000 +++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java Wed Jan 16 20:53:09 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,6 +52,7 @@ import java.security.interfaces.ECKey; +import java.security.spec.AlgorithmParameterSpec; import java.security.spec.ECParameterSpec; import java.text.Collator; import java.text.MessageFormat; @@ -1431,14 +1432,16 @@ signature.initSign(privateKey); X509CertInfo info = new X509CertInfo(); + AlgorithmParameterSpec params = AlgorithmId + .getDefaultAlgorithmParameterSpec(sigAlgName, privateKey); + AlgorithmId algID = AlgorithmId.getWithParameterSpec(sigAlgName, params); info.set(X509CertInfo.VALIDITY, interval); info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber( new java.util.Random().nextInt() & 0x7fffffff)); info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); info.set(X509CertInfo.ALGORITHM_ID, - new CertificateAlgorithmId( - AlgorithmId.get(sigAlgName))); + new CertificateAlgorithmId(algID)); info.set(X509CertInfo.ISSUER, issuer); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); @@ -1482,7 +1485,7 @@ signerCert.getPublicKey()); info.set(X509CertInfo.EXTENSIONS, ext); X509CertImpl cert = new X509CertImpl(info); - cert.sign(privateKey, sigAlgName); + cert.sign(privateKey, params, sigAlgName, null); dumpCert(cert, out); for (Certificate ca: keyStore.getCertificateChain(alias)) { if (ca instanceof X509Certificate) { @@ -1585,6 +1588,12 @@ Signature signature = Signature.getInstance(sigAlgName); signature.initSign(privKey); + AlgorithmParameterSpec params = AlgorithmId + .getDefaultAlgorithmParameterSpec(sigAlgName, privKey); + if (params != null) { + signature.setParameter(params); + } + X500Name subject = dname == null? new X500Name(((X509Certificate)cert).getSubjectDN().toString()): new X500Name(dname); @@ -2962,7 +2971,9 @@ // other solution: We first sign the cert, then retrieve the // outer sigalg and use it to set the inner sigalg X509CertImpl newCert = new X509CertImpl(certInfo); - newCert.sign(privKey, sigAlgName); + AlgorithmParameterSpec params = AlgorithmId + .getDefaultAlgorithmParameterSpec(sigAlgName, privKey); + newCert.sign(privKey, params, sigAlgName, null); AlgorithmId sigAlgid = (AlgorithmId)newCert.get(X509CertImpl.SIG_ALG); certInfo.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, sigAlgid); @@ -2979,7 +2990,7 @@ certInfo.set(X509CertInfo.EXTENSIONS, ext); // Sign the new certificate newCert = new X509CertImpl(certInfo); - newCert.sign(privKey, sigAlgName); + newCert.sign(privKey, params, sigAlgName, null); // Store the new certificate as a single-element certificate chain keyStore.setKeyEntry(alias, privKey, diff -r a47b8125b7cc -r 58e25974ede4 src/java.base/share/classes/sun/security/x509/AlgorithmId.java --- a/src/java.base/share/classes/sun/security/x509/AlgorithmId.java Wed Jan 16 19:09:16 2019 +0000 +++ b/src/java.base/share/classes/sun/security/x509/AlgorithmId.java Wed Jan 16 20:53:09 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * 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,9 +26,14 @@ package sun.security.x509; import java.io.*; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; import java.util.*; import java.security.*; +import sun.security.rsa.PSSParameters; import sun.security.util.*; @@ -190,7 +195,12 @@ } else { bytes.putNull(); }*/ - bytes.putNull(); + if (algid.equals(RSASSA_PSS_oid)) { + // RFC 4055 3.3: when an RSASSA-PSS key does not require + // parameter validation, field is absent. + } else { + bytes.putNull(); + } } else { bytes.putDerValue(params); } @@ -689,6 +699,8 @@ oid(1, 2, 840, 113549, 1, 1, 1); public static final ObjectIdentifier RSAES_OAEP_oid = oid(1, 2, 840, 113549, 1, 1, 7); + public static final ObjectIdentifier mgf1_oid = + oid(1, 2, 840, 113549, 1, 1, 8); public static final ObjectIdentifier RSASSA_PSS_oid = oid(1, 2, 840, 113549, 1, 1, 10); @@ -1063,6 +1075,81 @@ } } + // Most commonly used PSSParameterSpec and AlgorithmId + private static class PSSParamsHolder { + + final static PSSParameterSpec PSS_256_SPEC = new PSSParameterSpec( + "SHA-256", "MGF1", + new MGF1ParameterSpec("SHA-256"), + 32, PSSParameterSpec.TRAILER_FIELD_BC); + final static PSSParameterSpec PSS_384_SPEC = new PSSParameterSpec( + "SHA-384", "MGF1", + new MGF1ParameterSpec("SHA-384"), + 48, PSSParameterSpec.TRAILER_FIELD_BC); + final static PSSParameterSpec PSS_512_SPEC = new PSSParameterSpec( + "SHA-512", "MGF1", + new MGF1ParameterSpec("SHA-512"), + 64, PSSParameterSpec.TRAILER_FIELD_BC); + + final static AlgorithmId PSS_256_ID; + final static AlgorithmId PSS_384_ID; + final static AlgorithmId PSS_512_ID; + + static { + try { + PSS_256_ID = new AlgorithmId(RSASSA_PSS_oid, + new DerValue(PSSParameters.getEncoded(PSS_256_SPEC))); + PSS_384_ID = new AlgorithmId(RSASSA_PSS_oid, + new DerValue(PSSParameters.getEncoded(PSS_384_SPEC))); + PSS_512_ID = new AlgorithmId(RSASSA_PSS_oid, + new DerValue(PSSParameters.getEncoded(PSS_512_SPEC))); + } catch (IOException e) { + throw new AssertionError("Should not happen", e); + } + } + } + + public static AlgorithmId getWithParameterSpec(String algName, + AlgorithmParameterSpec spec) throws NoSuchAlgorithmException { + + if (spec == null) { + return AlgorithmId.get(algName); + } else if (spec == PSSParamsHolder.PSS_256_SPEC) { + return PSSParamsHolder.PSS_256_ID; + } else if (spec == PSSParamsHolder.PSS_384_SPEC) { + return PSSParamsHolder.PSS_384_ID; + } else if (spec == PSSParamsHolder.PSS_512_SPEC) { + return PSSParamsHolder.PSS_512_ID; + } else { + try { + AlgorithmParameters result = + AlgorithmParameters.getInstance(algName); + result.init(spec); + return get(result); + } catch (InvalidParameterSpecException | NoSuchAlgorithmException e) { + throw new ProviderException(e); + } + } + } + + public static PSSParameterSpec getDefaultAlgorithmParameterSpec( + String sigAlg, PrivateKey k) { + if (sigAlg.equalsIgnoreCase("RSASSA-PSS")) { + switch (ifcFfcStrength(KeyUtil.getKeySize(k))) { + case "SHA256": + return PSSParamsHolder.PSS_256_SPEC; + case "SHA384": + return PSSParamsHolder.PSS_384_SPEC; + case "SHA512": + return PSSParamsHolder.PSS_512_SPEC; + default: + throw new AssertionError("Should not happen"); + } + } else { + return null; + } + } + // Values from SP800-57 part 1 rev 4 tables 2 and 3 private static String ecStrength (int bitLength) { if (bitLength >= 512) { // 256 bits of strength diff -r a47b8125b7cc -r 58e25974ede4 src/java.base/share/classes/sun/security/x509/X509CertImpl.java --- a/src/java.base/share/classes/sun/security/x509/X509CertImpl.java Wed Jan 16 19:09:16 2019 +0000 +++ b/src/java.base/share/classes/sun/security/x509/X509CertImpl.java Wed Jan 16 20:53:09 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * 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,7 +42,6 @@ import javax.security.auth.x500.X500Principal; -import java.util.Base64; import sun.security.util.*; import sun.security.provider.X509Factory; @@ -599,14 +598,10 @@ sigEngine.initSign(key); - // set parameters after Signature.initSign/initVerify call, so - // the deferred provider selection happens when the key is set - try { + if (signingParams != null) { + // set parameters after Signature.initSign/initVerify call, so + // the deferred provider selection happens when the key is set sigEngine.setParameter(signingParams); - } catch (UnsupportedOperationException e) { - // for backward compatibility, only re-throw when - // parameters is not null - if (signingParams != null) throw e; } // in case the name is reset diff -r a47b8125b7cc -r 58e25974ede4 src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Wed Jan 16 19:09:16 2019 +0000 +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java Wed Jan 16 20:53:09 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -298,8 +298,6 @@ private Rectangle normalBounds = null; // not-null only for undecorated maximized windows private CPlatformResponder responder; private long lastBecomeMainTime; // this is necessary to preserve right siblings order - private boolean maximizedBothState = false; - private boolean frameResizibilityChanged = false; public CPlatformWindow() { super(0, true); @@ -402,7 +400,7 @@ // Either java.awt.Frame or java.awt.Dialog can be resizable, however java.awt.Window is never resizable { - final boolean resizable = isTargetResizable(); + final boolean resizable = isFrame ? ((Frame)target).isResizable() : (isDialog ? ((Dialog)target).isResizable() : false); styleBits = SET(styleBits, RESIZABLE, resizable); if (!resizable) { styleBits = SET(styleBits, ZOOMABLE, false); @@ -614,8 +612,6 @@ setBounds(maximizedBounds.x, maximizedBounds.y, maximizedBounds.width, maximizedBounds.height); } - setFrameResizibilityChanged(true); - updateResizableAndMaximizeState(true); } private void unmaximize() { @@ -712,9 +708,11 @@ // Manage the extended state when showing if (visible) { /* Frame or Dialog should be set property WINDOW_FULLSCREENABLE to true if the - Frame resizable and Frame state is not MAXIMIZED_BOTH or Dialog is resizable. + Frame or Dialog is resizable. **/ - if (isTargetResizable()) { + final boolean resizable = (target instanceof Frame) ? ((Frame)target).isResizable() : + ((target instanceof Dialog) ? ((Dialog)target).isResizable() : false); + if (resizable) { setCanFullscreen(true); } @@ -730,11 +728,6 @@ frameState = Frame.ICONIFIED; } - if (isFrameResizibilityChanged()) { - updateResizableAndMaximizeState(false); - setFrameResizibilityChanged(false); - } - switch (frameState) { case Frame.ICONIFIED: execute(CWrapper.NSWindow::miniaturize); @@ -854,10 +847,9 @@ @Override public void setResizable(final boolean resizable) { - boolean windowResizable = resizable && !isMaximizedBoth(); - setCanFullscreen(windowResizable); - setStyleBits(RESIZABLE, windowResizable); - setStyleBits(ZOOMABLE, windowResizable); + setCanFullscreen(resizable); + setStyleBits(RESIZABLE, resizable); + setStyleBits(ZOOMABLE, resizable); } @Override @@ -966,11 +958,6 @@ windowState = Frame.ICONIFIED; } - if (isFrameResizibilityChanged()) { - updateResizableAndMaximizeState(false); - setFrameResizibilityChanged(false); - } - switch (windowState) { case Frame.ICONIFIED: if (prevWindowState == Frame.MAXIMIZED_BOTH) { @@ -1174,21 +1161,6 @@ } /* - * Resizibility of frame with state MAXIMIZED_BOTH is set to true to zoom - * the frame on double click on title bar and set to false later. This is - * required as frame won't zoom if resizibility of frame is false. - */ - private void deliverDoubleClickOnTitlebar() { - if ((peer != null) && (target instanceof Frame)) { - if (isMaximizedBoth()) { - updateResizableAndMaximizeState(false); - execute(CWrapper.NSWindow::zoom); - updateResizableAndMaximizeState(true); - } - } - } - - /* * Our focus model is synthetic and only non-simple window * may become natively focusable window. */ @@ -1353,33 +1325,6 @@ } return false; } - - private boolean isTargetResizable() { - if (target instanceof Frame) { - return ((Frame)target).isResizable() && !isMaximizedBoth(); - } else if (target instanceof Dialog) { - return ((Dialog)target).isResizable(); - } - return false; - } - - private void updateResizableAndMaximizeState(boolean maximizeState) { - maximizedBothState = maximizeState; - setResizable(!maximizeState); - } - - private boolean isMaximizedBoth() { - return maximizedBothState; - } - - private void setFrameResizibilityChanged(boolean resize) { - frameResizibilityChanged = resize; - } - - private boolean isFrameResizibilityChanged() { - return frameResizibilityChanged; - } - // ---------------------------------------------------------------------- // NATIVE CALLBACKS // ---------------------------------------------------------------------- diff -r a47b8125b7cc -r 58e25974ede4 src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m Wed Jan 16 19:09:16 2019 +0000 +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m Wed Jan 16 20:53:09 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -965,11 +965,6 @@ // Currently, no need to deliver the whole NSEvent. static JNF_MEMBER_CACHE(jm_deliverNCMouseDown, jc_CPlatformWindow, "deliverNCMouseDown", "()V"); JNFCallVoidMethod(env, platformWindow, jm_deliverNCMouseDown); - // Deliver double click on title bar - if ([event clickCount] > 1) { - static JNF_MEMBER_CACHE(jm_deliverDoubleClickOnTitlebar, jc_CPlatformWindow, "deliverDoubleClickOnTitlebar", "()V"); - JNFCallVoidMethod(env, platformWindow, jm_deliverDoubleClickOnTitlebar); - } (*env)->DeleteLocalRef(env, platformWindow); } } diff -r a47b8125b7cc -r 58e25974ede4 test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java Wed Jan 16 19:09:16 2019 +0000 +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java Wed Jan 16 20:53:09 2019 +0100 @@ -168,6 +168,26 @@ } + static class ClassType { + } + + interface InterfaceType { + } + + @Test + public void testCloneAccessibility() { + /* + * The resolution machinery for clone on arrays has some hacks in that show up in odd places + * so make sure that resolveMethod works as expected. + */ + ResolvedJavaType interfaceType = getType(InterfaceType.class); + ResolvedJavaType classType = getType(ClassType.class); + ResolvedJavaType arrayType = getType(double[].class); + ResolvedJavaMethod cloneMethod = getMethod(getType(Object.class), "clone"); + assertEquals("Can't resolve clone for class", cloneMethod, arrayType.resolveMethod(cloneMethod, classType)); + assertEquals("Can't resolve clone for interface", cloneMethod, arrayType.resolveMethod(cloneMethod, interfaceType)); + } + static ResolvedJavaMethod getMethod(ResolvedJavaType type, String methodName) { for (ResolvedJavaMethod method : type.getDeclaredMethods()) { if (method.getName().equals(methodName)) { diff -r a47b8125b7cc -r 58e25974ede4 test/hotspot/jtreg/gc/g1/TestPeriodicLogMessages.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/gc/g1/TestPeriodicLogMessages.java Wed Jan 16 20:53:09 2019 +0100 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 TestPeriodicLogMessages + * @bug 8216490 + * @requires vm.gc.G1 + * @summary Verify that log messages are printed as expected + * @library /test/lib / + * @modules java.base/jdk.internal.misc + * @modules java.management/sun.management + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Platform; + +public class TestPeriodicLogMessages { + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:G1PeriodicGCInterval=0", + "-Xlog:gc,gc+periodic=debug", + "-Xmx10M", + GCTest.class.getName()); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Periodic GC disabled"); + output.shouldNotContain("Checking for periodic GC"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", + "-XX:G1PeriodicGCInterval=100", + "-Xlog:gc,gc+periodic=debug", + "-Xmx10M", + GCTest.class.getName()); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Periodic GC enabled with interval 100ms"); + output.shouldContain("Checking for periodic GC"); + output.shouldHaveExitValue(0); + } + + static class GCTest { + public static void main(String [] args) throws Exception { + System.out.println("Waiting for messages..."); + Thread.sleep(1000); + System.out.println("Done"); + } + } +} + + diff -r a47b8125b7cc -r 58e25974ede4 test/jdk/java/awt/Frame/UnfocusableMaximizedFrameResizablity/UnfocusableMaximizedFrameResizablity.java --- a/test/jdk/java/awt/Frame/UnfocusableMaximizedFrameResizablity/UnfocusableMaximizedFrameResizablity.java Wed Jan 16 19:09:16 2019 +0000 +++ b/test/jdk/java/awt/Frame/UnfocusableMaximizedFrameResizablity/UnfocusableMaximizedFrameResizablity.java Wed Jan 16 20:53:09 2019 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* @test @key headful - @bug 4980161 7158623 8204860 8208125 + @bug 4980161 7158623 8204860 8208125 8215280 @summary Setting focusable window state to false makes the maximized frame resizable @compile UnfocusableMaximizedFrameResizablity.java @run main UnfocusableMaximizedFrameResizablity @@ -47,8 +47,15 @@ private static void createAndShowFrame() throws Exception { + //MAXIMIZED_BOTH frame is resizable on Mac OS by default. Nothing to test. + if (System.getProperty("os.name").toLowerCase().startsWith("mac")) { + cleanup(); + return; + } + //The MAXIMIZED_BOTH state is not supported by the toolkit. Nothing to test. if (!Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) { + cleanup(); return; } @@ -93,7 +100,9 @@ } private static void cleanup() { - frame.dispose(); + if (frame != null) { + frame.dispose(); + } isProgInterruption = true; mainThread.interrupt(); } diff -r a47b8125b7cc -r 58e25974ede4 test/jdk/sun/security/tools/keytool/PSS.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/sun/security/tools/keytool/PSS.java Wed Jan 16 20:53:09 2019 +0100 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8215694 + * @summary keytool cannot generate RSASSA-PSS certificates + * @library /test/lib + * @modules java.base/sun.security.util + * java.base/sun.security.x509 + * @run main PSS + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.SecurityTools; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.security.DerUtils; +import sun.security.util.ObjectIdentifier; +import sun.security.x509.AlgorithmId; + +import java.io.File; +import java.security.KeyStore; +import java.security.cert.X509Certificate; + +public class PSS { + + public static void main(String[] args) throws Exception { + + genkeypair("p", "-keyalg RSASSA-PSS -sigalg RSASSA-PSS") + .shouldHaveExitValue(0); + + genkeypair("a", "-keyalg RSA -sigalg RSASSA-PSS -keysize 2048") + .shouldHaveExitValue(0); + + genkeypair("b", "-keyalg RSA -sigalg RSASSA-PSS -keysize 4096") + .shouldHaveExitValue(0); + + genkeypair("c", "-keyalg RSA -sigalg RSASSA-PSS -keysize 8192") + .shouldHaveExitValue(0); + + KeyStore ks = KeyStore.getInstance( + new File("ks"), "changeit".toCharArray()); + + check((X509Certificate)ks.getCertificate("p"), "RSASSA-PSS", + AlgorithmId.SHA256_oid); + + check((X509Certificate)ks.getCertificate("a"), "RSA", + AlgorithmId.SHA256_oid); + + check((X509Certificate)ks.getCertificate("b"), "RSA", + AlgorithmId.SHA384_oid); + + check((X509Certificate)ks.getCertificate("c"), "RSA", + AlgorithmId.SHA512_oid); + + // More commands + kt("-certreq -alias p -sigalg RSASSA-PSS -file p.req") + .shouldHaveExitValue(0); + + kt("-gencert -alias a -sigalg RSASSA-PSS -infile p.req -outfile p.cert") + .shouldHaveExitValue(0); + + kt("-importcert -alias p -file p.cert") + .shouldHaveExitValue(0); + + kt("-selfcert -alias p -sigalg RSASSA-PSS") + .shouldHaveExitValue(0); + } + + static OutputAnalyzer genkeypair(String alias, String options) + throws Exception { + return kt("-genkeypair -alias " + alias + + " -dname CN=" + alias + " " + options); + } + + static OutputAnalyzer kt(String cmd) + throws Exception { + return SecurityTools.keytool("-storepass changeit -keypass changeit " + + "-keystore ks " + cmd); + } + + static void check(X509Certificate cert, String expectedKeyAlg, + ObjectIdentifier expectedMdAlg) throws Exception { + Asserts.assertEQ(cert.getPublicKey().getAlgorithm(), expectedKeyAlg); + Asserts.assertEQ(cert.getSigAlgName(), "RSASSA-PSS"); + DerUtils.checkAlg(cert.getSigAlgParams(), "000", expectedMdAlg); + } +}