mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-05 13:40:18 +00:00
Merge
This commit is contained in:
commit
8cecc798a3
1
.hgtags
1
.hgtags
@ -575,3 +575,4 @@ e64383344f144217c36196c3c8a2df8f588a2af3 jdk-14+3
|
||||
0f1e29c77e50c7da11d83df410026392c4d1a28c jdk-14+5
|
||||
2e63fb0a885fa908a97bbb0da8d7c3de11536aca jdk-13+30
|
||||
443f7359b34d60e7821216ffc60f88b6ffe0ccdd jdk-14+6
|
||||
28ab01c067551ef158abaef08e154e1051ca0893 jdk-14+7
|
||||
|
||||
@ -2040,17 +2040,6 @@ void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fa
|
||||
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) {
|
||||
|
||||
@ -565,8 +565,6 @@ class MacroAssembler: public Assembler {
|
||||
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
|
||||
|
||||
@ -218,85 +218,6 @@ void Label::patch_instructions(MacroAssembler* masm) {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -4547,9 +4547,6 @@ void JavaClasses::compute_offsets() {
|
||||
// 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
|
||||
|
||||
@ -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 @@ void G1CollectedHeap::abort_refinement() {
|
||||
|
||||
// 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 @@ void G1CollectedHeap::iterate_dirty_card_closure(G1CardTableEntryClosure* cl, ui
|
||||
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 @@ size_t G1CollectedHeap::pending_card_num() {
|
||||
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();
|
||||
dcqs.verify_num_entries_in_completed_buffers();
|
||||
|
||||
return buffer_size * buffer_num + count_from_threads._cards;
|
||||
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 G1ParEvacuateFollowersClosure::do_void() {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -397,7 +397,7 @@ void G1ConcurrentRefine::adjust(double log_buffer_scan_time,
|
||||
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 @@ void G1ConcurrentRefine::maybe_activate_more_threads(uint worker_id, size_t num_
|
||||
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
|
||||
|
||||
@ -104,7 +104,7 @@ void G1ConcurrentRefineThread::run_service() {
|
||||
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 @@ void G1ConcurrentRefineThread::run_service() {
|
||||
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()) {
|
||||
|
||||
@ -84,7 +84,7 @@ G1DirtyCardQueueSet::G1DirtyCardQueueSet(bool notify_when_complete) :
|
||||
_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 @@ void G1DirtyCardQueueSet::enqueue_completed_buffer(BufferNode* cbn) {
|
||||
_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 @@ void G1DirtyCardQueueSet::abandon_completed_buffers() {
|
||||
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::abandon_completed_buffers() {
|
||||
|
||||
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 @@ void G1DirtyCardQueueSet::merge_bufferlists(G1RedirtyCardsQueueSet* src) {
|
||||
_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 @@ bool G1DirtyCardQueueSet::process_or_enqueue_completed_buffer(BufferNode* node)
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -69,7 +69,9 @@ class G1DirtyCardQueueSet: public PtrQueueSet {
|
||||
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 @@ class G1DirtyCardQueueSet: public PtrQueueSet {
|
||||
// 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 @@ public:
|
||||
// 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; }
|
||||
|
||||
@ -86,8 +86,14 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) :
|
||||
_gc_par_phases[MergeLB] = new WorkerDataArray<double>(max_gc_threads, "Log Buffers (ms):");
|
||||
if (G1HotCardCache::default_use_cache()) {
|
||||
_gc_par_phases[MergeHCC] = new WorkerDataArray<double>(max_gc_threads, "Hot Card Cache (ms):");
|
||||
_merge_hcc_dirty_cards = new WorkerDataArray<size_t>(max_gc_threads, "Dirty Cards:");
|
||||
_gc_par_phases[MergeHCC]->link_thread_work_items(_merge_hcc_dirty_cards, MergeHCCDirtyCards);
|
||||
_merge_hcc_skipped_cards = new WorkerDataArray<size_t>(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<double>(max_gc_threads, "Scan Heap Roots (ms):");
|
||||
_gc_par_phases[OptScanHR] = new WorkerDataArray<double>(max_gc_threads, "Optional Scan Heap Roots (ms):");
|
||||
|
||||
@ -100,6 +100,11 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
ScanHRUsedMemory
|
||||
};
|
||||
|
||||
enum GCMergeHCCWorkItems {
|
||||
MergeHCCDirtyCards,
|
||||
MergeHCCSkippedCards
|
||||
};
|
||||
|
||||
enum GCMergeLBWorkItems {
|
||||
MergeLBProcessedBuffers,
|
||||
MergeLBDirtyCards,
|
||||
@ -121,6 +126,9 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
WorkerDataArray<size_t>* _merge_rs_merged_fine;
|
||||
WorkerDataArray<size_t>* _merge_rs_merged_coarse;
|
||||
|
||||
WorkerDataArray<size_t>* _merge_hcc_dirty_cards;
|
||||
WorkerDataArray<size_t>* _merge_hcc_skipped_cards;
|
||||
|
||||
WorkerDataArray<size_t>* _merge_lb_processed_buffers;
|
||||
WorkerDataArray<size_t>* _merge_lb_dirty_cards;
|
||||
WorkerDataArray<size_t>* _merge_lb_skipped_cards;
|
||||
|
||||
83
src/hotspot/share/gc/g1/g1ParallelCleaning.cpp
Normal file
83
src/hotspot/share/gc/g1/g1ParallelCleaning.cpp
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
66
src/hotspot/share/gc/g1/g1ParallelCleaning.hpp
Normal file
66
src/hotspot/share/gc/g1/g1ParallelCleaning.hpp
Normal file
@ -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
|
||||
@ -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(G1RedirtyCardsQueueSet* shared_qse
|
||||
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 @@ void G1RedirtyCardsQueueBase::LocalQSet::enqueue_completed_buffer(BufferNode* no
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ void G1RedirtyCardsQueue::flush() {
|
||||
G1RedirtyCardsQueueSet::G1RedirtyCardsQueueSet() :
|
||||
PtrQueueSet(),
|
||||
_list(),
|
||||
_count(0),
|
||||
_entry_count(0),
|
||||
_tail(NULL)
|
||||
DEBUG_ONLY(COMMA _collecting(true))
|
||||
{}
|
||||
@ -116,7 +115,7 @@ G1RedirtyCardsQueueSet::~G1RedirtyCardsQueueSet() {
|
||||
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 @@ BufferNode* G1RedirtyCardsQueueSet::all_completed_buffers() const {
|
||||
|
||||
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::update_tail(BufferNode* node) {
|
||||
|
||||
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 @@ void G1RedirtyCardsQueueSet::merge_bufferlist(LocalQSet* src) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -36,10 +36,10 @@ class G1RedirtyCardsQueueSet;
|
||||
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 @@ class G1RedirtyCardsQueueSet : public PtrQueueSet {
|
||||
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;)
|
||||
|
||||
@ -94,24 +94,35 @@ class G1RemSetScanState : public CHeapObj<mtGC> {
|
||||
// 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 @@ public:
|
||||
_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 @@ public:
|
||||
_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 @@ public:
|
||||
_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 @@ public:
|
||||
|
||||
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 @@ public:
|
||||
}
|
||||
|
||||
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 @@ public:
|
||||
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.
|
||||
|
||||
@ -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 @@ void KlassCleaningTask::work() {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 @@ public:
|
||||
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
|
||||
|
||||
@ -760,6 +760,10 @@ Symbol* ConstantPool::exception_message(const constantPoolHandle& this_cp, int w
|
||||
// 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();
|
||||
}
|
||||
|
||||
@ -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 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError;
|
||||
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 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError;
|
||||
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);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -88,18 +88,20 @@ public class VerifyAccess {
|
||||
* @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 @@ public class VerifyAccess {
|
||||
|
||||
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 @@ public class VerifyAccess {
|
||||
* package that is exported to the module that contains D.
|
||||
* <li>C and D are members of the same runtime package.
|
||||
* </ul>
|
||||
*
|
||||
* @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 @@ public class VerifyAccess {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
48
test/hotspot/jtreg/gc/g1/TestNoUseHCC.java
Normal file
48
test/hotspot/jtreg/gc/g1/TestNoUseHCC.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
65
test/hotspot/jtreg/runtime/condy/staticInit/Example.jasm
Normal file
65
test/hotspot/jtreg/runtime/condy/staticInit/Example.jasm
Normal file
@ -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
|
||||
33
test/hotspot/jtreg/runtime/condy/staticInit/StaticInit.java
Normal file
33
test/hotspot/jtreg/runtime/condy/staticInit/StaticInit.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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.<clinit>(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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.invoke.*;
|
||||
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 @@ public class AccessControlTest {
|
||||
private class LookupCase implements Comparable<LookupCase> {
|
||||
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 class AccessControlTest {
|
||||
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 class AccessControlTest {
|
||||
}
|
||||
public boolean equals(LookupCase that) {
|
||||
return (this.lookupClass() == that.lookupClass() &&
|
||||
this.prevLookupClass() == that.prevLookupClass() &&
|
||||
this.lookupModes() == that.lookupModes());
|
||||
}
|
||||
|
||||
@ -113,20 +130,25 @@ public class AccessControlTest {
|
||||
/** 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 @@ public class AccessControlTest {
|
||||
* Creates a lookup on the specified new lookup class.
|
||||
* [A1] The resulting object will report the specified
|
||||
* class as its own {@link #lookupClass lookupClass}.
|
||||
* <p>
|
||||
* [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:<ul>
|
||||
* <li> [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.
|
||||
* <li> [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.
|
||||
* <li> [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.)
|
||||
* <li> [A6] If the new lookup class is in a different package than the old one,
|
||||
* protected and default (package) members will not be accessible.
|
||||
* <li> [A7] If the new lookup class is not within the same package member
|
||||
* as the old one, private members will not be accessible.
|
||||
* <li> [A8] If the new lookup class is not accessible to the old lookup class,
|
||||
* then no members, not even public members, will be accessible.
|
||||
* <li> [A9] (In all other cases, public members will continue to be accessible.)
|
||||
* </ul>
|
||||
* [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.
|
||||
* <p>
|
||||
* 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]
|
||||
* <hr>
|
||||
*/
|
||||
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 @@ public class AccessControlTest {
|
||||
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 class AccessControlTest {
|
||||
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 @@ public class AccessControlTest {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 @@ public class AccessControlTest {
|
||||
return i+1;
|
||||
}
|
||||
|
||||
private void addLookupEdge(LookupCase l1, Class<?> c2, LookupCase l2) {
|
||||
private void addLookupEdge(LookupCase l1, Class<?> c2, LookupCase l2, int dropAccess) {
|
||||
TreeSet<LookupCase> edges = CASE_EDGES.get(l2);
|
||||
if (edges == null) CASE_EDGES.put(l2, edges = new TreeSet<>());
|
||||
if (edges.add(l1)) {
|
||||
@ -337,7 +440,7 @@ public class AccessControlTest {
|
||||
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 @@ public class AccessControlTest {
|
||||
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 @@ public class AccessControlTest {
|
||||
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 @@ public class AccessControlTest {
|
||||
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 @@ public class AccessControlTest {
|
||||
}
|
||||
|
||||
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 @@ public class AccessControlTest {
|
||||
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);
|
||||
|
||||
@ -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 @@ public class DropLookupModeTest {
|
||||
assertTrue(lookup.lookupModes() == 0);
|
||||
}
|
||||
|
||||
@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 },
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Test dropLookupMode on the public Lookup.
|
||||
* Test dropLookupMode on the lookup with public lookup
|
||||
* and UNCONDITIONAL
|
||||
*/
|
||||
public void testPublicLookup() {
|
||||
final Lookup publicLookup = MethodHandles.publicLookup();
|
||||
final Class<?> lc = publicLookup.lookupClass();
|
||||
assertTrue(publicLookup.lookupModes() == (PUBLIC|UNCONDITIONAL));
|
||||
@Test(dataProvider = "unconditionals")
|
||||
public void testUnconditionalLookup(Lookup unconditionalLookup, Class<?> expected) {
|
||||
assertTrue(unconditionalLookup.lookupModes() == UNCONDITIONAL);
|
||||
|
||||
Lookup lookup = publicLookup.dropLookupMode(PRIVATE);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC);
|
||||
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(PROTECTED);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC);
|
||||
|
||||
lookup = publicLookup.dropLookupMode(PACKAGE);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC);
|
||||
|
||||
lookup = publicLookup.dropLookupMode(MODULE);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC);
|
||||
|
||||
lookup = publicLookup.dropLookupMode(PUBLIC);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
// drop all access
|
||||
Lookup lookup = unconditionalLookup.dropLookupMode(UNCONDITIONAL);
|
||||
assertTrue(lookup.lookupClass() == expected);
|
||||
assertTrue(lookup.lookupModes() == 0);
|
||||
}
|
||||
|
||||
lookup = publicLookup.dropLookupMode(UNCONDITIONAL);
|
||||
assertTrue(lookup.lookupClass() == lc);
|
||||
assertTrue(lookup.lookupModes() == PUBLIC);
|
||||
private void assertPublicLookup(Lookup lookup, Class<?> expected) {
|
||||
assertTrue(lookup.lookupClass() == expected);
|
||||
assertTrue(lookup.lookupModes() == UNCONDITIONAL);
|
||||
}
|
||||
|
||||
@DataProvider(name = "badInput")
|
||||
@ -157,4 +159,4 @@ public class DropLookupModeTest {
|
||||
MethodHandles.lookup().dropLookupMode(modeToDrop);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 @@ public class PrivateLookupInTests {
|
||||
}
|
||||
|
||||
// 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 @@ public class PrivateLookupInTests {
|
||||
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
|
||||
|
||||
31
test/jdk/java/lang/invoke/modules/Driver1.java
Normal file
31
test/jdk/java/lang/invoke/modules/Driver1.java
Normal file
@ -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
|
||||
*/
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
24
test/jdk/java/lang/invoke/modules/Unnamed1.java
Normal file
24
test/jdk/java/lang/invoke/modules/Unnamed1.java
Normal file
@ -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 { }
|
||||
@ -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 @@ public class Main {
|
||||
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 @@ public class Main {
|
||||
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 @@ public class Main {
|
||||
|
||||
// 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 @@ public class Main {
|
||||
|
||||
// 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 @@ public class Main {
|
||||
/**
|
||||
* 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 @@ public class Main {
|
||||
|
||||
// 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 @@ public class Main {
|
||||
/**
|
||||
* 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 @@ public class Main {
|
||||
|
||||
// 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 @@ public class Main {
|
||||
|
||||
/**
|
||||
* 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 @@ public class Main {
|
||||
|
||||
// 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 @@ public class Main {
|
||||
|
||||
// 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 @@ public class Main {
|
||||
/**
|
||||
* 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 @@ public class Main {
|
||||
|
||||
// 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);
|
||||
|
||||
34
test/jdk/java/lang/invoke/modules/m3/c1/C1.java
Normal file
34
test/jdk/java/lang/invoke/modules/m3/c1/C1.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
27
test/jdk/java/lang/invoke/modules/m3/c1/C2.java
Normal file
27
test/jdk/java/lang/invoke/modules/m3/c1/C2.java
Normal file
@ -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() { }
|
||||
}
|
||||
27
test/jdk/java/lang/invoke/modules/m3/c2/C3.java
Normal file
27
test/jdk/java/lang/invoke/modules/m3/c2/C3.java
Normal file
@ -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() { }
|
||||
}
|
||||
@ -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<String, ModuleLookup> 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<Class<?>> 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<String> 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<Class<?>> 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<Class<?>> 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<Class<?>> 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<Class<?>> 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);
|
||||
}
|
||||
}
|
||||
32
test/jdk/java/lang/invoke/modules/m3/module-info.java
Normal file
32
test/jdk/java/lang/invoke/modules/m3/module-info.java
Normal file
@ -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;
|
||||
}
|
||||
34
test/jdk/java/lang/invoke/modules/m4/d1/D1.java
Normal file
34
test/jdk/java/lang/invoke/modules/m4/d1/D1.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
27
test/jdk/java/lang/invoke/modules/m4/d1/D2.java
Normal file
27
test/jdk/java/lang/invoke/modules/m4/d1/D2.java
Normal file
@ -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() { }
|
||||
}
|
||||
27
test/jdk/java/lang/invoke/modules/m4/d2/D3.java
Normal file
27
test/jdk/java/lang/invoke/modules/m4/d2/D3.java
Normal file
@ -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() { }
|
||||
}
|
||||
28
test/jdk/java/lang/invoke/modules/m4/module-info.java
Normal file
28
test/jdk/java/lang/invoke/modules/m4/module-info.java
Normal file
@ -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;
|
||||
}
|
||||
33
test/jdk/java/lang/invoke/modules/m5/e1/CrackM5Access.java
Normal file
33
test/jdk/java/lang/invoke/modules/m5/e1/CrackM5Access.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
34
test/jdk/java/lang/invoke/modules/m5/e1/E1.java
Normal file
34
test/jdk/java/lang/invoke/modules/m5/e1/E1.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
27
test/jdk/java/lang/invoke/modules/m5/e1/E2.java
Normal file
27
test/jdk/java/lang/invoke/modules/m5/e1/E2.java
Normal file
@ -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() { }
|
||||
}
|
||||
27
test/jdk/java/lang/invoke/modules/m5/e1/NonPublic.java
Normal file
27
test/jdk/java/lang/invoke/modules/m5/e1/NonPublic.java
Normal file
@ -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() { }
|
||||
}
|
||||
29
test/jdk/java/lang/invoke/modules/m5/e1/Statics.java
Normal file
29
test/jdk/java/lang/invoke/modules/m5/e1/Statics.java
Normal file
@ -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() { }
|
||||
}
|
||||
27
test/jdk/java/lang/invoke/modules/m5/e2/E3.java
Normal file
27
test/jdk/java/lang/invoke/modules/m5/e2/E3.java
Normal file
@ -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() { }
|
||||
}
|
||||
28
test/jdk/java/lang/invoke/modules/m5/module-info.java
Normal file
28
test/jdk/java/lang/invoke/modules/m5/module-info.java
Normal file
@ -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;
|
||||
}
|
||||
@ -24,6 +24,7 @@
|
||||
/**
|
||||
* @test
|
||||
* @bug 8179559 8225239
|
||||
* @modules java.base/java.net:open
|
||||
*/
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user