# HG changeset patch # User psadhukhan # Date 1564037634 -19800 # Node ID b0aaa82a1b03bf2116fdbc98b84f3a640a1d5bab # Parent 70865ef2afc73879c359237a8f147e323b79e4fa# Parent 3307a6ded22d6cfdca64f50c8865f65c9b9dc096 Merge diff -r 70865ef2afc7 -r b0aaa82a1b03 .hgtags --- a/.hgtags Wed Jul 24 12:49:44 2019 +0530 +++ b/.hgtags Thu Jul 25 12:23:54 2019 +0530 @@ -575,3 +575,4 @@ 0f1e29c77e50c7da11d83df410026392c4d1a28c jdk-14+5 2e63fb0a885fa908a97bbb0da8d7c3de11536aca jdk-13+30 443f7359b34d60e7821216ffc60f88b6ffe0ccdd jdk-14+6 +28ab01c067551ef158abaef08e154e1051ca0893 jdk-14+7 diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/cpu/ppc/macroAssembler_ppc.cpp --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp Thu Jul 25 12:23:54 2019 +0530 @@ -2040,17 +2040,6 @@ bind(L_fallthrough); } -void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg, - Register temp_reg, - Label& wrong_method_type) { - assert_different_registers(mtype_reg, mh_reg, temp_reg); - // Compare method type against that of the receiver. - load_heap_oop(temp_reg, delayed_value(java_lang_invoke_MethodHandle::type_offset_in_bytes, temp_reg), mh_reg, - noreg, noreg, false, IS_NOT_NULL); - cmpd(CCR0, temp_reg, mtype_reg); - bne(CCR0, wrong_method_type); -} - RegisterOrConstant MacroAssembler::argument_offset(RegisterOrConstant arg_slot, Register temp_reg, int extra_slot_offset) { diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/cpu/ppc/macroAssembler_ppc.hpp --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp Thu Jul 25 12:23:54 2019 +0530 @@ -565,8 +565,6 @@ Label* L_slow_path = NULL); // Method handle support (JSR 292). - void check_method_handle_type(Register mtype_reg, Register mh_reg, Register temp_reg, Label& wrong_method_type); - RegisterOrConstant argument_offset(RegisterOrConstant arg_slot, Register temp_reg, int extra_slot_offset = 0); // Biased locking support diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/asm/assembler.cpp --- a/src/hotspot/share/asm/assembler.cpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/asm/assembler.cpp Thu Jul 25 12:23:54 2019 +0530 @@ -218,85 +218,6 @@ } } -struct DelayedConstant { - typedef void (*value_fn_t)(); - BasicType type; - intptr_t value; - value_fn_t value_fn; - // This limit of 20 is generous for initial uses. - // The limit needs to be large enough to store the field offsets - // into classes which do not have statically fixed layouts. - // (Initial use is for method handle object offsets.) - // Look for uses of "delayed_value" in the source code - // and make sure this number is generous enough to handle all of them. - enum { DC_LIMIT = 20 }; - static DelayedConstant delayed_constants[DC_LIMIT]; - static DelayedConstant* add(BasicType type, value_fn_t value_fn); - bool match(BasicType t, value_fn_t cfn) { - return type == t && value_fn == cfn; - } - static void update_all(); -}; - -DelayedConstant DelayedConstant::delayed_constants[DC_LIMIT]; -// Default C structure initialization rules have the following effect here: -// = { { (BasicType)0, (intptr_t)NULL }, ... }; - -DelayedConstant* DelayedConstant::add(BasicType type, - DelayedConstant::value_fn_t cfn) { - for (int i = 0; i < DC_LIMIT; i++) { - DelayedConstant* dcon = &delayed_constants[i]; - if (dcon->match(type, cfn)) - return dcon; - if (dcon->value_fn == NULL) { - dcon->value_fn = cfn; - dcon->type = type; - return dcon; - } - } - // If this assert is hit (in pre-integration testing!) then re-evaluate - // the comment on the definition of DC_LIMIT. - guarantee(false, "too many delayed constants"); - return NULL; -} - -void DelayedConstant::update_all() { - for (int i = 0; i < DC_LIMIT; i++) { - DelayedConstant* dcon = &delayed_constants[i]; - if (dcon->value_fn != NULL && dcon->value == 0) { - typedef int (*int_fn_t)(); - typedef address (*address_fn_t)(); - switch (dcon->type) { - case T_INT: dcon->value = (intptr_t) ((int_fn_t) dcon->value_fn)(); break; - case T_ADDRESS: dcon->value = (intptr_t) ((address_fn_t)dcon->value_fn)(); break; - default: break; - } - } - } -} - -RegisterOrConstant AbstractAssembler::delayed_value(int(*value_fn)(), Register tmp, int offset) { - intptr_t val = (intptr_t) (*value_fn)(); - if (val != 0) return val + offset; - return delayed_value_impl(delayed_value_addr(value_fn), tmp, offset); -} -RegisterOrConstant AbstractAssembler::delayed_value(address(*value_fn)(), Register tmp, int offset) { - intptr_t val = (intptr_t) (*value_fn)(); - if (val != 0) return val + offset; - return delayed_value_impl(delayed_value_addr(value_fn), tmp, offset); -} -intptr_t* AbstractAssembler::delayed_value_addr(int(*value_fn)()) { - DelayedConstant* dcon = DelayedConstant::add(T_INT, (DelayedConstant::value_fn_t) value_fn); - return &dcon->value; -} -intptr_t* AbstractAssembler::delayed_value_addr(address(*value_fn)()) { - DelayedConstant* dcon = DelayedConstant::add(T_ADDRESS, (DelayedConstant::value_fn_t) value_fn); - return &dcon->value; -} -void AbstractAssembler::update_delayed_values() { - DelayedConstant::update_all(); -} - void AbstractAssembler::block_comment(const char* comment) { if (sect() == CodeBuffer::SECT_INSTS) { code_section()->outer()->block_comment(offset(), comment); diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/classfile/javaClasses.cpp --- a/src/hotspot/share/classfile/javaClasses.cpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/classfile/javaClasses.cpp Thu Jul 25 12:23:54 2019 +0530 @@ -4547,9 +4547,6 @@ // BASIC_JAVA_CLASSES_DO_PART1 classes (java_lang_String and java_lang_Class) // earlier inside SystemDictionary::resolve_well_known_classes() BASIC_JAVA_CLASSES_DO_PART2(DO_COMPUTE_OFFSETS); - - // generated interpreter code wants to know about the offsets we just computed: - AbstractAssembler::update_delayed_values(); } #if INCLUDE_CDS diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/gc/g1/g1CollectedHeap.cpp --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp Thu Jul 25 12:23:54 2019 +0530 @@ -48,6 +48,7 @@ #include "gc/g1/g1HotCardCache.hpp" #include "gc/g1/g1MemoryPool.hpp" #include "gc/g1/g1OopClosures.inline.hpp" +#include "gc/g1/g1ParallelCleaning.hpp" #include "gc/g1/g1ParScanThreadState.inline.hpp" #include "gc/g1/g1Policy.hpp" #include "gc/g1/g1RedirtyCardsQueue.hpp" @@ -74,7 +75,6 @@ #include "gc/shared/generationSpec.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "gc/shared/oopStorageParState.hpp" -#include "gc/shared/parallelCleaning.hpp" #include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/suspendibleThreadSet.hpp" #include "gc/shared/referenceProcessor.inline.hpp" @@ -1080,7 +1080,7 @@ // Discard all remembered set updates. G1BarrierSet::dirty_card_queue_set().abandon_logs(); - assert(G1BarrierSet::dirty_card_queue_set().completed_buffers_num() == 0, + assert(G1BarrierSet::dirty_card_queue_set().num_completed_buffers() == 0, "DCQS should be empty"); redirty_cards_queue_set().verify_empty(); } @@ -1957,7 +1957,7 @@ while (dcqs.apply_closure_during_gc(cl, worker_i)) { n_completed_buffers++; } - assert(dcqs.completed_buffers_num() == 0, "Completed buffers exist!"); + assert(dcqs.num_completed_buffers() == 0, "Completed buffers exist!"); phase_times()->record_thread_work_item(G1GCPhaseTimes::MergeLB, worker_i, n_completed_buffers, G1GCPhaseTimes::MergeLBProcessedBuffers); } @@ -2613,10 +2613,9 @@ Threads::threads_do(&count_from_threads); G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set(); - size_t buffer_size = dcqs.buffer_size(); - size_t buffer_num = dcqs.completed_buffers_num(); - - return buffer_size * buffer_num + count_from_threads._cards; + dcqs.verify_num_entries_in_completed_buffers(); + + return dcqs.num_entries_in_completed_buffers() + count_from_threads._cards; } bool G1CollectedHeap::is_potential_eager_reclaim_candidate(HeapRegion* r) const { @@ -3166,7 +3165,7 @@ void G1CollectedHeap::complete_cleaning(BoolObjectClosure* is_alive, bool class_unloading_occurred) { uint num_workers = workers()->active_workers(); - ParallelCleaningTask unlink_task(is_alive, num_workers, class_unloading_occurred, false); + G1ParallelCleaningTask unlink_task(is_alive, num_workers, class_unloading_occurred, false); workers()->run_task(&unlink_task); } diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp Thu Jul 25 12:23:54 2019 +0530 @@ -397,7 +397,7 @@ dcqs.set_max_completed_buffers(red_zone()); } - size_t curr_queue_size = dcqs.completed_buffers_num(); + size_t curr_queue_size = dcqs.num_completed_buffers(); if ((dcqs.max_completed_buffers() > 0) && (curr_queue_size >= yellow_zone())) { dcqs.set_completed_buffers_padding(curr_queue_size); @@ -430,7 +430,7 @@ bool G1ConcurrentRefine::do_refinement_step(uint worker_id) { G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set(); - size_t curr_buffer_num = dcqs.completed_buffers_num(); + size_t curr_buffer_num = dcqs.num_completed_buffers(); // If the number of the buffers falls down into the yellow zone, // that means that the transition period after the evacuation pause has ended. // Since the value written to the DCQS is the same for all threads, there is no diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp Thu Jul 25 12:23:54 2019 +0530 @@ -104,7 +104,7 @@ size_t buffers_processed = 0; log_debug(gc, refine)("Activated worker %d, on threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT, _worker_id, _cr->activation_threshold(_worker_id), - G1BarrierSet::dirty_card_queue_set().completed_buffers_num()); + G1BarrierSet::dirty_card_queue_set().num_completed_buffers()); { SuspendibleThreadSetJoiner sts_join; @@ -126,7 +126,7 @@ log_debug(gc, refine)("Deactivated worker %d, off threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT ", processed: " SIZE_FORMAT, _worker_id, _cr->deactivation_threshold(_worker_id), - G1BarrierSet::dirty_card_queue_set().completed_buffers_num(), + G1BarrierSet::dirty_card_queue_set().num_completed_buffers(), buffers_processed); if (os::supports_vtime()) { diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp --- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp Thu Jul 25 12:23:54 2019 +0530 @@ -84,7 +84,7 @@ _cbl_mon(NULL), _completed_buffers_head(NULL), _completed_buffers_tail(NULL), - _n_completed_buffers(0), + _num_entries_in_completed_buffers(0), _process_completed_buffers_threshold(ProcessCompletedBuffersThresholdNever), _process_completed_buffers(false), _notify_when_complete(notify_when_complete), @@ -133,42 +133,56 @@ _completed_buffers_tail->set_next(cbn); _completed_buffers_tail = cbn; } - _n_completed_buffers++; + _num_entries_in_completed_buffers += buffer_size() - cbn->index(); if (!process_completed_buffers() && - (_n_completed_buffers > process_completed_buffers_threshold())) { + (num_completed_buffers() > process_completed_buffers_threshold())) { set_process_completed_buffers(true); if (_notify_when_complete) { _cbl_mon->notify_all(); } } - assert_completed_buffers_list_len_correct_locked(); + verify_num_entries_in_completed_buffers(); } BufferNode* G1DirtyCardQueueSet::get_completed_buffer(size_t stop_at) { MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag); - if (_n_completed_buffers <= stop_at) { + if (num_completed_buffers() <= stop_at) { return NULL; } - assert(_n_completed_buffers > 0, "invariant"); + assert(num_completed_buffers() > 0, "invariant"); assert(_completed_buffers_head != NULL, "invariant"); assert(_completed_buffers_tail != NULL, "invariant"); BufferNode* bn = _completed_buffers_head; - _n_completed_buffers--; + _num_entries_in_completed_buffers -= buffer_size() - bn->index(); _completed_buffers_head = bn->next(); if (_completed_buffers_head == NULL) { - assert(_n_completed_buffers == 0, "invariant"); + assert(num_completed_buffers() == 0, "invariant"); _completed_buffers_tail = NULL; set_process_completed_buffers(false); } - assert_completed_buffers_list_len_correct_locked(); + verify_num_entries_in_completed_buffers(); bn->set_next(NULL); return bn; } +#ifdef ASSERT +void G1DirtyCardQueueSet::verify_num_entries_in_completed_buffers() const { + size_t actual = 0; + BufferNode* cur = _completed_buffers_head; + while (cur != NULL) { + actual += buffer_size() - cur->index(); + cur = cur->next(); + } + assert(actual == _num_entries_in_completed_buffers, + "Num entries in completed buffers should be " SIZE_FORMAT " but are " SIZE_FORMAT, + _num_entries_in_completed_buffers, actual); +} +#endif + void G1DirtyCardQueueSet::abandon_completed_buffers() { BufferNode* buffers_to_delete = NULL; { @@ -176,7 +190,7 @@ buffers_to_delete = _completed_buffers_head; _completed_buffers_head = NULL; _completed_buffers_tail = NULL; - _n_completed_buffers = 0; + _num_entries_in_completed_buffers = 0; set_process_completed_buffers(false); } while (buffers_to_delete != NULL) { @@ -189,26 +203,13 @@ void G1DirtyCardQueueSet::notify_if_necessary() { MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag); - if (_n_completed_buffers > process_completed_buffers_threshold()) { + if (num_completed_buffers() > process_completed_buffers_threshold()) { set_process_completed_buffers(true); if (_notify_when_complete) _cbl_mon->notify(); } } -#ifdef ASSERT -void G1DirtyCardQueueSet::assert_completed_buffers_list_len_correct_locked() { - assert_lock_strong(_cbl_mon); - size_t n = 0; - for (BufferNode* bn = _completed_buffers_head; bn != NULL; bn = bn->next()) { - ++n; - } - assert(n == _n_completed_buffers, - "Completed buffer length is wrong: counted: " SIZE_FORMAT - ", expected: " SIZE_FORMAT, n, _n_completed_buffers); -} -#endif // ASSERT - // Merge lists of buffers. Notify the processing threads. // The source queue is emptied as a result. The queues // must share the monitor. @@ -227,12 +228,12 @@ _completed_buffers_tail->set_next(from._head); _completed_buffers_tail = from._tail; } - _n_completed_buffers += from._count; + _num_entries_in_completed_buffers += from._entry_count; assert(_completed_buffers_head == NULL && _completed_buffers_tail == NULL || _completed_buffers_head != NULL && _completed_buffers_tail != NULL, "Sanity"); - assert_completed_buffers_list_len_correct_locked(); + verify_num_entries_in_completed_buffers(); } bool G1DirtyCardQueueSet::apply_closure_to_buffer(G1CardTableEntryClosure* cl, @@ -278,7 +279,7 @@ // add of padding could overflow, which is treated as unlimited. size_t max_buffers = max_completed_buffers(); size_t limit = max_buffers + completed_buffers_padding(); - if ((completed_buffers_num() > limit) && (limit >= max_buffers)) { + if ((num_completed_buffers() > limit) && (limit >= max_buffers)) { if (mut_process_buffer(node)) { return true; } diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp --- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp Thu Jul 25 12:23:54 2019 +0530 @@ -69,7 +69,9 @@ Monitor* _cbl_mon; // Protects the fields below. BufferNode* _completed_buffers_head; BufferNode* _completed_buffers_tail; - volatile size_t _n_completed_buffers; + + // Number of actual entries in the list of completed buffers. + volatile size_t _num_entries_in_completed_buffers; size_t _process_completed_buffers_threshold; volatile bool _process_completed_buffers; @@ -77,8 +79,6 @@ // If true, notify_all on _cbl_mon when the threshold is reached. bool _notify_when_complete; - void assert_completed_buffers_list_len_correct_locked() NOT_DEBUG_RETURN; - void abandon_completed_buffers(); // Apply the closure to the elements of "node" from it's index to @@ -150,8 +150,17 @@ // return a completed buffer from the list. Otherwise, return NULL. BufferNode* get_completed_buffer(size_t stop_at = 0); - // The number of buffers in the list. Racy... - size_t completed_buffers_num() const { return _n_completed_buffers; } + // The number of buffers in the list. Derived as an approximation from the number + // of entries in the buffers. Racy. + size_t num_completed_buffers() const { + return (num_entries_in_completed_buffers() + buffer_size() - 1) / buffer_size(); + } + // The number of entries in completed buffers. Read without synchronization. + size_t num_entries_in_completed_buffers() const { return _num_entries_in_completed_buffers; } + + // Verify that _num_entries_in_completed_buffers is equal to the sum of actual entries + // in the completed buffers. + void verify_num_entries_in_completed_buffers() const NOT_DEBUG_RETURN; bool process_completed_buffers() { return _process_completed_buffers; } void set_process_completed_buffers(bool x) { _process_completed_buffers = x; } diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp Thu Jul 25 12:23:54 2019 +0530 @@ -86,8 +86,14 @@ _gc_par_phases[MergeLB] = new WorkerDataArray(max_gc_threads, "Log Buffers (ms):"); if (G1HotCardCache::default_use_cache()) { _gc_par_phases[MergeHCC] = new WorkerDataArray(max_gc_threads, "Hot Card Cache (ms):"); + _merge_hcc_dirty_cards = new WorkerDataArray(max_gc_threads, "Dirty Cards:"); + _gc_par_phases[MergeHCC]->link_thread_work_items(_merge_hcc_dirty_cards, MergeHCCDirtyCards); + _merge_hcc_skipped_cards = new WorkerDataArray(max_gc_threads, "Skipped Cards:"); + _gc_par_phases[MergeHCC]->link_thread_work_items(_merge_hcc_skipped_cards, MergeHCCSkippedCards); } else { _gc_par_phases[MergeHCC] = NULL; + _merge_hcc_dirty_cards = NULL; + _merge_hcc_skipped_cards = NULL; } _gc_par_phases[ScanHR] = new WorkerDataArray(max_gc_threads, "Scan Heap Roots (ms):"); _gc_par_phases[OptScanHR] = new WorkerDataArray(max_gc_threads, "Optional Scan Heap Roots (ms):"); diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp Thu Jul 25 12:23:54 2019 +0530 @@ -100,6 +100,11 @@ ScanHRUsedMemory }; + enum GCMergeHCCWorkItems { + MergeHCCDirtyCards, + MergeHCCSkippedCards + }; + enum GCMergeLBWorkItems { MergeLBProcessedBuffers, MergeLBDirtyCards, @@ -121,6 +126,9 @@ WorkerDataArray* _merge_rs_merged_fine; WorkerDataArray* _merge_rs_merged_coarse; + WorkerDataArray* _merge_hcc_dirty_cards; + WorkerDataArray* _merge_hcc_skipped_cards; + WorkerDataArray* _merge_lb_processed_buffers; WorkerDataArray* _merge_lb_dirty_cards; WorkerDataArray* _merge_lb_skipped_cards; diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/gc/g1/g1ParallelCleaning.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,83 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" + +#include "gc/g1/g1ParallelCleaning.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif + +#if INCLUDE_JVMCI +JVMCICleaningTask::JVMCICleaningTask() : + _cleaning_claimed(0) { +} + +bool JVMCICleaningTask::claim_cleaning_task() { + if (_cleaning_claimed) { + return false; + } + + return Atomic::cmpxchg(1, &_cleaning_claimed, 0) == 0; +} + +void JVMCICleaningTask::work(bool unloading_occurred) { + // One worker will clean JVMCI metadata handles. + if (unloading_occurred && EnableJVMCI && claim_cleaning_task()) { + JVMCI::do_unloading(unloading_occurred); + } +} +#endif // INCLUDE_JVMCI + +G1ParallelCleaningTask::G1ParallelCleaningTask(BoolObjectClosure* is_alive, + uint num_workers, + bool unloading_occurred, + bool resize_dedup_table) : + AbstractGangTask("G1 Parallel Cleaning"), + _unloading_occurred(unloading_occurred), + _string_dedup_task(is_alive, NULL, resize_dedup_table), + _code_cache_task(num_workers, is_alive, unloading_occurred), + JVMCI_ONLY(_jvmci_cleaning_task() COMMA) + _klass_cleaning_task() { +} + +// The parallel work done by all worker threads. +void G1ParallelCleaningTask::work(uint worker_id) { + // Clean JVMCI metadata handles. + // Execute this task first because it is serial task. + JVMCI_ONLY(_jvmci_cleaning_task.work(_unloading_occurred);) + + // Do first pass of code cache cleaning. + _code_cache_task.work(worker_id); + + // Clean the string dedup data structures. + _string_dedup_task.work(worker_id); + + // Clean all klasses that were not unloaded. + // The weak metadata in klass doesn't need to be + // processed if there was no unloading. + if (_unloading_occurred) { + _klass_cleaning_task.work(); + } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/gc/g1/g1ParallelCleaning.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1ParallelCleaning.hpp Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,66 @@ +/* + * 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. + * + */ + +#ifndef SHARE_GC_G1_G1PARALLELCLEANING_HPP +#define SHARE_GC_G1_G1PARALLELCLEANING_HPP + +#include "gc/shared/parallelCleaning.hpp" + +#if INCLUDE_JVMCI +class JVMCICleaningTask : public StackObj { + volatile int _cleaning_claimed; + +public: + JVMCICleaningTask(); + // Clean JVMCI metadata handles. + void work(bool unloading_occurred); + +private: + bool claim_cleaning_task(); +}; +#endif + +// Do cleanup of some weakly held data in the same parallel task. +// Assumes a non-moving context. +class G1ParallelCleaningTask : public AbstractGangTask { +private: + bool _unloading_occurred; + StringDedupCleaningTask _string_dedup_task; + CodeCacheUnloadingTask _code_cache_task; +#if INCLUDE_JVMCI + JVMCICleaningTask _jvmci_cleaning_task; +#endif + KlassCleaningTask _klass_cleaning_task; + +public: + // The constructor is run in the VMThread. + G1ParallelCleaningTask(BoolObjectClosure* is_alive, + uint num_workers, + bool unloading_occurred, + bool resize_dedup_table); + + void work(uint worker_id); +}; + +#endif // SHARE_GC_G1_G1PARALLELCLEANING_HPP diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp --- a/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp Thu Jul 25 12:23:54 2019 +0530 @@ -31,15 +31,15 @@ // G1RedirtyCardsBufferList G1RedirtyCardsBufferList::G1RedirtyCardsBufferList() : - _head(NULL), _tail(NULL), _count(0) {} + _head(NULL), _tail(NULL), _entry_count(0) {} G1RedirtyCardsBufferList::G1RedirtyCardsBufferList(BufferNode* head, BufferNode* tail, - size_t count) : - _head(head), _tail(tail), _count(count) + size_t entry_count) : + _head(head), _tail(tail), _entry_count(entry_count) { assert((_head == NULL) == (_tail == NULL), "invariant"); - assert((_head == NULL) == (_count == 0), "invariant"); + assert((_head == NULL) == (_entry_count == 0), "invariant"); } // G1RedirtyCardsQueueBase::LocalQSet @@ -55,11 +55,11 @@ G1RedirtyCardsQueueBase::LocalQSet::~LocalQSet() { assert(_buffers._head == NULL, "unflushed qset"); assert(_buffers._tail == NULL, "invariant"); - assert(_buffers._count == 0, "invariant"); + assert(_buffers._entry_count == 0, "invariant"); } void G1RedirtyCardsQueueBase::LocalQSet::enqueue_completed_buffer(BufferNode* node) { - ++_buffers._count; + _buffers._entry_count += buffer_size() - node->index(); node->set_next(_buffers._head); _buffers._head = node; if (_buffers._tail == NULL) { @@ -67,8 +67,7 @@ } } -G1RedirtyCardsBufferList -G1RedirtyCardsQueueBase::LocalQSet::take_all_completed_buffers() { +G1RedirtyCardsBufferList G1RedirtyCardsQueueBase::LocalQSet::take_all_completed_buffers() { G1RedirtyCardsBufferList result = _buffers; _buffers = G1RedirtyCardsBufferList(); return result; @@ -103,7 +102,7 @@ G1RedirtyCardsQueueSet::G1RedirtyCardsQueueSet() : PtrQueueSet(), _list(), - _count(0), + _entry_count(0), _tail(NULL) DEBUG_ONLY(COMMA _collecting(true)) {} @@ -116,7 +115,7 @@ void G1RedirtyCardsQueueSet::verify_empty() const { assert(_list.empty(), "precondition"); assert(_tail == NULL, "invariant"); - assert(_count == 0, "invariant"); + assert(_entry_count == 0, "invariant"); } #endif // ASSERT @@ -127,9 +126,9 @@ G1RedirtyCardsBufferList G1RedirtyCardsQueueSet::take_all_completed_buffers() { DEBUG_ONLY(_collecting = false;) - G1RedirtyCardsBufferList result(_list.pop_all(), _tail, _count); + G1RedirtyCardsBufferList result(_list.pop_all(), _tail, _entry_count); _tail = NULL; - _count = 0; + _entry_count = 0; DEBUG_ONLY(_collecting = true;) return result; } @@ -146,7 +145,7 @@ void G1RedirtyCardsQueueSet::enqueue_completed_buffer(BufferNode* node) { assert(_collecting, "precondition"); - Atomic::inc(&_count); + Atomic::add(buffer_size() - node->index(), &_entry_count); _list.push(*node); update_tail(node); } @@ -156,7 +155,7 @@ const G1RedirtyCardsBufferList from = src->take_all_completed_buffers(); if (from._head != NULL) { assert(from._tail != NULL, "invariant"); - Atomic::add(from._count, &_count); + Atomic::add(from._entry_count, &_entry_count); _list.prepend(*from._head, *from._tail); update_tail(from._tail); } diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp --- a/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp Thu Jul 25 12:23:54 2019 +0530 @@ -36,10 +36,10 @@ struct G1RedirtyCardsBufferList { BufferNode* _head; BufferNode* _tail; - size_t _count; + size_t _entry_count; G1RedirtyCardsBufferList(); - G1RedirtyCardsBufferList(BufferNode* head, BufferNode* tail, size_t count); + G1RedirtyCardsBufferList(BufferNode* head, BufferNode* tail, size_t entry_count); }; // Provide G1RedirtyCardsQueue with a thread-local qset. It provides an @@ -100,7 +100,7 @@ DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0); BufferNode::Stack _list; DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, sizeof(size_t)); - volatile size_t _count; + volatile size_t _entry_count; DEFINE_PAD_MINUS_SIZE(3, DEFAULT_CACHE_LINE_SIZE, sizeof(BufferNode*)); BufferNode* _tail; DEBUG_ONLY(mutable bool _collecting;) diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/gc/g1/g1RemSet.cpp --- a/src/hotspot/share/gc/g1/g1RemSet.cpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp Thu Jul 25 12:23:54 2019 +0530 @@ -94,24 +94,35 @@ // to (>=) HeapRegion::CardsPerRegion (completely scanned). uint volatile* _card_table_scan_state; - // Random power of two number of cards we want to claim per thread. This corresponds - // to a 64k of memory work chunk area for every thread. - // We use the same claim size as Parallel GC. No particular measurements have been - // performed to determine an optimal number. - static const uint CardsPerChunk = 128; + // Return "optimal" number of chunks per region we want to use for claiming areas + // within a region to claim. Dependent on the region size as proxy for the heap + // size, we limit the total number of chunks to limit memory usage and maintenance + // effort of that table vs. granularity of distributing scanning work. + // Testing showed that 8 for 1M/2M region, 16 for 4M/8M regions, 32 for 16/32M regions + // seems to be such a good trade-off. + static uint get_chunks_per_region(uint log_region_size) { + // Limit the expected input values to current known possible values of the + // (log) region size. Adjust as necessary after testing if changing the permissible + // values for region size. + assert(log_region_size >= 20 && log_region_size <= 25, + "expected value in [20,25], but got %u", log_region_size); + return 1u << (log_region_size / 2 - 7); + } - uint _scan_chunks_per_region; + uint _scan_chunks_per_region; // Number of chunks per region. + uint8_t _log_scan_chunks_per_region; // Log of number of chunks per region. bool* _region_scan_chunks; - uint8_t _scan_chunks_shift; + size_t _num_total_scan_chunks; // Total number of elements in _region_scan_chunks. + uint8_t _scan_chunks_shift; // For conversion between card index and chunk index. public: uint scan_chunk_size() const { return (uint)1 << _scan_chunks_shift; } // Returns whether the chunk corresponding to the given region/card in region contain a // dirty card, i.e. actually needs scanning. bool chunk_needs_scan(uint const region_idx, uint const card_in_region) const { - size_t const idx = (size_t)region_idx * _scan_chunks_per_region + (card_in_region >> _scan_chunks_shift); - assert(idx < (_max_regions * _scan_chunks_per_region), "Index " SIZE_FORMAT " out of bounds " SIZE_FORMAT, - idx, _max_regions * _scan_chunks_per_region); + size_t const idx = ((size_t)region_idx << _log_scan_chunks_per_region) + (card_in_region >> _scan_chunks_shift); + assert(idx < _num_total_scan_chunks, "Index " SIZE_FORMAT " out of bounds " SIZE_FORMAT, + idx, _num_total_scan_chunks); return _region_scan_chunks[idx]; } @@ -286,8 +297,10 @@ _max_regions(0), _collection_set_iter_state(NULL), _card_table_scan_state(NULL), - _scan_chunks_per_region((uint)(HeapRegion::CardsPerRegion / CardsPerChunk)), + _scan_chunks_per_region(get_chunks_per_region(HeapRegion::LogOfHRGrainBytes)), + _log_scan_chunks_per_region(log2_uint(_scan_chunks_per_region)), _region_scan_chunks(NULL), + _num_total_scan_chunks(0), _scan_chunks_shift(0), _all_dirty_regions(NULL), _next_dirty_regions(NULL), @@ -306,7 +319,8 @@ _max_regions = max_regions; _collection_set_iter_state = NEW_C_HEAP_ARRAY(G1RemsetIterState, max_regions, mtGC); _card_table_scan_state = NEW_C_HEAP_ARRAY(uint, max_regions, mtGC); - _region_scan_chunks = NEW_C_HEAP_ARRAY(bool, max_regions * _scan_chunks_per_region, mtGC); + _num_total_scan_chunks = max_regions * _scan_chunks_per_region; + _region_scan_chunks = NEW_C_HEAP_ARRAY(bool, _num_total_scan_chunks, mtGC); _scan_chunks_shift = (uint8_t)log2_intptr(HeapRegion::CardsPerRegion / _scan_chunks_per_region); _scan_top = NEW_C_HEAP_ARRAY(HeapWord*, max_regions, mtGC); @@ -333,7 +347,7 @@ _card_table_scan_state[i] = 0; } - ::memset(_region_scan_chunks, false, _max_regions * _scan_chunks_per_region * sizeof(*_region_scan_chunks)); + ::memset(_region_scan_chunks, false, _num_total_scan_chunks * sizeof(*_region_scan_chunks)); } // Returns whether the given region contains cards we need to scan. The remembered @@ -349,12 +363,12 @@ size_t num_visited_cards() const { size_t result = 0; - for (uint i = 0; i < _max_regions * _scan_chunks_per_region; i++) { + for (uint i = 0; i < _num_total_scan_chunks; i++) { if (_region_scan_chunks[i]) { result++; } } - return result * CardsPerChunk; + return result * (HeapRegion::CardsPerRegion / _scan_chunks_per_region); } size_t num_cards_in_dirty_regions() const { @@ -369,9 +383,9 @@ } void set_chunk_dirty(size_t const card_idx) { - assert((card_idx >> _scan_chunks_shift) < (_max_regions * _scan_chunks_per_region), + assert((card_idx >> _scan_chunks_shift) < _num_total_scan_chunks, "Trying to access index " SIZE_FORMAT " out of bounds " SIZE_FORMAT, - card_idx >> _scan_chunks_shift, _max_regions * _scan_chunks_per_region); + card_idx >> _scan_chunks_shift, _num_total_scan_chunks); size_t const chunk_idx = card_idx >> _scan_chunks_shift; if (!_region_scan_chunks[chunk_idx]) { _region_scan_chunks[chunk_idx] = true; @@ -1133,6 +1147,9 @@ G1GCParPhaseTimesTracker x(p, G1GCPhaseTimes::MergeHCC, worker_id); G1MergeLogBufferCardsClosure cl(g1h, _scan_state); g1h->iterate_hcc_closure(&cl, worker_id); + + p->record_thread_work_item(G1GCPhaseTimes::MergeHCC, worker_id, cl.cards_dirty(), G1GCPhaseTimes::MergeHCCDirtyCards); + p->record_thread_work_item(G1GCPhaseTimes::MergeHCC, worker_id, cl.cards_skipped(), G1GCPhaseTimes::MergeHCCSkippedCards); } // Now apply the closure to all remaining log entries. diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/gc/shared/parallelCleaning.cpp --- a/src/hotspot/share/gc/shared/parallelCleaning.cpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/gc/shared/parallelCleaning.cpp Thu Jul 25 12:23:54 2019 +0530 @@ -30,9 +30,6 @@ #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "logging/log.hpp" -#if INCLUDE_JVMCI -#include "jvmci/jvmci.hpp" -#endif StringDedupCleaningTask::StringDedupCleaningTask(BoolObjectClosure* is_alive, OopClosure* keep_alive, @@ -160,56 +157,3 @@ clean_klass(klass); } } - -#if INCLUDE_JVMCI -JVMCICleaningTask::JVMCICleaningTask() : - _cleaning_claimed(0) { -} - -bool JVMCICleaningTask::claim_cleaning_task() { - if (_cleaning_claimed) { - return false; - } - - return Atomic::cmpxchg(1, &_cleaning_claimed, 0) == 0; -} - -void JVMCICleaningTask::work(bool unloading_occurred) { - // One worker will clean JVMCI metadata handles. - if (unloading_occurred && EnableJVMCI && claim_cleaning_task()) { - JVMCI::do_unloading(unloading_occurred); - } -} -#endif // INCLUDE_JVMCI - -ParallelCleaningTask::ParallelCleaningTask(BoolObjectClosure* is_alive, - uint num_workers, - bool unloading_occurred, - bool resize_dedup_table) : - AbstractGangTask("Parallel Cleaning"), - _unloading_occurred(unloading_occurred), - _string_dedup_task(is_alive, NULL, resize_dedup_table), - _code_cache_task(num_workers, is_alive, unloading_occurred), - JVMCI_ONLY(_jvmci_cleaning_task() COMMA) - _klass_cleaning_task() { -} - -// The parallel work done by all worker threads. -void ParallelCleaningTask::work(uint worker_id) { - // Clean JVMCI metadata handles. - // Execute this task first because it is serial task. - JVMCI_ONLY(_jvmci_cleaning_task.work(_unloading_occurred);) - - // Do first pass of code cache cleaning. - _code_cache_task.work(worker_id); - - // Clean the string dedup data structures. - _string_dedup_task.work(worker_id); - - // Clean all klasses that were not unloaded. - // The weak metadata in klass doesn't need to be - // processed if there was no unloading. - if (_unloading_occurred) { - _klass_cleaning_task.work(); - } -} diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/gc/shared/parallelCleaning.hpp --- a/src/hotspot/share/gc/shared/parallelCleaning.hpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/gc/shared/parallelCleaning.hpp Thu Jul 25 12:23:54 2019 +0530 @@ -31,8 +31,6 @@ #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/workgroup.hpp" -class ParallelCleaningTask; - class StringDedupCleaningTask : public AbstractGangTask { StringDedupUnlinkOrOopsDoClosure _dedup_closure; @@ -87,40 +85,4 @@ void work(); }; -#if INCLUDE_JVMCI -class JVMCICleaningTask : public StackObj { - volatile int _cleaning_claimed; - -public: - JVMCICleaningTask(); - // Clean JVMCI metadata handles. - void work(bool unloading_occurred); - -private: - bool claim_cleaning_task(); -}; -#endif - -// Do cleanup of some weakly held data in the same parallel task. -// Assumes a non-moving context. -class ParallelCleaningTask : public AbstractGangTask { -private: - bool _unloading_occurred; - StringDedupCleaningTask _string_dedup_task; - CodeCacheUnloadingTask _code_cache_task; -#if INCLUDE_JVMCI - JVMCICleaningTask _jvmci_cleaning_task; -#endif - KlassCleaningTask _klass_cleaning_task; - -public: - // The constructor is run in the VMThread. - ParallelCleaningTask(BoolObjectClosure* is_alive, - uint num_workers, - bool unloading_occurred, - bool resize_dedup_table); - - void work(uint worker_id); -}; - #endif // SHARE_GC_SHARED_PARALLELCLEANING_HPP diff -r 70865ef2afc7 -r b0aaa82a1b03 src/hotspot/share/oops/constantPool.cpp --- a/src/hotspot/share/oops/constantPool.cpp Wed Jul 24 12:49:44 2019 +0530 +++ b/src/hotspot/share/oops/constantPool.cpp Thu Jul 25 12:23:54 2019 +0530 @@ -760,6 +760,10 @@ // return the method type signature in the error message message = this_cp->method_type_signature_at(which); break; + case JVM_CONSTANT_Dynamic: + // return the name of the condy in the error message + message = this_cp->uncached_name_ref_at(which); + break; default: ShouldNotReachHere(); } diff -r 70865ef2afc7 -r b0aaa82a1b03 src/java.base/share/classes/java/lang/invoke/MemberName.java --- a/src/java.base/share/classes/java/lang/invoke/MemberName.java Wed Jul 24 12:49:44 2019 +0530 +++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java Thu Jul 25 12:23:54 2019 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -521,7 +521,7 @@ public boolean isAccessibleFrom(Class lookupClass) { int mode = (ALL_ACCESS|MethodHandles.Lookup.PACKAGE|MethodHandles.Lookup.MODULE); return VerifyAccess.isMemberAccessible(this.getDeclaringClass(), this.getDeclaringClass(), flags, - lookupClass, mode); + lookupClass, null, mode); } /** @@ -930,13 +930,21 @@ message += ", from public Lookup"; } else { Module m; + Class plc; if (from instanceof MethodHandles.Lookup) { MethodHandles.Lookup lookup = (MethodHandles.Lookup)from; + from = lookup.lookupClass(); m = lookup.lookupClass().getModule(); + plc = lookup.previousLookupClass(); } else { - m = from.getClass().getModule(); + m = ((Class)from).getModule(); + plc = null; } message += ", from " + from + " (" + m + ")"; + if (plc != null) { + message += ", previous lookup " + + plc.getName() + " (" + plc.getModule() + ")"; + } } } return new IllegalAccessException(message); diff -r 70865ef2afc7 -r b0aaa82a1b03 src/java.base/share/classes/java/lang/invoke/MethodHandles.java --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Jul 24 12:49:44 2019 +0530 +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Thu Jul 25 12:23:54 2019 +0530 @@ -125,7 +125,7 @@ /** * Returns a {@link Lookup lookup object} which is trusted minimally. - * The lookup has the {@code PUBLIC} and {@code UNCONDITIONAL} modes. + * The lookup has the {@code UNCONDITIONAL} mode. * It can only be used to create method handles to public members of * public classes in packages that are exported unconditionally. *

@@ -134,14 +134,14 @@ * * @apiNote The use of Object is conventional, and because the lookup modes are * limited, there is no special access provided to the internals of Object, its package - * or its module. Consequently, the lookup context of this lookup object will be the - * bootstrap class loader, which means it cannot find user classes. + * or its module. This public lookup object or other lookup object with + * {@code UNCONDITIONAL} mode assumes readability. Consequently, the lookup class + * is not used to determine the lookup context. * *

* Discussion: * The lookup class can be changed to any other class {@code C} using an expression of the form * {@link Lookup#in publicLookup().in(C.class)}. - * but may change the lookup context by virtue of changing the class loader. * A public lookup object is always subject to * security manager checks. * Also, it cannot access @@ -156,64 +156,106 @@ } /** - * Returns a {@link Lookup lookup object} with full capabilities to emulate all - * supported bytecode behaviors, including - * private access, on a target class. - * This method checks that a caller, specified as a {@code Lookup} object, is allowed to - * do deep reflection on the target class. If {@code m1} is the module containing - * the {@link Lookup#lookupClass() lookup class}, and {@code m2} is the module containing - * the target class, then this check ensures that + * Returns a {@link Lookup lookup} object on a target class to emulate all supported + * bytecode behaviors, including private access. + * The returned lookup object can provide access to classes in modules and packages, + * and members of those classes, outside the normal rules of Java access control, + * instead conforming to the more permissive rules for modular deep reflection. + *

+ * A caller, specified as a {@code Lookup} object, in module {@code M1} is + * allowed to do deep reflection on module {@code M2} and package of the target class + * if and only if all of the following conditions are {@code true}: *

    - *
  • {@code m1} {@link Module#canRead reads} {@code m2}.
  • - *
  • {@code m2} {@link Module#isOpen(String,Module) opens} the package containing - * the target class to at least {@code m1}.
  • - *
  • The lookup has the {@link Lookup#MODULE MODULE} lookup mode.
  • + *
  • If there is a security manager, its {@code checkPermission} method is + * called to check {@code ReflectPermission("suppressAccessChecks")} and + * that must return normally. + *
  • The caller lookup object must have the {@link Lookup#MODULE MODULE} lookup mode. + * (This is because otherwise there would be no way to ensure the original lookup + * creator was a member of any particular module, and so any subsequent checks + * for readability and qualified exports would become ineffective.) + *
  • The caller lookup object must have {@link Lookup#PRIVATE PRIVATE} access. + * (This is because an application intending to share intra-module access + * using {@link Lookup#MODULE MODULE} alone will inadvertently also share + * deep reflection to its own module.) + *
  • The target class must be a proper class, not a primitive or array class. + * (Thus, {@code M2} is well-defined.) + *
  • If the caller module {@code M1} differs from + * the target module {@code M2} then both of the following must be true: + *
      + *
    • {@code M1} {@link Module#canRead reads} {@code M2}.
    • + *
    • {@code M2} {@link Module#isOpen(String,Module) opens} the package + * containing the target class to at least {@code M1}.
    • + *
    *
*

- * If there is a security manager, its {@code checkPermission} method is called to - * check {@code ReflectPermission("suppressAccessChecks")}. - * @apiNote The {@code MODULE} lookup mode serves to authenticate that the lookup object - * was created by code in the caller module (or derived from a lookup object originally - * created by the caller). A lookup object with the {@code MODULE} lookup mode can be - * shared with trusted parties without giving away {@code PRIVATE} and {@code PACKAGE} - * access to the caller. + * If any of the above checks is violated, this method fails with an + * exception. + *

+ * Otherwise, if {@code M1} and {@code M2} are the same module, this method + * returns a {@code Lookup} on {@code targetClass} with full capabilities and + * {@code null} previous lookup class. + *

+ * Otherwise, {@code M1} and {@code M2} are two different modules. This method + * returns a {@code Lookup} on {@code targetClass} that records + * the lookup class of the caller as the new previous lookup class and + * drops {@code MODULE} access from the full capabilities mode. + * * @param targetClass the target class - * @param lookup the caller lookup object + * @param caller the caller lookup object * @return a lookup object for the target class, with private access - * @throws IllegalArgumentException if {@code targetClass} is a primitve type or array class + * @throws IllegalArgumentException if {@code targetClass} is a primitive type or array class * @throws NullPointerException if {@code targetClass} or {@code caller} is {@code null} - * @throws IllegalAccessException if the access check specified above fails * @throws SecurityException if denied by the security manager + * @throws IllegalAccessException if any of the other access checks specified above fails * @since 9 * @spec JPMS * @see Lookup#dropLookupMode + * @see Cross-module lookups */ - public static Lookup privateLookupIn(Class targetClass, Lookup lookup) throws IllegalAccessException { + public static Lookup privateLookupIn(Class targetClass, Lookup caller) throws IllegalAccessException { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(ACCESS_PERMISSION); if (targetClass.isPrimitive()) throw new IllegalArgumentException(targetClass + " is a primitive class"); if (targetClass.isArray()) throw new IllegalArgumentException(targetClass + " is an array class"); - Module targetModule = targetClass.getModule(); - Module callerModule = lookup.lookupClass().getModule(); - if (!callerModule.canRead(targetModule)) - throw new IllegalAccessException(callerModule + " does not read " + targetModule); - if (targetModule.isNamed()) { - String pn = targetClass.getPackageName(); - assert !pn.isEmpty() : "unnamed package cannot be in named module"; - if (!targetModule.isOpen(pn, callerModule)) - throw new IllegalAccessException(targetModule + " does not open " + pn + " to " + callerModule); + // Ensure that we can reason accurately about private and module access. + if ((caller.lookupModes() & Lookup.PRIVATE) == 0) + throw new IllegalAccessException("caller does not have PRIVATE lookup mode"); + if ((caller.lookupModes() & Lookup.MODULE) == 0) + throw new IllegalAccessException("caller does not have MODULE lookup mode"); + + // previous lookup class is never set if it has MODULE access + assert caller.previousLookupClass() == null; + + Class callerClass = caller.lookupClass(); + Module callerModule = callerClass.getModule(); // M1 + Module targetModule = targetClass.getModule(); // M2 + Class newPreviousClass = null; + int newModes = Lookup.FULL_POWER_MODES; + + if (targetModule != callerModule) { + if (!callerModule.canRead(targetModule)) + throw new IllegalAccessException(callerModule + " does not read " + targetModule); + if (targetModule.isNamed()) { + String pn = targetClass.getPackageName(); + assert !pn.isEmpty() : "unnamed package cannot be in named module"; + if (!targetModule.isOpen(pn, callerModule)) + throw new IllegalAccessException(targetModule + " does not open " + pn + " to " + callerModule); + } + + // M2 != M1, set previous lookup class to M1 and drop MODULE access + newPreviousClass = callerClass; + newModes &= ~Lookup.MODULE; } - if ((lookup.lookupModes() & Lookup.MODULE) == 0) - throw new IllegalAccessException("lookup does not have MODULE lookup mode"); + if (!callerModule.isNamed() && targetModule.isNamed()) { IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger(); if (logger != null) { - logger.logIfOpenedForIllegalAccess(lookup, targetClass); + logger.logIfOpenedForIllegalAccess(caller, targetClass); } } - return new Lookup(targetClass); + return Lookup.newLookup(targetClass, newPreviousClass, newModes); } /** @@ -533,6 +575,514 @@ * whose bytecode behaviors and Java language access permissions * can be reliably determined and emulated by method handles. * + *

Cross-module lookups

+ * When a lookup class in one module {@code M1} accesses a class in another module + * {@code M2}, extra access checking is performed beyond the access mode bits. + * A {@code Lookup} with {@link #PUBLIC} mode and a lookup class in {@code M1} + * can access public types in {@code M2} when {@code M2} is readable to {@code M1} + * and when the type is in a package of {@code M2} that is exported to + * at least {@code M1}. + *

+ * A {@code Lookup} on {@code C} can also teleport to a target class + * via {@link #in(Class) Lookup.in} and {@link MethodHandles#privateLookupIn(Class, Lookup) + * MethodHandles.privateLookupIn} methods. + * Teleporting across modules will always record the original lookup class as + * the {@linkplain #previousLookupClass() previous lookup class} + * and drops {@link Lookup#MODULE MODULE} access. + * If the target class is in the same module as the lookup class {@code C}, + * then the target class becomes the new lookup class + * and there is no change to the previous lookup class. + * If the target class is in a different module from {@code M1} ({@code C}'s module), + * {@code C} becomes the new previous lookup class + * and the target class becomes the new lookup class. + * In that case, if there was already a previous lookup class in {@code M0}, + * and it differs from {@code M1} and {@code M2}, then the resulting lookup + * drops all privileges. + * For example, + *

+     * {@code
+     * Lookup lookup = MethodHandles.lookup();   // in class C
+     * Lookup lookup2 = lookup.in(D.class);
+     * MethodHandle mh = lookup2.findStatic(E.class, "m", MT);
+     * }
+ *

+ * The {@link #lookup()} factory method produces a {@code Lookup} object + * with {@code null} previous lookup class. + * {@link Lookup#in lookup.in(D.class)} transforms the {@code lookup} on class {@code C} + * to class {@code D} without elevation of privileges. + * If {@code C} and {@code D} are in the same module, + * {@code lookup2} records {@code D} as the new lookup class and keeps the + * same previous lookup class as the original {@code lookup}, or + * {@code null} if not present. + *

+ * When a {@code Lookup} teleports from a class + * in one nest to another nest, {@code PRIVATE} access is dropped. + * When a {@code Lookup} teleports from a class in one package to + * another package, {@code PACKAGE} access is dropped. + * When a {@code Lookup} teleports from a class in one module to another module, + * {@code MODULE} access is dropped. + * Teleporting across modules drops the ability to access non-exported classes + * in both the module of the new lookup class and the module of the old lookup class + * and the resulting {@code Lookup} remains only {@code PUBLIC} access. + * A {@code Lookup} can teleport back and forth to a class in the module of + * the lookup class and the module of the previous class lookup. + * Teleporting across modules can only decrease access but cannot increase it. + * Teleporting to some third module drops all accesses. + *

+ * In the above example, if {@code C} and {@code D} are in different modules, + * {@code lookup2} records {@code D} as its lookup class and + * {@code C} as its previous lookup class and {@code lookup2} has only + * {@code PUBLIC} access. {@code lookup2} can teleport to other class in + * {@code C}'s module and {@code D}'s module. + * If class {@code E} is in a third module, {@code lookup2.in(E.class)} creates + * a {@code Lookup} on {@code E} with no access and {@code lookup2}'s lookup + * class {@code D} is recorded as its previous lookup class. + *

+ * Teleporting across modules restricts access to the public types that + * both the lookup class and the previous lookup class can equally access + * (see below). + *

+ * {@link MethodHandles#privateLookupIn(Class, Lookup) MethodHandles.privateLookupIn(T.class, lookup)} + * can be used to teleport a {@code lookup} from class {@code C} to class {@code T} + * and create a new {@code Lookup} with private access + * if the lookup class is allowed to do deep reflection on {@code T}. + * The {@code lookup} must have {@link #MODULE} and {@link #PRIVATE} access + * to call {@code privateLookupIn}. + * A {@code lookup} on {@code C} in module {@code M1} is allowed to do deep reflection + * on all classes in {@code M1}. If {@code T} is in {@code M1}, {@code privateLookupIn} + * produces a new {@code Lookup} on {@code T} with full capabilities. + * A {@code lookup} on {@code C} is also allowed + * to do deep reflection on {@code T} in another module {@code M2} if + * {@code M1} reads {@code M2} and {@code M2} {@link Module#isOpen(String,Module) opens} + * the package containing {@code T} to at least {@code M1}. + * {@code T} becomes the new lookup class and {@code C} becomes the new previous + * lookup class and {@code MODULE} access is dropped from the resulting {@code Lookup}. + * The resulting {@code Lookup} can be used to do member lookup or teleport + * to another lookup class by calling {@link #in Lookup::in}. But + * it cannot be used to obtain another private {@code Lookup} by calling + * {@link MethodHandles#privateLookupIn(Class, Lookup) privateLookupIn} + * because it has no {@code MODULE} access. + * + *

Cross-module access checks

+ * + * A {@code Lookup} with {@link #PUBLIC} or with {@link #UNCONDITIONAL} mode + * allows cross-module access. The access checking is performed with respect + * to both the lookup class and the previous lookup class if present. + *

+ * A {@code Lookup} with {@link #UNCONDITIONAL} mode can access public type + * in all modules when the type is in a package that is {@linkplain Module#isExported(String) + * exported unconditionally}. + *

+ * If a {@code Lookup} on {@code LC} in {@code M1} has no previous lookup class, + * the lookup with {@link #PUBLIC} mode can access all public types in modules + * that are readable to {@code M1} and the type is in a package that is exported + * at least to {@code M1}. + *

+ * If a {@code Lookup} on {@code LC} in {@code M1} has a previous lookup class + * {@code PLC} on {@code M0}, the lookup with {@link #PUBLIC} mode can access + * the intersection of all public types that are accessible to {@code M1} + * with all public types that are accessible to {@code M0}. {@code M0} + * reads {@code M1} and hence the set of accessible types includes: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * Public types in the following packages are accessible to the + * lookup class and the previous lookup class. + *
Equally accessible types to {@code M0} and {@code M1}
unconditional-exported packages from {@code M1}
unconditional-exported packages from {@code M0} if {@code M1} reads {@code M0}
unconditional-exported packages from a third module {@code M2} + * if both {@code M0} and {@code M1} read {@code M2}
qualified-exported packages from {@code M1} to {@code M0}
qualified-exported packages from {@code M0} to {@code M1} + * if {@code M1} reads {@code M0}
qualified-exported packages from a third module {@code M2} to + * both {@code M0} and {@code M1} if both {@code M0} and {@code M1} read {@code M2}
+ * + *

Access modes

+ * + * The table below shows the access modes of a {@code Lookup} produced by + * any of the following factory or transformation methods: + *
    + *
  • {@link #lookup() MethodHandles.lookup()}
  • + *
  • {@link #publicLookup() MethodHandles.publicLookup()}
  • + *
  • {@link #privateLookupIn(Class, Lookup) MethodHandles.privateLookupIn}
  • + *
  • {@link Lookup#in}
  • + *
  • {@link Lookup#dropLookupMode(int)}
  • + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * Access mode summary + *
Lookup objectprotectedprivatepackagemodulepublic
{@code CL = MethodHandles.lookup()} in {@code C}PROPRIPACMOD1R
{@code CL.in(C1)} same packagePACMOD1R
{@code CL.in(C1)} same moduleMOD1R
{@code CL.in(D)} different module2R
{@code CL.in(D).in(C)} hop back to module2R
{@code PRI1 = privateLookupIn(C1,CL)}PROPRIPACMOD1R
{@code PRI1a = privateLookupIn(C,PRI1)}PROPRIPACMOD1R
{@code PRI1.in(C1)} same packagePACMOD1R
{@code PRI1.in(C1)} different packageMOD1R
{@code PRI1.in(D)} different module2R
{@code PRI1.dropLookupMode(PROTECTED)}PRIPACMOD1R
{@code PRI1.dropLookupMode(PRIVATE)}PACMOD1R
{@code PRI1.dropLookupMode(PACKAGE)}MOD1R
{@code PRI1.dropLookupMode(MODULE)}1R
{@code PRI1.dropLookupMode(PUBLIC)}none
{@code PRI2 = privateLookupIn(D,CL)}PROPRIPAC2R
{@code privateLookupIn(D,PRI1)}PROPRIPAC2R
{@code privateLookupIn(C,PRI2)} failsIAE
{@code PRI2.in(D2)} same packagePAC2R
{@code PRI2.in(D2)} different package2R
{@code PRI2.in(C1)} hop back to module2R
{@code PRI2.in(E)} hop to third modulenone
{@code PRI2.dropLookupMode(PROTECTED)}PRIPAC2R
{@code PRI2.dropLookupMode(PRIVATE)}PAC2R
{@code PRI2.dropLookupMode(PACKAGE)}2R
{@code PRI2.dropLookupMode(MODULE)}2R
{@code PRI2.dropLookupMode(PUBLIC)}none
{@code CL.dropLookupMode(PROTECTED)}PRIPACMOD1R
{@code CL.dropLookupMode(PRIVATE)}PACMOD1R
{@code CL.dropLookupMode(PACKAGE)}MOD1R
{@code CL.dropLookupMode(MODULE)}1R
{@code CL.dropLookupMode(PUBLIC)}none
{@code PUB = publicLookup()}U
{@code PUB.in(D)} different moduleU
{@code PUB.in(D).in(E)} third moduleU
{@code PUB.dropLookupMode(UNCONDITIONAL)}none
{@code privateLookupIn(C1,PUB)} failsIAE
{@code ANY.in(X)}, for inaccessible Xnone
+ * + *

+ * Notes: + *

    + *
  • Class {@code C} and class {@code C1} are in module {@code M1}, + * but {@code D} and {@code D2} are in module {@code M2}, and {@code E} + * is in module {@code M3}. {@code X} stands for class which is inaccessible + * to the lookup. {@code ANY} stands for any of the example lookups.
  • + *
  • {@code PRO} indicates {@link #PROTECTED} bit set, + * {@code PRI} indicates {@link #PRIVATE} bit set, + * {@code PAC} indicates {@link #PACKAGE} bit set, + * {@code MOD} indicates {@link #MODULE} bit set, + * {@code 1R} and {@code 2R} indicate {@link #PUBLIC} bit set, + * {@code U} indicates {@link #UNCONDITIONAL} bit set, + * {@code IAE} indicates {@code IllegalAccessException} thrown.
  • + *
  • Public access comes in three kinds: + *
      + *
    • unconditional ({@code U}): the lookup assumes readability. + * The lookup has {@code null} previous lookup class. + *
    • one-module-reads ({@code 1R}): the module access checking is + * performed with respect to the lookup class. The lookup has {@code null} + * previous lookup class. + *
    • two-module-reads ({@code 2R}): the module access checking is + * performed with respect to the lookup class and the previous lookup class. + * The lookup has a non-null previous lookup class which is in a + * different module from the current lookup class. + *
    + *
  • Any attempt to reach a third module loses all access.
  • + *
  • If a target class {@code X} is not accessible to {@code Lookup::in} + * all access modes are dropped.
  • + *
+ * *

Security manager interactions

* Although bytecode instructions can only refer to classes in * a related class loader, this API can search for methods in any @@ -645,6 +1195,9 @@ /** The class on behalf of whom the lookup is being performed. */ private final Class lookupClass; + /** previous lookup class */ + private final Class prevLookupClass; + /** The allowed sorts of members which may be looked up (PUBLIC, etc.). */ private final int allowedModes; @@ -656,6 +1209,10 @@ * which may contribute to the result of {@link #lookupModes lookupModes}. * The value, {@code 0x01}, happens to be the same as the value of the * {@code public} {@linkplain java.lang.reflect.Modifier#PUBLIC modifier bit}. + *

+ * A {@code Lookup} with this lookup mode performs cross-module access check + * with respect to the {@linkplain #lookupClass() lookup class} and + * {@linkplain #previousLookupClass() previous lookup class} if present. */ public static final int PUBLIC = Modifier.PUBLIC; @@ -680,7 +1237,7 @@ */ public static final int PACKAGE = Modifier.STATIC; - /** A single-bit mask representing {@code module} access (default access), + /** A single-bit mask representing {@code module} access, * which may contribute to the result of {@link #lookupModes lookupModes}. * The value is {@code 0x10}, which does not correspond meaningfully to * any particular {@linkplain java.lang.reflect.Modifier modifier bit}. @@ -688,6 +1245,10 @@ * with this lookup mode can access all public types in the module of the * lookup class and public types in packages exported by other modules * to the module of the lookup class. + *

+ * If this lookup mode is set, the {@linkplain #previousLookupClass() + * previous lookup class} is always {@code null}. + * * @since 9 * @spec JPMS */ @@ -699,10 +1260,14 @@ * any particular {@linkplain java.lang.reflect.Modifier modifier bit}. * A {@code Lookup} with this lookup mode assumes {@linkplain * java.lang.Module#canRead(java.lang.Module) readability}. - * In conjunction with the {@code PUBLIC} modifier bit, a {@code Lookup} - * with this lookup mode can access all public members of public types - * of all modules where the type is in a package that is {@link + * This lookup mode can access all public members of public types + * of all modules when the type is in a package that is {@link * java.lang.Module#isExported(String) exported unconditionally}. + * + *

+ * If this lookup mode is set, the {@linkplain #previousLookupClass() + * previous lookup class} is always {@code null}. + * * @since 9 * @spec JPMS * @see #publicLookup() @@ -713,24 +1278,55 @@ private static final int FULL_POWER_MODES = (ALL_MODES & ~UNCONDITIONAL); private static final int TRUSTED = -1; + /* + * Adjust PUBLIC => PUBLIC|MODULE|UNCONDITIONAL + * Adjust 0 => PACKAGE + */ private static int fixmods(int mods) { mods &= (ALL_MODES - PACKAGE - MODULE - UNCONDITIONAL); - return (mods != 0) ? mods : (PACKAGE | MODULE | UNCONDITIONAL); + if (Modifier.isPublic(mods)) + mods |= UNCONDITIONAL; + return (mods != 0) ? mods : PACKAGE; } /** Tells which class is performing the lookup. It is this class against * which checks are performed for visibility and access permissions. *

+ * If this lookup object has a {@linkplain #previousLookupClass() previous lookup class}, + * access checks are performed against both the lookup class and the previous lookup class. + *

* The class implies a maximum level of access permission, * but the permissions may be additionally limited by the bitmask * {@link #lookupModes lookupModes}, which controls whether non-public members * can be accessed. * @return the lookup class, on behalf of which this lookup object finds members + * @see Cross-module lookups */ public Class lookupClass() { return lookupClass; } + /** Reports a lookup class in another module that this lookup object + * was previously teleported from, or {@code null}. + *

+ * A {@code Lookup} object produced by the factory methods, such as the + * {@link #lookup() lookup()} and {@link #publicLookup() publicLookup()} method, + * has {@code null} previous lookup class. + * A {@code Lookup} object has a non-null previous lookup class + * when this lookup was teleported from an old lookup class + * in one module to a new lookup class in another module. + * + * @return the lookup class in another module that this lookup object was + * previously teleported from, or {@code null} + * @since 14 + * @see #in(Class) + * @see MethodHandles#privateLookupIn(Class, Lookup) + * @see Cross-module lookups + */ + public Class previousLookupClass() { + return prevLookupClass; + } + // This is just for calling out to MethodHandleImpl. private Class lookupClassOrNull() { return (allowedModes == TRUSTED) ? null : lookupClass; @@ -774,48 +1370,69 @@ * which in turn is called by a method not in this package. */ Lookup(Class lookupClass) { - this(lookupClass, FULL_POWER_MODES); + this(lookupClass, null, FULL_POWER_MODES); // make sure we haven't accidentally picked up a privileged class: checkUnprivilegedlookupClass(lookupClass); } - private Lookup(Class lookupClass, int allowedModes) { + private Lookup(Class lookupClass, Class prevLookupClass, int allowedModes) { + assert prevLookupClass == null || ((allowedModes & MODULE) == 0 + && prevLookupClass.getModule() != lookupClass.getModule()); + this.lookupClass = lookupClass; + this.prevLookupClass = prevLookupClass; this.allowedModes = allowedModes; } + private static Lookup newLookup(Class lookupClass, Class prevLookupClass, int allowedModes) { + // make sure we haven't accidentally picked up a privileged class: + checkUnprivilegedlookupClass(lookupClass); + return new Lookup(lookupClass, prevLookupClass, allowedModes); + } + /** * Creates a lookup on the specified new lookup class. * The resulting object will report the specified * class as its own {@link #lookupClass() lookupClass}. + * *

* However, the resulting {@code Lookup} object is guaranteed * to have no more access capabilities than the original. * In particular, access capabilities can be lost as follows:

    - *
  • If the old lookup class is in a {@link Module#isNamed() named} module, and - * the new lookup class is in a different module {@code M}, then no members, not - * even public members in {@code M}'s exported packages, will be accessible. - * The exception to this is when this lookup is {@link #publicLookup() - * publicLookup}, in which case {@code PUBLIC} access is not lost. - *
  • If the old lookup class is in an unnamed module, and the new lookup class - * is a different module then {@link #MODULE MODULE} access is lost. - *
  • If the new lookup class differs from the old one then {@code UNCONDITIONAL} is lost. + *
  • If the new lookup class is in a different module from the old one, + * i.e. {@link #MODULE MODULE} access is lost. *
  • If the new lookup class is in a different package - * than the old one, protected and default (package) members will not be accessible. + * than the old one, protected and default (package) members will not be accessible, + * i.e. {@link #PROTECTED PROTECTED} and {@link #PACKAGE PACKAGE} access are lost. *
  • If the new lookup class is not within the same package member * as the old one, private members will not be accessible, and protected members - * will not be accessible by virtue of inheritance. + * will not be accessible by virtue of inheritance, + * i.e. {@link #PRIVATE PRIVATE} access is lost. * (Protected members may continue to be accessible because of package sharing.) - *
  • If the new lookup class is not accessible to the old lookup class, - * then no members, not even public members, will be accessible. - * (In all other cases, public members will continue to be accessible.) + *
  • If the new lookup class is not + * {@linkplain #accessClass(Class) accessible} to this lookup, + * then no members, not even public members, will be accessible + * i.e. all access modes are lost. + *
  • If the new lookup class, the old lookup class and the previous lookup class + * are all in different modules i.e. teleporting to a third module, + * all access modes are lost. *
*

+ * The new previous lookup class is chosen as follows: + *

    + *
  • If the new lookup object has {@link #UNCONDITIONAL UNCONDITIONAL} bit, + * the new previous lookup class is {@code null}. + *
  • If the new lookup class is in the same module as the old lookup class, + * the new previous lookup class is the old previous lookup class. + *
  • If the new lookup class is in a different module from the old lookup class, + * the new previous lookup class is the the old lookup class. + *
+ *

* The resulting lookup's capabilities for loading classes * (used during {@link #findClass} invocations) * are determined by the lookup class' loader, * which may change due to this operation. - * + *

* @param requestedLookupClass the desired lookup class for the new lookup object * @return a lookup object which reports the desired lookup class, or the same object * if there is no change @@ -823,22 +1440,32 @@ * * @revised 9 * @spec JPMS + * @see #accessClass(Class) + * @see Cross-module lookups */ public Lookup in(Class requestedLookupClass) { Objects.requireNonNull(requestedLookupClass); if (allowedModes == TRUSTED) // IMPL_LOOKUP can make any lookup at all - return new Lookup(requestedLookupClass, FULL_POWER_MODES); + return new Lookup(requestedLookupClass, null, FULL_POWER_MODES); if (requestedLookupClass == this.lookupClass) return this; // keep same capabilities int newModes = (allowedModes & FULL_POWER_MODES); - if (!VerifyAccess.isSameModule(this.lookupClass, requestedLookupClass)) { - // Need to drop all access when teleporting from a named module to another - // module. The exception is publicLookup where PUBLIC is not lost. - if (this.lookupClass.getModule().isNamed() - && (this.allowedModes & UNCONDITIONAL) == 0) + Module fromModule = this.lookupClass.getModule(); + Module targetModule = requestedLookupClass.getModule(); + Class plc = this.previousLookupClass(); + if ((this.allowedModes & UNCONDITIONAL) != 0) { + assert plc == null; + newModes = UNCONDITIONAL; + } else if (fromModule != targetModule) { + if (plc != null && !VerifyAccess.isSameModule(plc, requestedLookupClass)) { + // allow hopping back and forth between fromModule and plc's module + // but not the third module newModes = 0; - else - newModes &= ~(MODULE|PACKAGE|PRIVATE|PROTECTED); + } + // drop MODULE access + newModes &= ~(MODULE|PACKAGE|PRIVATE|PROTECTED); + // teleport from this lookup class + plc = this.lookupClass; } if ((newModes & PACKAGE) != 0 && !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) { @@ -849,29 +1476,39 @@ && !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) { newModes &= ~(PRIVATE|PROTECTED); } - if ((newModes & PUBLIC) != 0 - && !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass, allowedModes)) { + if ((newModes & (PUBLIC|UNCONDITIONAL)) != 0 + && !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass, this.prevLookupClass, allowedModes)) { // The requested class it not accessible from the lookup class. // No permissions. newModes = 0; } - - checkUnprivilegedlookupClass(requestedLookupClass); - return new Lookup(requestedLookupClass, newModes); + return newLookup(requestedLookupClass, plc, newModes); } - /** * Creates a lookup on the same lookup class which this lookup object * finds members, but with a lookup mode that has lost the given lookup mode. * The lookup mode to drop is one of {@link #PUBLIC PUBLIC}, {@link #MODULE * MODULE}, {@link #PACKAGE PACKAGE}, {@link #PROTECTED PROTECTED} or {@link #PRIVATE PRIVATE}. - * {@link #PROTECTED PROTECTED} and {@link #UNCONDITIONAL UNCONDITIONAL} are always - * dropped and so the resulting lookup mode will never have these access capabilities. + * {@link #PROTECTED PROTECTED} is always + * dropped and so the resulting lookup mode will never have this access capability. * When dropping {@code PACKAGE} then the resulting lookup will not have {@code PACKAGE} * or {@code PRIVATE} access. When dropping {@code MODULE} then the resulting lookup will * not have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code PUBLIC} + * is dropped then the resulting lookup has no access. If {@code UNCONDITIONAL} * is dropped then the resulting lookup has no access. + * + * @apiNote + * A lookup with {@code PACKAGE} but not {@code PRIVATE} mode can safely + * delegate non-public access within the package of the lookup class without + * conferring private access. A lookup with {@code MODULE} but not + * {@code PACKAGE} mode can safely delegate {@code PUBLIC} access within + * the module of the lookup class without conferring package access. + * A lookup with a {@linkplain #previousLookupClass() previous lookup class} + * (and {@code PUBLIC} but not {@code MODULE} mode) can safely delegate access + * to public classes accessible to both the module of the lookup class + * and the module of the previous lookup class. + * * @param modeToDrop the lookup mode to drop * @return a lookup object which lacks the indicated mode, or the same object if there is no change * @throws IllegalArgumentException if {@code modeToDrop} is not one of {@code PUBLIC}, @@ -881,9 +1518,9 @@ */ public Lookup dropLookupMode(int modeToDrop) { int oldModes = lookupModes(); - int newModes = oldModes & ~(modeToDrop | PROTECTED | UNCONDITIONAL); + int newModes = oldModes & ~(modeToDrop | PROTECTED); switch (modeToDrop) { - case PUBLIC: newModes &= ~(ALL_MODES); break; + case PUBLIC: newModes &= ~(FULL_POWER_MODES); break; case MODULE: newModes &= ~(PACKAGE | PRIVATE); break; case PACKAGE: newModes &= ~(PRIVATE); break; case PROTECTED: @@ -892,7 +1529,7 @@ default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop"); } if (newModes == oldModes) return this; // return self if no change - return new Lookup(lookupClass(), newModes); + return newLookup(lookupClass(), previousLookupClass(), newModes); } /** @@ -997,13 +1634,13 @@ static { IMPL_NAMES.getClass(); } /** Package-private version of lookup which is trusted. */ - static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED); + static final Lookup IMPL_LOOKUP = new Lookup(Object.class, null, TRUSTED); /** Version of lookup which is trusted minimally. * It can only be used to create method handles to publicly accessible * members in packages that are exported unconditionally. */ - static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, (PUBLIC|UNCONDITIONAL)); + static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, null, UNCONDITIONAL); private static void checkUnprivilegedlookupClass(Class lookupClass) { String name = lookupClass.getName(); @@ -1013,6 +1650,8 @@ /** * Displays the name of the class from which lookups are to be made. + * followed with "/" and the name of the {@linkplain #previousLookupClass() + * previous lookup class} if present. * (The name is the one reported by {@link java.lang.Class#getName() Class.getName}.) * If there are restrictions on the access permitted to this lookup, * this is indicated by adding a suffix to the class name, consisting @@ -1020,14 +1659,14 @@ * allowed access, and is chosen as follows: *

    *
  • If no access is allowed, the suffix is "/noaccess". + *
  • If only unconditional access is allowed, the suffix is "/publicLookup". *
  • If only public access to types in exported packages is allowed, the suffix is "/public". - *
  • If only public access and unconditional access are allowed, the suffix is "/publicLookup". *
  • If only public and module access are allowed, the suffix is "/module". - *
  • If only public, module and package access are allowed, the suffix is "/package". - *
  • If only public, module, package, and private access are allowed, the suffix is "/private". + *
  • If public and package access are allowed, the suffix is "/package". + *
  • If public, package, and private access are allowed, the suffix is "/private". *
- * If none of the above cases apply, it is the case that full - * access (public, module, package, private, and protected) is allowed. + * If none of the above cases apply, it is the case that full access + * (public, module, package, private, and protected) is allowed. * In this case, no suffix is added. * This is true only of an object obtained originally from * {@link java.lang.invoke.MethodHandles#lookup MethodHandles.lookup}. @@ -1047,20 +1686,25 @@ @Override public String toString() { String cname = lookupClass.getName(); + if (prevLookupClass != null) + cname += "/" + prevLookupClass.getName(); switch (allowedModes) { case 0: // no privileges return cname + "/noaccess"; + case UNCONDITIONAL: + return cname + "/publicLookup"; case PUBLIC: return cname + "/public"; - case PUBLIC|UNCONDITIONAL: - return cname + "/publicLookup"; case PUBLIC|MODULE: return cname + "/module"; + case PUBLIC|PACKAGE: case PUBLIC|MODULE|PACKAGE: return cname + "/package"; - case FULL_POWER_MODES & ~PROTECTED: - return cname + "/private"; + case FULL_POWER_MODES & (~PROTECTED): + case FULL_POWER_MODES & ~(PROTECTED|MODULE): + return cname + "/private"; case FULL_POWER_MODES: + case FULL_POWER_MODES & (~MODULE): return cname; case TRUSTED: return "/trusted"; // internal only; not exported @@ -1301,24 +1945,75 @@ } /** - * Determines if a class can be accessed from the lookup context defined by this {@code Lookup} object. The - * static initializer of the class is not run. + * Determines if a class can be accessed from the lookup context defined by + * this {@code Lookup} object. The static initializer of the class is not run. + *

+ * If the {@code targetClass} is in the same module as the lookup class, + * the lookup class is {@code LC} in module {@code M1} and + * the previous lookup class is in module {@code M0} or + * {@code null} if not present, + * {@code targetClass} is accessible if and only if one of the following is true: + *

    + *
  • If this lookup has {@link #PRIVATE} access, {@code targetClass} is + * {@code LC} or other class in the same nest of {@code LC}.
  • + *
  • If this lookup has {@link #PACKAGE} access, {@code targetClass} is + * in the same runtime package of {@code LC}.
  • + *
  • If this lookup has {@link #MODULE} access, {@code targetClass} is + * a public type in {@code M1}.
  • + *
  • If this lookup has {@link #PUBLIC} access, {@code targetClass} is + * a public type in a package exported by {@code M1} to at least {@code M0} + * if the previous lookup class is present; otherwise, {@code targetClass} + * is a public type in a package exported by {@code M1} unconditionally.
  • + *
+ * + *

+ * Otherwise, if this lookup has {@link #UNCONDITIONAL} access, this lookup + * can access public types in all modules when the type is in a package + * that is exported unconditionally. *

- * The lookup context here is determined by the {@linkplain #lookupClass() lookup class} and the - * {@linkplain #lookupModes() lookup modes}. + * Otherwise, the target class is in a different module from {@code lookupClass}, + * and if this lookup does not have {@code PUBLIC} access, {@code lookupClass} + * is inaccessible. + *

+ * Otherwise, if this lookup has no {@linkplain #previousLookupClass() previous lookup class}, + * {@code M1} is the module containing {@code lookupClass} and + * {@code M2} is the module containing {@code targetClass}, + * then {@code targetClass} is accessible if and only if + *

    + *
  • {@code M1} reads {@code M2}, and + *
  • {@code targetClass} is public and in a package exported by + * {@code M2} at least to {@code M1}. + *
+ *

+ * Otherwise, if this lookup has a {@linkplain #previousLookupClass() previous lookup class}, + * {@code M1} and {@code M2} are as before, and {@code M0} is the module + * containing the previous lookup class, then {@code targetClass} is accessible + * if and only if one of the following is true: + *

    + *
  • {@code targetClass} is in {@code M0} and {@code M1} + * {@linkplain Module#reads reads} {@code M0} and the type is + * in a package that is exported to at least {@code M1}. + *
  • {@code targetClass} is in {@code M1} and {@code M0} + * {@linkplain Module#reads reads} {@code M1} and the type is + * in a package that is exported to at least {@code M0}. + *
  • {@code targetClass} is in a third module {@code M2} and both {@code M0} + * and {@code M1} reads {@code M2} and the type is in a package + * that is exported to at least both {@code M0} and {@code M2}. + *
+ *

+ * Otherwise, {@code targetClass} is not accessible. * * @param targetClass the class to be access-checked - * * @return the class that has been access-checked - * - * @throws IllegalAccessException if the class is not accessible from the lookup class, using the allowed access - * modes. + * @throws IllegalAccessException if the class is not accessible from the lookup class + * and previous lookup class, if present, using the allowed access modes. * @exception SecurityException if a security manager is present and it * refuses access * @since 9 + * @see Cross-module lookups */ public Class accessClass(Class targetClass) throws IllegalAccessException { - if (!VerifyAccess.isClassAccessible(targetClass, lookupClass, allowedModes)) { + if (!VerifyAccess.isClassAccessible(targetClass, lookupClass, prevLookupClass, allowedModes)) { throw new MemberName(targetClass).makeAccessException("access violation", this); } checkSecurityManager(targetClass, null); @@ -2083,7 +2778,7 @@ boolean isClassAccessible(Class refc) { Objects.requireNonNull(refc); Class caller = lookupClassOrNull(); - return caller == null || VerifyAccess.isClassAccessible(refc, caller, allowedModes); + return caller == null || VerifyAccess.isClassAccessible(refc, caller, prevLookupClass, allowedModes); } /** Check name for an illegal leading "<" character. */ @@ -2220,7 +2915,7 @@ int requestedModes = fixmods(mods); // adjust 0 => PACKAGE if ((requestedModes & allowedModes) != 0) { if (VerifyAccess.isMemberAccessible(refc, m.getDeclaringClass(), - mods, lookupClass(), allowedModes)) + mods, lookupClass(), previousLookupClass(), allowedModes)) return; } else { // Protected members can also be checked as if they were package-private. @@ -2239,9 +2934,10 @@ (defc == refc || Modifier.isPublic(refc.getModifiers()))); if (!classOK && (allowedModes & PACKAGE) != 0) { - classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), FULL_POWER_MODES) && + // ignore previous lookup class to check if default package access + classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), null, FULL_POWER_MODES) && (defc == refc || - VerifyAccess.isClassAccessible(refc, lookupClass(), FULL_POWER_MODES))); + VerifyAccess.isClassAccessible(refc, lookupClass(), null, FULL_POWER_MODES))); } if (!classOK) return "class is not public"; diff -r 70865ef2afc7 -r b0aaa82a1b03 src/java.base/share/classes/sun/invoke/util/VerifyAccess.java --- a/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java Wed Jul 24 12:49:44 2019 +0530 +++ b/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java Thu Jul 25 12:23:54 2019 +0530 @@ -88,18 +88,20 @@ * @param defc the class in which the proposed member is actually defined * @param mods modifier flags for the proposed member * @param lookupClass the class for which the access check is being made + * @param prevLookupClass the class for which the access check is being made + * @param allowedModes allowed modes * @return true iff the accessing class can access such a member */ public static boolean isMemberAccessible(Class refc, // symbolic ref class Class defc, // actual def class int mods, // actual member mods Class lookupClass, + Class prevLookupClass, int allowedModes) { if (allowedModes == 0) return false; - assert((allowedModes & PUBLIC) != 0 && - (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0); + assert((allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0); // The symbolic reference class (refc) must always be fully verified. - if (!isClassAccessible(refc, lookupClass, allowedModes)) { + if (!isClassAccessible(refc, lookupClass, prevLookupClass, allowedModes)) { return false; } // Usually refc and defc are the same, but verify defc also in case they differ. @@ -109,6 +111,7 @@ switch (mods & ALL_ACCESS_MODES) { case PUBLIC: + assert (allowedModes & PUBLIC) != 0 || (allowedModes & UNCONDITIONAL_ALLOWED) != 0; return true; // already checked above case PROTECTED: assert !defc.isInterface(); // protected members aren't allowed in interfaces @@ -175,14 +178,23 @@ * package that is exported to the module that contains D. *

  • C and D are members of the same runtime package. * + * * @param refc the symbolic reference class to which access is being checked (C) * @param lookupClass the class performing the lookup (D) + * @param prevLookupClass the class from which the lookup was teleported or null + * @param allowedModes allowed modes */ - public static boolean isClassAccessible(Class refc, Class lookupClass, + public static boolean isClassAccessible(Class refc, + Class lookupClass, + Class prevLookupClass, int allowedModes) { if (allowedModes == 0) return false; - assert((allowedModes & PUBLIC) != 0 && - (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0); + assert((allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0); + + if ((allowedModes & PACKAGE_ALLOWED) != 0 && + isSamePackage(lookupClass, refc)) + return true; + int mods = getClassModifiers(refc); if (isPublic(mods)) { @@ -195,37 +207,62 @@ return true; } - // trivially allow - if ((allowedModes & MODULE_ALLOWED) != 0 && - (lookupModule == refModule)) + // allow access to public types in all unconditionally exported packages + if ((allowedModes & UNCONDITIONAL_ALLOWED) != 0) { + return refModule.isExported(refc.getPackageName()); + } + + if (lookupModule == refModule && prevLookupClass == null) { + // allow access to all public types in lookupModule + if ((allowedModes & MODULE_ALLOWED) != 0) + return true; + + assert (allowedModes & PUBLIC) != 0; + return refModule.isExported(refc.getPackageName()); + } + + // cross-module access + // 1. refc is in different module from lookupModule, or + // 2. refc is in lookupModule and a different module from prevLookupModule + Module prevLookupModule = prevLookupClass != null ? prevLookupClass.getModule() + : null; + assert refModule != lookupModule || refModule != prevLookupModule; + if (isModuleAccessible(refc, lookupModule, prevLookupModule)) return true; - // check readability when UNCONDITIONAL not allowed - if (((allowedModes & UNCONDITIONAL_ALLOWED) != 0) - || lookupModule.canRead(refModule)) { - - // check that refc is in an exported package - if ((allowedModes & MODULE_ALLOWED) != 0) { - if (refModule.isExported(refc.getPackageName(), lookupModule)) - return true; - } else { - // exported unconditionally - if (refModule.isExported(refc.getPackageName())) - return true; - } - - // not exported but allow access during VM initialization - // because java.base does not have its exports setup - if (!jdk.internal.misc.VM.isModuleSystemInited()) - return true; - } + // not exported but allow access during VM initialization + // because java.base does not have its exports setup + if (!jdk.internal.misc.VM.isModuleSystemInited()) + return true; // public class not accessible to lookupClass return false; } - if ((allowedModes & PACKAGE_ALLOWED) != 0 && - isSamePackage(lookupClass, refc)) - return true; + + return false; + } + + /* + * Tests if a class or interface REFC is accessible to m1 and m2 where m2 + * may be null. + * + * A class or interface REFC in m is accessible to m1 and m2 if and only if + * both m1 and m2 read m and m exports the package of REFC at least to + * both m1 and m2. + */ + public static boolean isModuleAccessible(Class refc, Module m1, Module m2) { + Module refModule = refc.getModule(); + assert refModule != m1 || refModule != m2; + int mods = getClassModifiers(refc); + if (isPublic(mods)) { + if (m1.canRead(refModule) && (m2 == null || m2.canRead(refModule))) { + String pn = refc.getPackageName(); + + // refc is exported package to at least both m1 and m2 + if (refModule.isExported(pn, m1) && (m2 == null || refModule.isExported(pn, m2))) + return true; + } + } return false; } diff -r 70865ef2afc7 -r b0aaa82a1b03 test/hotspot/jtreg/gc/g1/TestNoUseHCC.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/gc/g1/TestNoUseHCC.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,48 @@ +/* + * 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. + */ + +package gc.g1; + +/* + * @test TestNoUseHCC + * @summary Check that G1 survives a GC without HCC enabled + * @requires vm.gc.G1 + * @key gc + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @build sun.hotspot.WhiteBox + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -Xlog:gc+phases=debug -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC -Xmx64M -XX:G1ConcRSLogCacheSize=0 gc.g1.TestNoUseHCC + */ + +import sun.hotspot.WhiteBox; + +public class TestNoUseHCC { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public static void main(String [] args) { + WB.youngGC(); + } +} + diff -r 70865ef2afc7 -r b0aaa82a1b03 test/hotspot/jtreg/runtime/condy/staticInit/Example.jasm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/condy/staticInit/Example.jasm Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,65 @@ +/* + * 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. + */ + +// This class gets an initialization error in a condy invokestatic. Need jasm so that StaticInit isn't +// initialized before the condy call. +// Test that second invocation gets same error as first. + +public class Example + version 55:0 +{ + + +static Method $jacocoInit:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;" + stack 1 locals 3 +{ + invokestatic Method StaticInit.get:"()Ljava/lang/Object;"; + areturn; +} + +public static Method foo:"()V" + stack 1 locals 2 +{ + ldc Dynamic REF_invokeStatic:Example.$jacocoInit:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;":$jacocoData:"Ljava/lang/Object;"; + astore_1; + return; +} + +public static Method main:"([Ljava/lang/String;)V" + stack 1 locals 2 +{ + try t0; + invokestatic Method Example.foo:"()V"; + endtry t0; + goto L7; + catch t0 java/lang/Error; + stack_frame_type stack1; + stack_map class java/lang/Error; + astore_1; + aload_1; + invokevirtual Method java/lang/Error.printStackTrace:"()V"; + L7: stack_frame_type same; + invokestatic Method Example.foo:"()V"; + return; +} +} // end Class Example diff -r 70865ef2afc7 -r b0aaa82a1b03 test/hotspot/jtreg/runtime/condy/staticInit/StaticInit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/condy/staticInit/StaticInit.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,33 @@ +/* + * 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. + */ + +class StaticInit { + static { + if (true) + throw new RuntimeException(); + } + + static Object get() { + return new Object(); + } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/hotspot/jtreg/runtime/condy/staticInit/TestInitException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/condy/staticInit/TestInitException.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,53 @@ +/* + * 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 8228485 + * @summary Correctly handle initialization error for Condy BSM. + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @compile Example.jasm + * @compile StaticInit.java + * @run main/othervm TestInitException + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestInitException { + public static void main(java.lang.String[] unused) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("Example"); + OutputAnalyzer oa = new OutputAnalyzer(pb.start()); + // First call stack trace + oa.shouldContain("at Example.$jacocoInit(Example.jasm)"); + oa.shouldContain("Caused by: java.lang.RuntimeException"); + oa.shouldContain("at StaticInit.(StaticInit.java:27)"); + // Second call stack trace, with the message + oa.shouldContain("java.lang.ExceptionInInitializerError: $jacocoData"); + oa.shouldContain("at Example.foo(Example.jasm)"); + oa.shouldContain("at Example.main(Example.jasm)"); + oa.shouldHaveExitValue(1); + } +} + diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/ProblemList.txt diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/AccessControlTest.java --- a/test/jdk/java/lang/invoke/AccessControlTest.java Wed Jul 24 12:49:44 2019 +0530 +++ b/test/jdk/java/lang/invoke/AccessControlTest.java Thu Jul 25 12:23:54 2019 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -33,7 +33,6 @@ import java.lang.reflect.*; import java.lang.reflect.Modifier; import java.util.*; -import org.testng.*; import org.testng.annotations.*; import static java.lang.invoke.MethodHandles.*; @@ -62,23 +61,28 @@ private class LookupCase implements Comparable { final Lookup lookup; final Class lookupClass; + final Class prevLookupClass; final int lookupModes; public LookupCase(Lookup lookup) { this.lookup = lookup; this.lookupClass = lookup.lookupClass(); + this.prevLookupClass = lookup.previousLookupClass(); this.lookupModes = lookup.lookupModes(); + assert(lookupString().equals(lookup.toString())); numberOf(lookupClass().getClassLoader()); // assign CL# } - public LookupCase(Class lookupClass, int lookupModes) { + public LookupCase(Class lookupClass, Class prevLookupClass, int lookupModes) { this.lookup = null; this.lookupClass = lookupClass; + this.prevLookupClass = prevLookupClass; this.lookupModes = lookupModes; numberOf(lookupClass().getClassLoader()); // assign CL# } - public final Class lookupClass() { return lookupClass; } - public final int lookupModes() { return lookupModes; } + public final Class lookupClass() { return lookupClass; } + public final Class prevLookupClass() { return prevLookupClass; } + public final int lookupModes() { return lookupModes; } public Lookup lookup() { lookup.getClass(); return lookup; } @@ -86,12 +90,24 @@ public int compareTo(LookupCase that) { Class c1 = this.lookupClass(); Class c2 = that.lookupClass(); + Class p1 = this.prevLookupClass(); + Class p2 = that.prevLookupClass(); if (c1 != c2) { int cmp = c1.getName().compareTo(c2.getName()); if (cmp != 0) return cmp; cmp = numberOf(c1.getClassLoader()) - numberOf(c2.getClassLoader()); assert(cmp != 0); return cmp; + } else if (p1 != p2){ + if (p1 == null) + return 1; + else if (p2 == null) + return -1; + int cmp = p1.getName().compareTo(p2.getName()); + if (cmp != 0) return cmp; + cmp = numberOf(p1.getClassLoader()) - numberOf(p2.getClassLoader()); + assert(cmp != 0); + return cmp; } return -(this.lookupModes() - that.lookupModes()); } @@ -102,6 +118,7 @@ } public boolean equals(LookupCase that) { return (this.lookupClass() == that.lookupClass() && + this.prevLookupClass() == that.prevLookupClass() && this.lookupModes() == that.lookupModes()); } @@ -113,20 +130,25 @@ /** Simulate all assertions in the spec. for Lookup.toString. */ private String lookupString() { String name = lookupClass.getName(); + if (prevLookupClass != null) + name += "/" + prevLookupClass.getName(); String suffix = ""; if (lookupModes == 0) suffix = "/noaccess"; else if (lookupModes == PUBLIC) suffix = "/public"; - else if (lookupModes == (PUBLIC|UNCONDITIONAL)) + else if (lookupModes == UNCONDITIONAL) suffix = "/publicLookup"; else if (lookupModes == (PUBLIC|MODULE)) suffix = "/module"; - else if (lookupModes == (PUBLIC|MODULE|PACKAGE)) + else if (lookupModes == (PUBLIC|PACKAGE) + || lookupModes == (PUBLIC|MODULE|PACKAGE)) suffix = "/package"; - else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE)) + else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE) + || lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE)) suffix = "/private"; - else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED)) + else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE|PROTECTED) + || lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED)) suffix = ""; else suffix = "/#"+Integer.toHexString(lookupModes); @@ -138,41 +160,50 @@ * Creates a lookup on the specified new lookup class. * [A1] The resulting object will report the specified * class as its own {@link #lookupClass lookupClass}. - *

    * [A2] However, the resulting {@code Lookup} object is guaranteed * to have no more access capabilities than the original. * In particular, access capabilities can be lost as follows:

      - *
    • [A3] If the old lookup class is in a named module, and the new - * lookup class is in a different module {@code M}, then no members, not - * even public members in {@code M}'s exported packages, will be accessible. - * The exception to this is when this lookup is publicLookup, in which case - * public access is not lost. - *
    • [A4] If the old lookup class is in an unnamed module, and the new - * lookup class is a different module then module access is lost. - *
    • [A5] If the new lookup class differs from the old one then UNCONDITIONAL - * is lost. If the new lookup class is not within the same package member as the - * old one, protected members will not be accessible by virtue of inheritance. + * [A3] If the new lookup class is in a different module from the old one, + * i.e. {@link #MODULE MODULE} access is lost. + * [A4] If the new lookup class is in a different package + * than the old one, protected and default (package) members will not be accessible, + * i.e. {@link #PROTECTED PROTECTED} and {@link #PACKAGE PACKAGE} access are lost. + * [A5] If the new lookup class is not within the same package member + * as the old one, private members will not be accessible, and protected members + * will not be accessible by virtue of inheritance, + * i.e. {@link #PRIVATE PRIVATE} access is lost. * (Protected members may continue to be accessible because of package sharing.) - *
    • [A6] If the new lookup class is in a different package than the old one, - * protected and default (package) members will not be accessible. - *
    • [A7] If the new lookup class is not within the same package member - * as the old one, private members will not be accessible. - *
    • [A8] If the new lookup class is not accessible to the old lookup class, - * then no members, not even public members, will be accessible. - *
    • [A9] (In all other cases, public members will continue to be accessible.) - *
    + * [A6] If the new lookup class is not + * {@linkplain #accessClass(Class) accessible} to this lookup, + * then no members, not even public members, will be accessible + * i.e. all access modes are lost. + * [A7] If the new lookup class, the old lookup class and the previous lookup class + * are all in different modules i.e. teleporting to a third module, + * all access modes are lost. + *

    + * The new previous lookup class is chosen as follows: + * [A8] If the new lookup object has {@link #UNCONDITIONAL UNCONDITIONAL} bit, + * the new previous lookup class is {@code null}. + * [A9] If the new lookup class is in the same module as the old lookup class, + * the new previous lookup class is the old previous lookup class. + * [A10] If the new lookup class is in a different module from the old lookup class, + * the new previous lookup class is the the old lookup class. + * * Other than the above cases, the new lookup will have the same - * access capabilities as the original. [A10] + * access capabilities as the original. [A11] *


    */ public LookupCase in(Class c2) { Class c1 = lookupClass(); - int m1 = lookupModes(); + Module m1 = c1.getModule(); + Module m2 = c2.getModule(); + Module m0 = prevLookupClass() != null ? prevLookupClass.getModule() : c1.getModule(); + int modes1 = lookupModes(); int changed = 0; // for the purposes of access control then treat classes in different unnamed // modules as being in the same module. - boolean sameModule = (c1.getModule() == c2.getModule()) || - (!c1.getModule().isNamed() && !c2.getModule().isNamed()); + boolean sameModule = (m1 == m2) || + (!m1.isNamed() && !m2.isNamed()); boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() && c1.getPackageName().equals(c2.getPackageName())); boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2)); @@ -180,40 +211,85 @@ assert(samePackage || !sameTopLevel); assert(sameTopLevel || !sameClass); boolean accessible = sameClass; - if ((m1 & PACKAGE) != 0) accessible |= samePackage; - if ((m1 & PUBLIC ) != 0) accessible |= (c2.getModifiers() & PUBLIC) != 0; - if (!sameModule) { - if (c1.getModule().isNamed() && (m1 & UNCONDITIONAL) == 0) { - accessible = false; // [A3] - } else { - changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED); // [A3] [A4] - } + + if ((modes1 & PACKAGE) != 0) accessible |= samePackage; + if ((modes1 & PUBLIC ) != 0) { + if (isModuleAccessible(c2)) + accessible |= (c2.getModifiers() & PUBLIC) != 0; + else + accessible = false; + } + if ((modes1 & UNCONDITIONAL) != 0) { + if (m2.isExported(c2.getPackageName())) + accessible |= (c2.getModifiers() & PUBLIC) != 0; + else + accessible = false; } if (!accessible) { - // Different package and no access to c2; lose all access. - changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED); // [A8] + // no access to c2; lose all access. + changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED|UNCONDITIONAL); // [A6] + } + if (m2 != m1 && m0 != m1) { + // hop to a third module; lose all access + changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED); // [A7] + } + if (!sameModule) { + changed |= MODULE; // [A3] } if (!samePackage) { // Different package; loose PACKAGE and lower access. - changed |= (PACKAGE|PRIVATE|PROTECTED); // [A6] + changed |= (PACKAGE|PRIVATE|PROTECTED); // [A4] } if (!sameTopLevel) { // Different top-level class. Lose PRIVATE and PROTECTED access. - changed |= (PRIVATE|PROTECTED); // [A5] [A7] + changed |= (PRIVATE|PROTECTED); // [A5] } - if (!sameClass) { - changed |= (UNCONDITIONAL); // [A5] - } else { - assert(changed == 0); // [A10] (no deprivation if same class) + if (sameClass) { + assert(changed == 0); // [A11] (no deprivation if same class) } - if (accessible) assert((changed & PUBLIC) == 0); // [A9] - int m2 = m1 & ~changed; - LookupCase l2 = new LookupCase(c2, m2); - assert(l2.lookupClass() == c2); // [A1] - assert((m1 | m2) == m1); // [A2] (no elevation of access) + + if (accessible) assert((changed & PUBLIC) == 0); + int modes2 = modes1 & ~changed; + Class plc = (m1 == m2) ? prevLookupClass() : c1; // [A9] [A10] + if ((modes1 & UNCONDITIONAL) != 0) plc = null; // [A8] + LookupCase l2 = new LookupCase(c2, plc, modes2); + assert(l2.lookupClass() == c2); // [A1] + assert((modes1 | modes2) == modes1); // [A2] (no elevation of access) + assert(l2.prevLookupClass() == null || (modes2 & MODULE) == 0); return l2; } + LookupCase dropLookupMode(int modeToDrop) { + int oldModes = lookupModes(); + int newModes = oldModes & ~(modeToDrop | PROTECTED); + switch (modeToDrop) { + case PUBLIC: newModes &= ~(MODULE|PACKAGE|PROTECTED|PRIVATE); break; + case MODULE: newModes &= ~(PACKAGE|PRIVATE); break; + case PACKAGE: newModes &= ~(PRIVATE); break; + case PROTECTED: + case PRIVATE: + case UNCONDITIONAL: break; + default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop"); + } + if (newModes == oldModes) return this; // return self if no change + LookupCase l2 = new LookupCase(lookupClass(), prevLookupClass(), newModes); + assert((oldModes | newModes) == oldModes); // [A2] (no elevation of access) + assert(l2.prevLookupClass() == null || (newModes & MODULE) == 0); + return l2; + } + + boolean isModuleAccessible(Class c) { + Module m1 = lookupClass().getModule(); + Module m2 = c.getModule(); + Module m0 = prevLookupClass() != null ? prevLookupClass.getModule() : m1; + String pn = c.getPackageName(); + boolean accessible = m1.canRead(m2) && m2.isExported(pn, m1); + if (m1 != m0) { + accessible = accessible && m0.canRead(m2) && m2.isExported(pn, m0); + } + return accessible; + } + @Override public String toString() { String s = lookupClass().getSimpleName(); @@ -229,33 +305,48 @@ public boolean willAccess(Method m) { Class c1 = lookupClass(); Class c2 = m.getDeclaringClass(); + Module m1 = c1.getModule(); + Module m2 = c2.getModule(); + Module m0 = prevLookupClass != null ? prevLookupClass.getModule() : m1; + // unconditional has access to all public types/members of types that is in a package + // are unconditionally exported + if ((lookupModes & UNCONDITIONAL) != 0) { + return m2.isExported(c2.getPackageName()) + && Modifier.isPublic(c2.getModifiers()) + && Modifier.isPublic(m.getModifiers()); + } - // publicLookup has access to all public types/members of types in unnamed modules - if ((lookupModes & UNCONDITIONAL) != 0 - && (lookupModes & PUBLIC) != 0 - && !c2.getModule().isNamed() - && Modifier.isPublic(c2.getModifiers()) - && Modifier.isPublic(m.getModifiers())) - return true; + // c1 and c2 are in different module + if (m1 != m2 || m0 != m2) { + return (lookupModes & PUBLIC) != 0 + && isModuleAccessible(c2) + && Modifier.isPublic(c2.getModifiers()) + && Modifier.isPublic(m.getModifiers()); + } + + assert(m1 == m2 && prevLookupClass == null); + + if (!willAccessClass(c2, false)) + return false; LookupCase lc = this.in(c2); - int m1 = lc.lookupModes(); - int m2 = fixMods(m.getModifiers()); + int modes1 = lc.lookupModes(); + int modes2 = fixMods(m.getModifiers()); // allow private lookup on nestmates. Otherwise, privacy is strictly enforced - if (c1 != c2 && ((m2 & PRIVATE) == 0 || !c1.isNestmateOf(c2))) { - m1 &= ~PRIVATE; + if (c1 != c2 && ((modes2 & PRIVATE) == 0 || !c1.isNestmateOf(c2))) { + modes1 &= ~PRIVATE; } // protected access is sometimes allowed - if ((m2 & PROTECTED) != 0) { - int prev = m2; - m2 |= PACKAGE; // it acts like a package method also + if ((modes2 & PROTECTED) != 0) { + int prev = modes2; + modes2 |= PACKAGE; // it acts like a package method also if ((lookupModes() & PROTECTED) != 0 && c2.isAssignableFrom(c1)) - m2 |= PUBLIC; // from a subclass, it acts like a public method also + modes2 |= PUBLIC; // from a subclass, it acts like a public method also } if (verbosity >= 2) - System.out.format("%s willAccess %s m1=0x%h m2=0x%h => %s%n", this, lc, m1, m2, ((m2 & m1) != 0)); - return (m2 & m1) != 0; + System.out.format("%s willAccess %s modes1=0x%h modes2=0x%h => %s%n", lookupString(), lc.lookupString(), modes1, modes2, (modes2 & modes1) != 0); + return (modes2 & modes1) != 0; } /** Predict the success or failure of accessing this class. */ @@ -268,24 +359,36 @@ } } - // publicLookup has access to all public types/members of types in unnamed modules - if ((lookupModes & UNCONDITIONAL) != 0 - && (lookupModes & PUBLIC) != 0 - && (!c2.getModule().isNamed()) - && Modifier.isPublic(c2.getModifiers())) - return true; + Module m1 = c1.getModule(); + Module m2 = c2.getModule(); + Module m0 = prevLookupClass != null ? prevLookupClass.getModule() : m1; + // unconditional has access to all public types that is in an unconditionally exported package + if ((lookupModes & UNCONDITIONAL) != 0) { + return m2.isExported(c2.getPackageName()) && Modifier.isPublic(c2.getModifiers()); + } + // c1 and c2 are in different module + if (m1 != m2 || m0 != m2) { + return (lookupModes & PUBLIC) != 0 + && isModuleAccessible(c2) + && Modifier.isPublic(c2.getModifiers()); + } + + assert(m1 == m2 && prevLookupClass == null); LookupCase lc = this.in(c2); - int m1 = lc.lookupModes(); + int modes1 = lc.lookupModes(); boolean r = false; - if (m1 == 0) { + if (modes1 == 0) { r = false; } else { - int m2 = fixMods(c2.getModifiers()); - if ((m2 & PUBLIC) != 0) { - r = true; - } else if ((m1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage()) { - r = true; + if (Modifier.isPublic(c2.getModifiers())) { + if ((modes1 & MODULE) != 0) + r = true; + else if ((modes1 & PUBLIC) != 0) + r = m1.isExported(c2.getPackageName()); + } else { + if ((modes1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage()) + r = true; } } if (verbosity >= 2) { @@ -328,7 +431,7 @@ return i+1; } - private void addLookupEdge(LookupCase l1, Class c2, LookupCase l2) { + private void addLookupEdge(LookupCase l1, Class c2, LookupCase l2, int dropAccess) { TreeSet edges = CASE_EDGES.get(l2); if (edges == null) CASE_EDGES.put(l2, edges = new TreeSet<>()); if (edges.add(l1)) { @@ -337,7 +440,7 @@ int m1 = l1.lookupModes(); int m2 = l2.lookupModes(); assert((m1 | m2) == m1); // [A2] (no elevation of access) - LookupCase expect = l1.in(c2); + LookupCase expect = dropAccess == 0 ? l1.in(c2) : l1.in(c2).dropLookupMode(dropAccess); if (!expect.equals(l2)) System.out.println("*** expect "+l1+" => "+expect+" but got "+l2); assertEquals(l2, expect); @@ -358,9 +461,14 @@ for (int lastCount = -1; lastCount != CASES.size(); ) { lastCount = CASES.size(); // if CASES grow in the loop we go round again for (LookupCase lc1 : CASES.toArray(new LookupCase[0])) { + for (int mode : ACCESS_CASES) { + LookupCase lc2 = new LookupCase(lc1.lookup().dropLookupMode(mode)); + addLookupEdge(lc1, lc1.lookupClass(), lc2, mode); + CASES.add(lc2); + } for (Class c2 : classes) { LookupCase lc2 = new LookupCase(lc1.lookup().in(c2)); - addLookupEdge(lc1, c2, lc2); + addLookupEdge(lc1, c2, lc2, 0); CASES.add(lc2); } } @@ -386,8 +494,8 @@ if (verbosity > 0) { verbosity += 9; Method pro_in_self = targetMethod(THIS_CLASS, PROTECTED, methodType(void.class)); - testOneAccess(lookupCase("AccessControlTest/public"), pro_in_self, "find"); - testOneAccess(lookupCase("Remote_subclass/public"), pro_in_self, "find"); + testOneAccess(lookupCase("AccessControlTest/module"), pro_in_self, "find"); + testOneAccess(lookupCase("Remote_subclass/module"), pro_in_self, "find"); testOneAccess(lookupCase("Remote_subclass"), pro_in_self, "find"); verbosity -= 9; } @@ -398,6 +506,8 @@ String targetPlace = placeName(targetClass); if (targetPlace == null) continue; // Object, String, not a target for (int targetAccess : ACCESS_CASES) { + if (targetAccess == MODULE || targetAccess == UNCONDITIONAL) + continue; MethodType methodType = methodType(void.class); Method method = targetMethod(targetClass, targetAccess, methodType); // Try to access target method from various contexts. @@ -457,7 +567,6 @@ } static Method targetMethod(Class targetClass, int targetAccess, MethodType methodType) { - assert targetAccess != MODULE; String methodName = accessName(targetAccess)+placeName(targetClass); if (verbosity >= 2) System.out.println(targetClass.getSimpleName()+"."+methodName+methodType); @@ -491,10 +600,13 @@ assert(false); return "?"; } - // MODULE not a test case at this time private static final int[] ACCESS_CASES = { - PUBLIC, PACKAGE, PRIVATE, PROTECTED + PUBLIC, PACKAGE, PRIVATE, PROTECTED, MODULE, UNCONDITIONAL }; + /* + * Adjust PUBLIC => PUBLIC|MODULE|UNCONDITIONAL + * Adjust 0 => PACKAGE + */ /** Return one of the ACCESS_CASES. */ static int fixMods(int mods) { mods &= (PUBLIC|PRIVATE|PROTECTED); diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/DropLookupModeTest.java --- a/test/jdk/java/lang/invoke/DropLookupModeTest.java Wed Jul 24 12:49:44 2019 +0530 +++ b/test/jdk/java/lang/invoke/DropLookupModeTest.java Thu Jul 25 12:23:54 2019 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -106,37 +106,39 @@ assertTrue(lookup.lookupModes() == 0); } - /** - * Test dropLookupMode on the public Lookup. - */ - public void testPublicLookup() { - final Lookup publicLookup = MethodHandles.publicLookup(); - final Class lc = publicLookup.lookupClass(); - assertTrue(publicLookup.lookupModes() == (PUBLIC|UNCONDITIONAL)); - - Lookup lookup = publicLookup.dropLookupMode(PRIVATE); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == PUBLIC); - - lookup = publicLookup.dropLookupMode(PROTECTED); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == PUBLIC); + @DataProvider(name = "unconditionals") + public Object[][] unconditionals() { + Lookup publicLookup = MethodHandles.publicLookup(); + return new Object[][] { + { publicLookup, Object.class }, + { publicLookup.in(String.class), String.class }, + { publicLookup.in(DropLookupModeTest.class), DropLookupModeTest.class }, + }; + } - lookup = publicLookup.dropLookupMode(PACKAGE); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == PUBLIC); - - lookup = publicLookup.dropLookupMode(MODULE); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == PUBLIC); + /** + * Test dropLookupMode on the lookup with public lookup + * and UNCONDITIONAL + */ + @Test(dataProvider = "unconditionals") + public void testUnconditionalLookup(Lookup unconditionalLookup, Class expected) { + assertTrue(unconditionalLookup.lookupModes() == UNCONDITIONAL); - lookup = publicLookup.dropLookupMode(PUBLIC); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == 0); + assertPublicLookup(unconditionalLookup.dropLookupMode(PRIVATE), expected); + assertPublicLookup(unconditionalLookup.dropLookupMode(PROTECTED), expected); + assertPublicLookup(unconditionalLookup.dropLookupMode(PACKAGE), expected); + assertPublicLookup(unconditionalLookup.dropLookupMode(MODULE), expected); + assertPublicLookup(unconditionalLookup.dropLookupMode(PUBLIC), expected); - lookup = publicLookup.dropLookupMode(UNCONDITIONAL); - assertTrue(lookup.lookupClass() == lc); - assertTrue(lookup.lookupModes() == PUBLIC); + // drop all access + Lookup lookup = unconditionalLookup.dropLookupMode(UNCONDITIONAL); + assertTrue(lookup.lookupClass() == expected); + assertTrue(lookup.lookupModes() == 0); + } + + private void assertPublicLookup(Lookup lookup, Class expected) { + assertTrue(lookup.lookupClass() == expected); + assertTrue(lookup.lookupModes() == UNCONDITIONAL); } @DataProvider(name = "badInput") @@ -157,4 +159,4 @@ MethodHandles.lookup().dropLookupMode(modeToDrop); } -} \ No newline at end of file +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java --- a/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java Wed Jul 24 12:49:44 2019 +0530 +++ b/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java Thu Jul 25 12:23:54 2019 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -82,6 +82,7 @@ } // Invoke MethodHandles.privateLookupIn with a reduced-power caller + @Test(expectedExceptions = {IllegalAccessException.class}) public void testReducedAccessCallerSameModule() throws Throwable { Lookup caller = MethodHandles.lookup().dropLookupMode(PACKAGE); assertTrue((caller.lookupModes() & PRIVATE) == 0); @@ -89,12 +90,6 @@ assertTrue((caller.lookupModes() & MODULE) != 0); Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, caller); - assertTrue(lookup.lookupClass() == nonPublicType); - assertTrue(lookup.hasPrivateAccess()); - - // use it - MethodHandle mh = lookup.findStaticGetter(nonPublicType, "obj", Object.class); - Object obj = mh.invokeExact(); } // Invoke MethodHandles.privateLookupIn with the public lookup as caller diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/Driver1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/Driver1.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,31 @@ +/* + * 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 8173978 + * @build m3/* m4/* m5/* Unnamed Unnamed1 + * @run testng/othervm m3/jdk.test.ModuleAccessTest + * @summary Basic test case for module access checks and Lookup.in and + * MethodHandles.privateLookupIn + */ diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/Unnamed.java --- a/test/jdk/java/lang/invoke/modules/Unnamed.java Wed Jul 24 12:49:44 2019 +0530 +++ b/test/jdk/java/lang/invoke/modules/Unnamed.java Thu Jul 25 12:23:54 2019 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -21,4 +21,11 @@ * questions. */ -public class Unnamed { } +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; + +public class Unnamed { + public static Lookup lookup() { + return MethodHandles.lookup(); + } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/Unnamed1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/Unnamed1.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,24 @@ +/* + * 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. + */ + +public class Unnamed1 { } diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m1/p1/Main.java --- a/test/jdk/java/lang/invoke/modules/m1/p1/Main.java Wed Jul 24 12:49:44 2019 +0530 +++ b/test/jdk/java/lang/invoke/modules/m1/p1/Main.java Thu Jul 25 12:23:54 2019 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -45,7 +45,7 @@ private Class p2_Type2; // m1, not exported private Class q1_Type1; // m2, exported private Class q2_Type2; // m2, not exported - private Class x500NameClass; // java.base, not exported + private Class signalClass; // java.base, not exported private Class unnamedClass; // class in unnamed module @BeforeTest @@ -55,7 +55,7 @@ p2_Type2 = Class.forName("p2.Type2"); q1_Type1 = Class.forName("q1.Type1"); q2_Type2 = Class.forName("q2.Type2"); - x500NameClass = Class.forName("sun.security.x509.X500Name"); + signalClass = Class.forName("jdk.internal.misc.Signal"); unnamedClass = Class.forName("Unnamed"); } catch (ClassNotFoundException e) { throw new AssertionError(e); @@ -105,7 +105,7 @@ // java.base findConstructor(lookup, Object.class, void.class); // [A2] - findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // [A3] + findConstructorExpectingIAE(lookup, signalClass, void.class, String.class); // [A3] // unnamed findConstructor(lookup, unnamedClass, void.class); // [A3] @@ -130,7 +130,7 @@ // java.base findConstructor(lookup, Object.class, void.class); - findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + findConstructorExpectingIAE(lookup, signalClass, void.class, String.class); // unnamed findConstructor(lookup, unnamedClass, void.class); @@ -139,51 +139,70 @@ /** * Hop to lookup class in another named module * - * [A0] has no access + * [A0] has PUBLIC access if accessible; otherwise no access + * [A1] old lookup class becomes previous lookup class */ public void testFromNamedToNamedModule() throws Exception { + // m2/q1_Type1 is accessible to m1 whereas m2/q_Type2 is not accessible Lookup lookup = MethodHandles.lookup().in(q1_Type1); - assertTrue(lookup.lookupModes() == 0); // [A0] + assertTrue(lookup.lookupModes() == PUBLIC); // [A0] + assertTrue(lookup.previousLookupClass() == Main.class); // [A1] + + Lookup lookup2 = MethodHandles.lookup().in(q2_Type2); + assertTrue(lookup2.lookupModes() == 0); // [A0] + assertTrue(lookup2.previousLookupClass() == Main.class); // [A1] // m1 findConstructorExpectingIAE(lookup, p1_Type1, void.class); findConstructorExpectingIAE(lookup, p2_Type2, void.class); + findConstructorExpectingIAE(lookup2, p1_Type1, void.class); + findConstructorExpectingIAE(lookup2, p2_Type2, void.class); + // m2 - findConstructorExpectingIAE(lookup, q1_Type1, void.class); + findConstructor(lookup, q1_Type1, void.class); // m2/q1 is exported findConstructorExpectingIAE(lookup, q2_Type2, void.class); + findConstructorExpectingIAE(lookup2, q1_Type1, void.class); + findConstructorExpectingIAE(lookup2, q2_Type2, void.class); + // java.base - findConstructorExpectingIAE(lookup, Object.class, void.class); - findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, signalClass, void.class, String.class); + + findConstructorExpectingIAE(lookup2, Object.class, void.class); + findConstructorExpectingIAE(lookup2, signalClass, void.class, String.class); // unnamed findConstructorExpectingIAE(lookup, unnamedClass, void.class); + + findConstructorExpectingIAE(lookup2, unnamedClass, void.class); + } /** * Hop to lookup class in an unnamed module * - * [A0] has no access + * [A0] has PUBLIC access */ public void testFromNamedToUnnamedModule() throws Exception { Lookup lookup = MethodHandles.lookup().in(unnamedClass); - assertTrue(lookup.lookupModes() == 0); // [A0] + assertTrue(lookup.lookupModes() == PUBLIC); // [A0] // m1 - findConstructorExpectingIAE(lookup, p1_Type1, void.class); + findConstructor(lookup, p1_Type1, void.class); // p1 is exported findConstructorExpectingIAE(lookup, p2_Type2, void.class); // m2 - findConstructorExpectingIAE(lookup, q1_Type1, void.class); + findConstructor(lookup, q1_Type1, void.class); findConstructorExpectingIAE(lookup, q2_Type2, void.class); // java.base - findConstructorExpectingIAE(lookup, Object.class, void.class); - findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, signalClass, void.class, String.class); // unnamed - findConstructorExpectingIAE(lookup, unnamedClass, void.class); + findConstructor(lookup, unnamedClass, void.class); } /** @@ -206,7 +225,7 @@ // java.base findConstructor(lookup, Object.class, void.class); - findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + findConstructorExpectingIAE(lookup, signalClass, void.class, String.class); // unnamed findConstructor(lookup, unnamedClass, void.class); @@ -215,11 +234,11 @@ /** * MethodHandles.publicLookup() * - * [A0] has PUBLIC|UNCONDITIONAL access + * [A0] has UNCONDITIONAL access */ public void testPublicLookup() throws Exception { Lookup lookup = MethodHandles.publicLookup(); - assertTrue(lookup.lookupModes() == (PUBLIC|UNCONDITIONAL)); // A0 + assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0 // m1 findConstructor(lookup, p1_Type1, void.class); @@ -231,7 +250,7 @@ // java.base findConstructor(lookup, Object.class, void.class); - findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + findConstructorExpectingIAE(lookup, signalClass, void.class, String.class); // unnamed findConstructor(lookup, unnamedClass, void.class); @@ -239,36 +258,12 @@ /** * Hop from publicLookup to accessible type in java.base + * + * [A0] has UNCONDITIONAL access */ public void testPublicLookupToBaseModule() throws Exception { Lookup lookup = MethodHandles.publicLookup().in(String.class); - assertTrue(lookup.lookupModes() == PUBLIC); // A0 - - // m1 - findConstructorExpectingIAE(lookup, p1_Type1, void.class); - findConstructorExpectingIAE(lookup, p2_Type2, void.class); - - // m2 - findConstructorExpectingIAE(lookup, q1_Type1, void.class); - findConstructorExpectingIAE(lookup, q2_Type2, void.class); - - // java.base - findConstructor(lookup, Object.class, void.class); - findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); - - // unnamed - findConstructorExpectingIAE(lookup, unnamedClass, void.class); - } - - - /** - * Hop from publicLookup to accessible type in named module. - * - * [A0] has PUBLIC access - */ - public void testPublicLookupToAccessibleTypeInNamedModule() throws Exception { - Lookup lookup = MethodHandles.publicLookup().in(p1_Type1); - assertTrue(lookup.lookupModes() == PUBLIC); // A0 + assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0 // m1 findConstructor(lookup, p1_Type1, void.class); @@ -280,7 +275,33 @@ // java.base findConstructor(lookup, Object.class, void.class); - findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + findConstructorExpectingIAE(lookup, signalClass, void.class, String.class); + + // unnamed + findConstructor(lookup, unnamedClass, void.class); + } + + + /** + * Hop from publicLookup to accessible type in named module. + * + * [A0] has UNCONDITIONAL access + */ + public void testPublicLookupToAccessibleTypeInNamedModule() throws Exception { + Lookup lookup = MethodHandles.publicLookup().in(p1_Type1); + assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0 + + // m1 + findConstructor(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructor(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, signalClass, void.class, String.class); // unnamed findConstructor(lookup, unnamedClass, void.class); @@ -305,7 +326,7 @@ // java.base findConstructorExpectingIAE(lookup, Object.class, void.class); - findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + findConstructorExpectingIAE(lookup, signalClass, void.class, String.class); // unnamed findConstructorExpectingIAE(lookup, unnamedClass, void.class); @@ -314,11 +335,11 @@ /** * Teleport from publicLookup to public type in unnamed module * - * [A0] has PUBLIC access + * [A0] has UNCONDITIONAL access */ public void testPublicLookupToUnnamedModule() throws Exception { Lookup lookup = MethodHandles.publicLookup().in(unnamedClass); - assertTrue(lookup.lookupModes() == PUBLIC); // A0 + assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0 // m1 findConstructor(lookup, p1_Type1, void.class); @@ -330,7 +351,7 @@ // java.base findConstructor(lookup, Object.class, void.class); - findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + findConstructorExpectingIAE(lookup, signalClass, void.class, String.class); // unnamed findConstructor(lookup, unnamedClass, void.class); diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m3/c1/C1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m3/c1/C1.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,34 @@ +/* + * 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. + */ +package c1; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; + +public class C1 { + public C1() { } + + public static Lookup lookup() { + return MethodHandles.lookup(); + } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m3/c1/C2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m3/c1/C2.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,27 @@ +/* + * 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. + */ +package c1; + +public class C2 { + public C2() { } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m3/c2/C3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m3/c2/C3.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,27 @@ +/* + * 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. + */ +package c2; + +public class C3{ + public C3() { } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m3/jdk/test/ModuleAccessTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m3/jdk/test/ModuleAccessTest.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,568 @@ +/* + * 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. + */ + +package jdk.test; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; + +import java.lang.invoke.MethodType; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import e1.CrackM5Access; + +import static java.lang.invoke.MethodHandles.Lookup.*; +import static org.testng.Assert.*; + +public class ModuleAccessTest { + static ModuleLookup m3; + static ModuleLookup m4; + static ModuleLookup m5; + static Map moduleLookupMap = new HashMap<>(); + static Lookup privLookupIn; + static Lookup privLookupIn2; + static Lookup unnamedLookup; + static Class unnamed; + static Class unnamed1; + + @BeforeTest + public void setup() throws Exception { + m3 = new ModuleLookup("m3", 'C'); + m4 = new ModuleLookup("m4", 'D'); + m5 = new ModuleLookup("m5", 'E'); + moduleLookupMap.put(m3.name(), m3); + moduleLookupMap.put(m4.name(), m4); + moduleLookupMap.put(m5.name(), m5); + + privLookupIn = MethodHandles.privateLookupIn(m3.type2, m3.lookup); + privLookupIn2 = MethodHandles.privateLookupIn(m4.type1, m3.lookup); + + unnamed = Class.forName("Unnamed"); + unnamed1 = Class.forName("Unnamed1"); + unnamedLookup = (Lookup)unnamed.getMethod("lookup").invoke(null); + + // m5 reads m3 + CrackM5Access.addReads(m3.module); + CrackM5Access.addReads(unnamed.getModule()); + } + + @DataProvider(name = "samePackage") + public Object[][] samePackage() throws Exception { + return new Object[][] { + { m3.lookup, m3.type2 }, + { privLookupIn, m3.type1 }, + { privLookupIn2, m4.type2 }, + { unnamedLookup, unnamed1 } + }; + } + + /** + * Test lookup.in(T) where T is in the same package of the lookup class. + * + * [A0] targetClass becomes the lookup class + * [A1] no change in previous lookup class + * [A2] PROTECTED and PRIVATE are dropped + */ + @Test(dataProvider = "samePackage") + public void testLookupInSamePackage(Lookup lookup, Class targetClass) throws Exception { + Class lookupClass = lookup.lookupClass(); + Lookup lookup2 = lookup.in(targetClass); + + assertTrue(lookupClass.getPackage() == targetClass.getPackage()); + assertTrue(lookupClass.getModule() == targetClass.getModule()); + assertTrue(lookup2.lookupClass() == targetClass); // [A0] + assertTrue(lookup2.previousLookupClass() == lookup.previousLookupClass()); // [A1] + assertTrue(lookup2.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE))); // [A2] + } + + @DataProvider(name = "sameModule") + public Object[][] sameModule() throws Exception { + return new Object[][] { + { m3.lookup, m3.type3}, + { privLookupIn, m3.type3}, + { privLookupIn2, m4.type3} + }; + } + + /** + * Test lookup.in(T) where T is in the same module but different package from the lookup class. + * + * [A0] targetClass becomes the lookup class + * [A1] no change in previous lookup class + * [A2] PROTECTED, PRIVATE and PACKAGE are dropped + */ + @Test(dataProvider = "sameModule") + public void testLookupInSameModule(Lookup lookup, Class targetClass) throws Exception { + Class lookupClass = lookup.lookupClass(); + Lookup lookup2 = lookup.in(targetClass); + + assertTrue(lookupClass.getPackage() != targetClass.getPackage()); + assertTrue(lookupClass.getModule() == targetClass.getModule()); + assertTrue(lookup2.lookupClass() == targetClass); // [A0] + assertTrue(lookup2.previousLookupClass() == lookup.previousLookupClass()); // [A1] + assertTrue(lookup2.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE))); // [A2] + } + + @DataProvider(name = "anotherModule") + public Object[][] anotherModule() throws Exception { + return new Object[][] { + { m3.lookup, m4.type1, m5, m5.accessibleTypesTo(m3.module, m4.module) }, + { m4.lookup, m5.type2, m3, m3.accessibleTypesTo(m4.module, m5.module) }, + { m3.lookup, m5.type1, m4, m4.accessibleTypesTo(m3.module, m5.module) }, + { m5.lookup, unnamed, m3, m3.accessibleTypesTo(m5.module, unnamed.getModule()) }, + }; + } + + /** + * Test lookup.in(T) where T is in a different module from the lookup class. + * + * [A0] targetClass becomes the lookup class + * [A1] lookup class becomes previous lookup class + * [A2] PROTECTED, PRIVATE, PACKAGE, and MODULE are dropped + * [A3] no access to module internal types in m0 and m1 + * [A4] if m1 reads m0, can access public types in m0; otherwise no access. + * [A5] can access public types in m1 exported to m0 + * [A6] can access public types in m2 exported to m0 and m1 + */ + @Test(dataProvider = "anotherModule") + public void testLookupInAnotherModule(Lookup lookup, Class targetClass, + ModuleLookup m2, Set> otherTypes) throws Exception { + Class lookupClass = lookup.lookupClass(); + Module m0 = lookupClass.getModule(); + Module m1 = targetClass.getModule(); + + assertTrue(m0 != m1); + assertTrue(m0.canRead(m1)); + assertTrue(m1.isExported(targetClass.getPackageName(), m0)); + + Lookup lookup2 = lookup.in(targetClass); + assertTrue(lookup2.lookupClass() == targetClass); // [A0] + assertTrue(lookup2.previousLookupClass() == lookup.lookupClass()); // [A1] + assertTrue(lookup2.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE|MODULE))); // [A2] + + // [A3] no access to module internal type in m0 + // [A4] if m1 reads m0, + // [A4] no access to public types exported from m0 unconditionally + // [A4] no access to public types exported from m0 + ModuleLookup ml0 = moduleLookupMap.get(m0.getName()); + if (m1.canRead(m0)) { + for (Class type : ml0.unconditionalExports()) { + testAccess(lookup2, type); + } + for (Class type : ml0.qualifiedExportsTo(m1)) { + testAccess(lookup2, type); + } + } else { + findConstructorExpectingIAE(lookup2, ml0.type1, void.class); + findConstructorExpectingIAE(lookup2, ml0.type2, void.class); + findConstructorExpectingIAE(lookup2, ml0.type3, void.class); + } + + // [A5] can access public types exported from m1 unconditionally + // [A5] can access public types exported from m1 to m0 + if (m1.isNamed()) { + ModuleLookup ml1 = moduleLookupMap.get(m1.getName()); + assertTrue(ml1.unconditionalExports().size() + ml1.qualifiedExportsTo(m0).size() > 0); + for (Class type : ml1.unconditionalExports()) { + testAccess(lookup2, type); + } + for (Class type : ml1.qualifiedExportsTo(m0)) { + testAccess(lookup2, type); + } + } else { + // unnamed module + testAccess(lookup2, unnamed1); + } + + // [A5] can access public types exported from m2 unconditionally + // [A5] can access public types exported from m2 to m0 and m1 + for (Class type : otherTypes) { + assertTrue(type.getModule() == m2.module); + testAccess(lookup2, type); + } + + // test inaccessible types + for (Class type : Set.of(m2.type1, m2.type2, m2.type3)) { + if (!otherTypes.contains(type)) { + // type is accessible to this lookup + try { + lookup2.accessClass(type); + assertTrue(false); + } catch (IllegalAccessException e) {} + + findConstructorExpectingIAE(lookup2, type, void.class); + } + } + } + + public void testAccess(Lookup lookup, Class type) throws Exception { + // type is accessible to this lookup + assertTrue(lookup.accessClass(type) == type); + + // can find constructor + findConstructor(lookup, type, void.class); + + Module m0 = lookup.previousLookupClass().getModule(); + Module m1 = lookup.lookupClass().getModule(); + Module m2 = type.getModule(); + + assertTrue(m0 != m1 && m0 != null); + assertTrue((lookup.lookupModes() & MODULE) == 0); + assertTrue(m0 != m2 || m1 != m2); + + MethodHandles.Lookup lookup2 = lookup.in(type); + if (m2 == m1) { + // the same module of the lookup class + assertTrue(lookup2.lookupClass() == type); + assertTrue(lookup2.previousLookupClass() == lookup.previousLookupClass()); + } else if (m2 == m0) { + // hop back to the module of the previous lookup class + assertTrue(lookup2.lookupClass() == type); + assertTrue(lookup2.previousLookupClass() == lookup.lookupClass()); + } else { + // hop to a third module + assertTrue(lookup2.lookupClass() == type); + assertTrue(lookup2.previousLookupClass() == lookup.lookupClass()); + assertTrue(lookup2.lookupModes() == 0); + } + } + + @DataProvider(name = "thirdModule") + public Object[][] thirdModule() throws Exception { + return new Object[][] { + { m3.lookup, m4.type1, m5.type1}, + { m3.lookup, m4.type2, m5.type1}, + { unnamedLookup, m3.type1, m4.type1 }, + }; + } + + /** + * Test lookup.in(c1).in(c2) where c1 is in second module and c2 is in a third module. + * + * [A0] c2 becomes the lookup class + * [A1] c1 becomes previous lookup class + * [A2] all access bits are dropped + */ + @Test(dataProvider = "thirdModule") + public void testLookupInThirdModule(Lookup lookup, Class c1, Class c2) throws Exception { + Class c0 = lookup.lookupClass(); + Module m0 = c0.getModule(); + Module m1 = c1.getModule(); + Module m2 = c2.getModule(); + + assertTrue(m0 != m1 && m0 != m2 && m1 != m2); + assertTrue(m0.canRead(m1) && m0.canRead(m2)); + assertTrue(m1.canRead(m2)); + assertTrue(m1.isExported(c1.getPackageName(), m0)); + assertTrue(m2.isExported(c2.getPackageName(), m0) && m2.isExported(c2.getPackageName(), m1)); + + Lookup lookup1 = lookup.in(c1); + assertTrue(lookup1.lookupClass() == c1); + assertTrue(lookup1.previousLookupClass() == c0); + assertTrue(lookup1.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE|MODULE))); + + Lookup lookup2 = lookup1.in(c2); + assertTrue(lookup2.lookupClass() == c2); // [A0] + assertTrue(lookup2.previousLookupClass() == c1); // [A1] + assertTrue(lookup2.lookupModes() == 0, lookup2.toString()); // [A2] + } + + @DataProvider(name = "privLookupIn") + public Object[][] privLookupIn() throws Exception { + return new Object[][] { + { m3.lookup, m4.type1 }, + { m3.lookup, m5.type1 }, + { m4.lookup, m5.type2 }, + { m5.lookup, m3.type3 }, + { m5.lookup, unnamed } + }; + } + + /** + * Test privateLookupIn(T, lookup) where T is in another module + * + * [A0] full capabilities except MODULE bit + * [A1] target class becomes the lookup class + * [A2] the lookup class becomes previous lookup class + * [A3] IAE thrown if lookup has no MODULE access + */ + @Test(dataProvider = "privLookupIn") + public void testPrivateLookupIn(Lookup lookup, Class targetClass) throws Exception { + Module m0 = lookup.lookupClass().getModule(); + Module m1 = targetClass.getModule(); + + // privateLookupIn from m0 to m1 + assertTrue(m0 != m1); + assertTrue(m1.isOpen(targetClass.getPackageName(), m0)); + Lookup privLookup1 = MethodHandles.privateLookupIn(targetClass, lookup); + assertTrue(privLookup1.lookupModes() == (PROTECTED|PRIVATE|PACKAGE|PUBLIC)); // [A0] + assertTrue(privLookup1.lookupClass() == targetClass); // [A1] + assertTrue(privLookup1.previousLookupClass() == lookup.lookupClass()); // [A2] + + // privLookup1 has no MODULE access; can't do privateLookupIn + try { + Lookup privLookup2 = MethodHandles.privateLookupIn(targetClass, privLookup1); // [A3] + assertFalse(privLookup2 != null); + } catch (IllegalAccessException e) {} + } + + /** + * Test member access from the Lookup returned from privateLookupIn + */ + @Test + public void testPrivateLookupAccess() throws Exception { + Class staticsClass = e1.Statics.class; + Lookup privLookup1 = MethodHandles.privateLookupIn(staticsClass, m4.lookup); + assertTrue((privLookup1.lookupModes() & MODULE) == 0); + assertTrue(privLookup1.lookupClass() == staticsClass); + assertTrue(privLookup1.previousLookupClass() == m4.lookup.lookupClass()); + + // access private member and default package member in m5 + MethodType mtype = MethodType.methodType(void.class); + MethodHandle mh1 = privLookup1.findStatic(staticsClass, "privateMethod", mtype); + MethodHandle mh2 = privLookup1.findStatic(staticsClass, "packageMethod", mtype); + + // access public member in exported types from m5 to m4 + findConstructor(privLookup1, m5.type1, void.class); + // no access to public member in non-exported types to m5 + findConstructorExpectingIAE(privLookup1, m5.type3, void.class); + + // no access to public types in m4 since m5 does not read m4 + assertFalse(m5.module.canRead(m4.module)); + findConstructorExpectingIAE(privLookup1, m4.type1, void.class); + + // teleport from a privateLookup to another class in the same package + // lose private access + Lookup privLookup2 = MethodHandles.privateLookupIn(m5.type1, m4.lookup); + Lookup lookup = privLookup2.in(staticsClass); + assertTrue((lookup.lookupModes() & PRIVATE) == 0); + MethodHandle mh3 = lookup.findStatic(staticsClass, "packageMethod", mtype); + try { + lookup.findStatic(staticsClass, "privateMethod", mtype); + assertTrue(false); + } catch (IllegalAccessException e) {} + } + + /** + * Test member access from the Lookup returned from privateLookupIn and + * the lookup mode after dropLookupMode + */ + @Test + public void testDropLookupMode() throws Exception { + Lookup lookup = MethodHandles.privateLookupIn(m5.type1, m4.lookup); + assertTrue((lookup.lookupModes() & MODULE) == 0); + + Lookup lookup1 = lookup.dropLookupMode(PRIVATE); + assertTrue(lookup1.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE))); + Lookup lookup2 = lookup.dropLookupMode(PACKAGE); + assertTrue(lookup2.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE))); + Lookup lookup3 = lookup.dropLookupMode(MODULE); + assertTrue(lookup3.lookupModes() == (lookup.lookupModes() & ~(PROTECTED|PRIVATE|PACKAGE))); + Lookup lookup4 = lookup.dropLookupMode(PUBLIC); + assertTrue(lookup4.lookupModes() == 0); + + } + + /** + * Test no access to a public member on a non-public class + */ + @Test + public void testPrivateLookupOnNonPublicType() throws Exception { + // privateLookup in a non-public type + Class nonPUblicType = Class.forName("e1.NonPublic"); + Lookup privLookup = MethodHandles.privateLookupIn(nonPUblicType, m4.lookup); + MethodType mtype = MethodType.methodType(void.class); + MethodHandle mh1 = privLookup.findStatic(nonPUblicType, "publicStatic", mtype); + + // drop MODULE access i.e. only PUBLIC access + Lookup lookup = privLookup.dropLookupMode(MODULE); + assertTrue(lookup.lookupModes() == PUBLIC); + try { + MethodHandle mh2 = lookup.findStatic(nonPUblicType, "publicStatic", mtype); + assertFalse(mh2 != null); + } catch (IllegalAccessException e) {} + } + + @Test + public void testPublicLookup() { + Lookup publicLookup = MethodHandles.publicLookup(); + Lookup pub1 = publicLookup.in(m3.type1); + Lookup pub2 = pub1.in(java.lang.String.class); + Lookup pub3 = pub2.in(java.lang.management.ThreadMXBean.class); + Lookup pub4 = pub3.dropLookupMode(UNCONDITIONAL); + + assertTrue(publicLookup.lookupClass() == Object.class); + assertTrue(publicLookup.lookupModes() == UNCONDITIONAL); + assertTrue(pub1.lookupClass() == m3.type1); + assertTrue(pub1.lookupModes() == UNCONDITIONAL); + assertTrue(pub2.lookupClass() == String.class); + assertTrue(pub2.lookupModes() == UNCONDITIONAL); + assertTrue(pub3.lookupClass() == java.lang.management.ThreadMXBean.class); + assertTrue(pub3.lookupModes() == UNCONDITIONAL); + assertTrue(pub4.lookupModes() == 0); + + // publicLookup has no MODULE access; can't do privateLookupIn + try { + Lookup pub5 = MethodHandles.privateLookupIn(m4.type1, pub1); + assertFalse(pub5 != null); + } catch (IllegalAccessException e) {} + } + + static class ModuleLookup { + private final Module module; + private final Set packages; + private final Lookup lookup; + private final Class type1; + private final Class type2; + private final Class type3; + + ModuleLookup(String mn, char c) throws Exception { + this.module = ModuleLayer.boot().findModule(mn).orElse(null); + assertNotNull(this.module); + this.packages = module.getDescriptor().packages(); + assertTrue(packages.size() <= 3); + Lookup lookup = null; + Class type1 = null; + Class type2 = null; + Class type3 = null; + for (String pn : packages) { + char n = pn.charAt(pn.length() - 1); + switch (n) { + case '1': + type1 = Class.forName(pn + "." + c + "1"); + type2 = Class.forName(pn + "." + c + "2"); + Method m = type1.getMethod("lookup"); + lookup = (Lookup) m.invoke(null); + break; + case '2': + type3 = Class.forName(pn + "." + c + "3"); + break; + + default: + } + } + this.lookup = lookup; + this.type1 = type1; + this.type2 = type2; + this.type3 = type3; + } + + String name() { + return module.getName(); + } + + /* + * Returns the set of types that are unconditionally exported. + */ + Set> unconditionalExports() { + return Stream.of(type1, type2, type3) + .filter(c -> module.isExported(c.getPackageName())) + .collect(Collectors.toSet()); + } + + /* + * Returns the set of types that are qualifiedly exported to the specified + * caller module + */ + Set> qualifiedExportsTo(Module caller) { + if (caller.canRead(this.module)) { + return Stream.of(type1, type2, type3) + .filter(c -> !module.isExported(c.getPackageName()) + && module.isExported(c.getPackageName(), caller)) + .collect(Collectors.toSet()); + } else { + return Set.of(); + } + } + + /* + * Returns the set of types that are qualifiedly exported to the specified + * caller module + */ + Set> accessibleTypesTo(Module m0, Module m1) { + if (m0.canRead(this.module) && m1.canRead(this.module)) { + return Stream.of(type1, type2, type3) + .filter(c -> module.isExported(c.getPackageName(), m0) + && module.isExported(c.getPackageName(), m1)) + .collect(Collectors.toSet()); + } else { + return Set.of(); + } + } + + /* + * Returns the set of types that are open to the specified caller + * unconditionally or qualifiedly. + */ + Set> opensTo(Module caller) { + if (caller.canRead(this.module)) { + return Stream.of(type1, type2, type3) + .filter(c -> module.isOpen(c.getPackageName(), caller)) + .collect(Collectors.toSet()); + } else { + return Set.of(); + } + } + + public String toString() { + return module.toString(); + } + } + + /** + * Invokes Lookup findConstructor with a method type constructed from the + * given return and parameter types, expecting IllegalAccessException to be + * thrown. + */ + static void findConstructorExpectingIAE(Lookup lookup, + Class clazz, + Class rtype, + Class... ptypes) throws Exception { + try { + MethodHandle mh = findConstructor(lookup, clazz, rtype, ptypes); + assertTrue(false); + } catch (IllegalAccessException expected) { } + } + + /** + * Invokes Lookup findConstructor with a method type constructored from the + * given return and parameter types. + */ + static MethodHandle findConstructor(Lookup lookup, + Class clazz, + Class rtype, + Class... ptypes) throws Exception { + MethodType mt = MethodType.methodType(rtype, ptypes); + return lookup.findConstructor(clazz, mt); + } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m3/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m3/module-info.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,32 @@ +/* + * 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. + */ + +module m3 { + requires m4; + requires m5; + requires testng; + requires java.management; + exports c1; + opens c2 to m5; + exports jdk.test; +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m4/d1/D1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m4/d1/D1.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,34 @@ +/* + * 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. + */ +package d1; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; + +public class D1 { + public D1() { } + + public static Lookup lookup() { + return MethodHandles.lookup(); + } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m4/d1/D2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m4/d1/D2.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,27 @@ +/* + * 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. + */ +package d1; + +public class D2 { + public D2() { } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m4/d2/D3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m4/d2/D3.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,27 @@ +/* + * 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. + */ +package d2; + +public class D3 { + public D3() { } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m4/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m4/module-info.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module m4 { + requires m5; + opens d1; + exports d2 to m3; +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m5/e1/CrackM5Access.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m5/e1/CrackM5Access.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,33 @@ +/* + * 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. + */ +package e1; + +public class CrackM5Access { + private static void privateMethod() { } + + static void packageMethod() { } + + public static void addReads(Module m) { + CrackM5Access.class.getModule().addReads(m); + } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m5/e1/E1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m5/e1/E1.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,34 @@ +/* + * 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. + */ +package e1; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; + +public class E1 { + public E1() { } + + public static Lookup lookup() { + return MethodHandles.lookup(); + } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m5/e1/E2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m5/e1/E2.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,27 @@ +/* + * 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. + */ +package e1; + +public class E2 { + public E2() { } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m5/e1/NonPublic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m5/e1/NonPublic.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,27 @@ +/* + * 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. + */ +package e1; + +class NonPublic { + public static void publicStatic() { } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m5/e1/Statics.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m5/e1/Statics.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,29 @@ +/* + * 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. + */ +package e1; + +public class Statics { + private static void privateMethod() { } + + static void packageMethod() { } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m5/e2/E3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m5/e2/E3.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,27 @@ +/* + * 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. + */ +package e2; + +public class E3 { + public E3() { } +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/lang/invoke/modules/m5/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/lang/invoke/modules/m5/module-info.java Thu Jul 25 12:23:54 2019 +0530 @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module m5 { + exports e1 to m3; + opens e1 to m3, m4; + exports e2 to m3; +} diff -r 70865ef2afc7 -r b0aaa82a1b03 test/jdk/java/net/NetworkInterface/NetworkInterfaceRetrievalTests.java --- a/test/jdk/java/net/NetworkInterface/NetworkInterfaceRetrievalTests.java Wed Jul 24 12:49:44 2019 +0530 +++ b/test/jdk/java/net/NetworkInterface/NetworkInterfaceRetrievalTests.java Thu Jul 25 12:23:54 2019 +0530 @@ -24,6 +24,7 @@ /** * @test * @bug 8179559 8225239 + * @modules java.base/java.net:open */ import java.net.InetAddress;