Merge
authorpsadhukhan
Thu, 25 Jul 2019 12:23:54 +0530
changeset 57927 b0aaa82a1b03
parent 57926 70865ef2afc7 (current diff)
parent 57528 3307a6ded22d (diff)
child 57928 f95327be136a
Merge
test/jdk/ProblemList.txt
--- a/.hgtags	Wed Jul 24 12:49:44 2019 +0530
+++ b/.hgtags	Thu Jul 25 12:23:54 2019 +0530
@@ -575,3 +575,4 @@
 0f1e29c77e50c7da11d83df410026392c4d1a28c jdk-14+5
 2e63fb0a885fa908a97bbb0da8d7c3de11536aca jdk-13+30
 443f7359b34d60e7821216ffc60f88b6ffe0ccdd jdk-14+6
+28ab01c067551ef158abaef08e154e1051ca0893 jdk-14+7
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp	Thu Jul 25 12:23:54 2019 +0530
@@ -2040,17 +2040,6 @@
   bind(L_fallthrough);
 }
 
-void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg,
-                                              Register temp_reg,
-                                              Label& wrong_method_type) {
-  assert_different_registers(mtype_reg, mh_reg, temp_reg);
-  // Compare method type against that of the receiver.
-  load_heap_oop(temp_reg, delayed_value(java_lang_invoke_MethodHandle::type_offset_in_bytes, temp_reg), mh_reg,
-                noreg, noreg, false, IS_NOT_NULL);
-  cmpd(CCR0, temp_reg, mtype_reg);
-  bne(CCR0, wrong_method_type);
-}
-
 RegisterOrConstant MacroAssembler::argument_offset(RegisterOrConstant arg_slot,
                                                    Register temp_reg,
                                                    int extra_slot_offset) {
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp	Thu Jul 25 12:23:54 2019 +0530
@@ -565,8 +565,6 @@
                       Label* L_slow_path = NULL);
 
   // Method handle support (JSR 292).
-  void check_method_handle_type(Register mtype_reg, Register mh_reg, Register temp_reg, Label& wrong_method_type);
-
   RegisterOrConstant argument_offset(RegisterOrConstant arg_slot, Register temp_reg, int extra_slot_offset = 0);
 
   // Biased locking support
--- a/src/hotspot/share/asm/assembler.cpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/asm/assembler.cpp	Thu Jul 25 12:23:54 2019 +0530
@@ -218,85 +218,6 @@
   }
 }
 
-struct DelayedConstant {
-  typedef void (*value_fn_t)();
-  BasicType type;
-  intptr_t value;
-  value_fn_t value_fn;
-  // This limit of 20 is generous for initial uses.
-  // The limit needs to be large enough to store the field offsets
-  // into classes which do not have statically fixed layouts.
-  // (Initial use is for method handle object offsets.)
-  // Look for uses of "delayed_value" in the source code
-  // and make sure this number is generous enough to handle all of them.
-  enum { DC_LIMIT = 20 };
-  static DelayedConstant delayed_constants[DC_LIMIT];
-  static DelayedConstant* add(BasicType type, value_fn_t value_fn);
-  bool match(BasicType t, value_fn_t cfn) {
-    return type == t && value_fn == cfn;
-  }
-  static void update_all();
-};
-
-DelayedConstant DelayedConstant::delayed_constants[DC_LIMIT];
-// Default C structure initialization rules have the following effect here:
-// = { { (BasicType)0, (intptr_t)NULL }, ... };
-
-DelayedConstant* DelayedConstant::add(BasicType type,
-                                      DelayedConstant::value_fn_t cfn) {
-  for (int i = 0; i < DC_LIMIT; i++) {
-    DelayedConstant* dcon = &delayed_constants[i];
-    if (dcon->match(type, cfn))
-      return dcon;
-    if (dcon->value_fn == NULL) {
-        dcon->value_fn = cfn;
-        dcon->type = type;
-        return dcon;
-    }
-  }
-  // If this assert is hit (in pre-integration testing!) then re-evaluate
-  // the comment on the definition of DC_LIMIT.
-  guarantee(false, "too many delayed constants");
-  return NULL;
-}
-
-void DelayedConstant::update_all() {
-  for (int i = 0; i < DC_LIMIT; i++) {
-    DelayedConstant* dcon = &delayed_constants[i];
-    if (dcon->value_fn != NULL && dcon->value == 0) {
-      typedef int     (*int_fn_t)();
-      typedef address (*address_fn_t)();
-      switch (dcon->type) {
-      case T_INT:     dcon->value = (intptr_t) ((int_fn_t)    dcon->value_fn)(); break;
-      case T_ADDRESS: dcon->value = (intptr_t) ((address_fn_t)dcon->value_fn)(); break;
-      default:        break;
-      }
-    }
-  }
-}
-
-RegisterOrConstant AbstractAssembler::delayed_value(int(*value_fn)(), Register tmp, int offset) {
-  intptr_t val = (intptr_t) (*value_fn)();
-  if (val != 0)  return val + offset;
-  return delayed_value_impl(delayed_value_addr(value_fn), tmp, offset);
-}
-RegisterOrConstant AbstractAssembler::delayed_value(address(*value_fn)(), Register tmp, int offset) {
-  intptr_t val = (intptr_t) (*value_fn)();
-  if (val != 0)  return val + offset;
-  return delayed_value_impl(delayed_value_addr(value_fn), tmp, offset);
-}
-intptr_t* AbstractAssembler::delayed_value_addr(int(*value_fn)()) {
-  DelayedConstant* dcon = DelayedConstant::add(T_INT, (DelayedConstant::value_fn_t) value_fn);
-  return &dcon->value;
-}
-intptr_t* AbstractAssembler::delayed_value_addr(address(*value_fn)()) {
-  DelayedConstant* dcon = DelayedConstant::add(T_ADDRESS, (DelayedConstant::value_fn_t) value_fn);
-  return &dcon->value;
-}
-void AbstractAssembler::update_delayed_values() {
-  DelayedConstant::update_all();
-}
-
 void AbstractAssembler::block_comment(const char* comment) {
   if (sect() == CodeBuffer::SECT_INSTS) {
     code_section()->outer()->block_comment(offset(), comment);
--- a/src/hotspot/share/classfile/javaClasses.cpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Thu Jul 25 12:23:54 2019 +0530
@@ -4547,9 +4547,6 @@
   // BASIC_JAVA_CLASSES_DO_PART1 classes (java_lang_String and java_lang_Class)
   // earlier inside SystemDictionary::resolve_well_known_classes()
   BASIC_JAVA_CLASSES_DO_PART2(DO_COMPUTE_OFFSETS);
-
-  // generated interpreter code wants to know about the offsets we just computed:
-  AbstractAssembler::update_delayed_values();
 }
 
 #if INCLUDE_CDS
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Thu Jul 25 12:23:54 2019 +0530
@@ -48,6 +48,7 @@
 #include "gc/g1/g1HotCardCache.hpp"
 #include "gc/g1/g1MemoryPool.hpp"
 #include "gc/g1/g1OopClosures.inline.hpp"
+#include "gc/g1/g1ParallelCleaning.hpp"
 #include "gc/g1/g1ParScanThreadState.inline.hpp"
 #include "gc/g1/g1Policy.hpp"
 #include "gc/g1/g1RedirtyCardsQueue.hpp"
@@ -74,7 +75,6 @@
 #include "gc/shared/generationSpec.hpp"
 #include "gc/shared/isGCActiveMark.hpp"
 #include "gc/shared/oopStorageParState.hpp"
-#include "gc/shared/parallelCleaning.hpp"
 #include "gc/shared/preservedMarks.inline.hpp"
 #include "gc/shared/suspendibleThreadSet.hpp"
 #include "gc/shared/referenceProcessor.inline.hpp"
@@ -1080,7 +1080,7 @@
 
   // Discard all remembered set updates.
   G1BarrierSet::dirty_card_queue_set().abandon_logs();
-  assert(G1BarrierSet::dirty_card_queue_set().completed_buffers_num() == 0,
+  assert(G1BarrierSet::dirty_card_queue_set().num_completed_buffers() == 0,
          "DCQS should be empty");
   redirty_cards_queue_set().verify_empty();
 }
@@ -1957,7 +1957,7 @@
   while (dcqs.apply_closure_during_gc(cl, worker_i)) {
     n_completed_buffers++;
   }
-  assert(dcqs.completed_buffers_num() == 0, "Completed buffers exist!");
+  assert(dcqs.num_completed_buffers() == 0, "Completed buffers exist!");
   phase_times()->record_thread_work_item(G1GCPhaseTimes::MergeLB, worker_i, n_completed_buffers, G1GCPhaseTimes::MergeLBProcessedBuffers);
 }
 
@@ -2613,10 +2613,9 @@
   Threads::threads_do(&count_from_threads);
 
   G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
-  size_t buffer_size = dcqs.buffer_size();
-  size_t buffer_num = dcqs.completed_buffers_num();
-
-  return buffer_size * buffer_num + count_from_threads._cards;
+  dcqs.verify_num_entries_in_completed_buffers();
+
+  return dcqs.num_entries_in_completed_buffers() + count_from_threads._cards;
 }
 
 bool G1CollectedHeap::is_potential_eager_reclaim_candidate(HeapRegion* r) const {
@@ -3166,7 +3165,7 @@
 void G1CollectedHeap::complete_cleaning(BoolObjectClosure* is_alive,
                                         bool class_unloading_occurred) {
   uint num_workers = workers()->active_workers();
-  ParallelCleaningTask unlink_task(is_alive, num_workers, class_unloading_occurred, false);
+  G1ParallelCleaningTask unlink_task(is_alive, num_workers, class_unloading_occurred, false);
   workers()->run_task(&unlink_task);
 }
 
--- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp	Thu Jul 25 12:23:54 2019 +0530
@@ -397,7 +397,7 @@
     dcqs.set_max_completed_buffers(red_zone());
   }
 
-  size_t curr_queue_size = dcqs.completed_buffers_num();
+  size_t curr_queue_size = dcqs.num_completed_buffers();
   if ((dcqs.max_completed_buffers() > 0) &&
       (curr_queue_size >= yellow_zone())) {
     dcqs.set_completed_buffers_padding(curr_queue_size);
@@ -430,7 +430,7 @@
 bool G1ConcurrentRefine::do_refinement_step(uint worker_id) {
   G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
 
-  size_t curr_buffer_num = dcqs.completed_buffers_num();
+  size_t curr_buffer_num = dcqs.num_completed_buffers();
   // If the number of the buffers falls down into the yellow zone,
   // that means that the transition period after the evacuation pause has ended.
   // Since the value written to the DCQS is the same for all threads, there is no
--- a/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp	Thu Jul 25 12:23:54 2019 +0530
@@ -104,7 +104,7 @@
     size_t buffers_processed = 0;
     log_debug(gc, refine)("Activated worker %d, on threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT,
                           _worker_id, _cr->activation_threshold(_worker_id),
-                           G1BarrierSet::dirty_card_queue_set().completed_buffers_num());
+                           G1BarrierSet::dirty_card_queue_set().num_completed_buffers());
 
     {
       SuspendibleThreadSetJoiner sts_join;
@@ -126,7 +126,7 @@
     log_debug(gc, refine)("Deactivated worker %d, off threshold: " SIZE_FORMAT
                           ", current: " SIZE_FORMAT ", processed: " SIZE_FORMAT,
                           _worker_id, _cr->deactivation_threshold(_worker_id),
-                          G1BarrierSet::dirty_card_queue_set().completed_buffers_num(),
+                          G1BarrierSet::dirty_card_queue_set().num_completed_buffers(),
                           buffers_processed);
 
     if (os::supports_vtime()) {
--- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp	Thu Jul 25 12:23:54 2019 +0530
@@ -84,7 +84,7 @@
   _cbl_mon(NULL),
   _completed_buffers_head(NULL),
   _completed_buffers_tail(NULL),
-  _n_completed_buffers(0),
+  _num_entries_in_completed_buffers(0),
   _process_completed_buffers_threshold(ProcessCompletedBuffersThresholdNever),
   _process_completed_buffers(false),
   _notify_when_complete(notify_when_complete),
@@ -133,42 +133,56 @@
     _completed_buffers_tail->set_next(cbn);
     _completed_buffers_tail = cbn;
   }
-  _n_completed_buffers++;
+  _num_entries_in_completed_buffers += buffer_size() - cbn->index();
 
   if (!process_completed_buffers() &&
-      (_n_completed_buffers > process_completed_buffers_threshold())) {
+      (num_completed_buffers() > process_completed_buffers_threshold())) {
     set_process_completed_buffers(true);
     if (_notify_when_complete) {
       _cbl_mon->notify_all();
     }
   }
-  assert_completed_buffers_list_len_correct_locked();
+  verify_num_entries_in_completed_buffers();
 }
 
 BufferNode* G1DirtyCardQueueSet::get_completed_buffer(size_t stop_at) {
   MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
 
-  if (_n_completed_buffers <= stop_at) {
+  if (num_completed_buffers() <= stop_at) {
     return NULL;
   }
 
-  assert(_n_completed_buffers > 0, "invariant");
+  assert(num_completed_buffers() > 0, "invariant");
   assert(_completed_buffers_head != NULL, "invariant");
   assert(_completed_buffers_tail != NULL, "invariant");
 
   BufferNode* bn = _completed_buffers_head;
-  _n_completed_buffers--;
+  _num_entries_in_completed_buffers -= buffer_size() - bn->index();
   _completed_buffers_head = bn->next();
   if (_completed_buffers_head == NULL) {
-    assert(_n_completed_buffers == 0, "invariant");
+    assert(num_completed_buffers() == 0, "invariant");
     _completed_buffers_tail = NULL;
     set_process_completed_buffers(false);
   }
-  assert_completed_buffers_list_len_correct_locked();
+  verify_num_entries_in_completed_buffers();
   bn->set_next(NULL);
   return bn;
 }
 
+#ifdef ASSERT
+void G1DirtyCardQueueSet::verify_num_entries_in_completed_buffers() const {
+  size_t actual = 0;
+  BufferNode* cur = _completed_buffers_head;
+  while (cur != NULL) {
+    actual += buffer_size() - cur->index();
+    cur = cur->next();
+  }
+  assert(actual == _num_entries_in_completed_buffers,
+         "Num entries in completed buffers should be " SIZE_FORMAT " but are " SIZE_FORMAT,
+         _num_entries_in_completed_buffers, actual);
+}
+#endif
+
 void G1DirtyCardQueueSet::abandon_completed_buffers() {
   BufferNode* buffers_to_delete = NULL;
   {
@@ -176,7 +190,7 @@
     buffers_to_delete = _completed_buffers_head;
     _completed_buffers_head = NULL;
     _completed_buffers_tail = NULL;
-    _n_completed_buffers = 0;
+    _num_entries_in_completed_buffers = 0;
     set_process_completed_buffers(false);
   }
   while (buffers_to_delete != NULL) {
@@ -189,26 +203,13 @@
 
 void G1DirtyCardQueueSet::notify_if_necessary() {
   MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
-  if (_n_completed_buffers > process_completed_buffers_threshold()) {
+  if (num_completed_buffers() > process_completed_buffers_threshold()) {
     set_process_completed_buffers(true);
     if (_notify_when_complete)
       _cbl_mon->notify();
   }
 }
 
-#ifdef ASSERT
-void G1DirtyCardQueueSet::assert_completed_buffers_list_len_correct_locked() {
-  assert_lock_strong(_cbl_mon);
-  size_t n = 0;
-  for (BufferNode* bn = _completed_buffers_head; bn != NULL; bn = bn->next()) {
-    ++n;
-  }
-  assert(n == _n_completed_buffers,
-         "Completed buffer length is wrong: counted: " SIZE_FORMAT
-         ", expected: " SIZE_FORMAT, n, _n_completed_buffers);
-}
-#endif // ASSERT
-
 // Merge lists of buffers. Notify the processing threads.
 // The source queue is emptied as a result. The queues
 // must share the monitor.
@@ -227,12 +228,12 @@
     _completed_buffers_tail->set_next(from._head);
     _completed_buffers_tail = from._tail;
   }
-  _n_completed_buffers += from._count;
+  _num_entries_in_completed_buffers += from._entry_count;
 
   assert(_completed_buffers_head == NULL && _completed_buffers_tail == NULL ||
          _completed_buffers_head != NULL && _completed_buffers_tail != NULL,
          "Sanity");
-  assert_completed_buffers_list_len_correct_locked();
+  verify_num_entries_in_completed_buffers();
 }
 
 bool G1DirtyCardQueueSet::apply_closure_to_buffer(G1CardTableEntryClosure* cl,
@@ -278,7 +279,7 @@
     // add of padding could overflow, which is treated as unlimited.
     size_t max_buffers = max_completed_buffers();
     size_t limit = max_buffers + completed_buffers_padding();
-    if ((completed_buffers_num() > limit) && (limit >= max_buffers)) {
+    if ((num_completed_buffers() > limit) && (limit >= max_buffers)) {
       if (mut_process_buffer(node)) {
         return true;
       }
--- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp	Thu Jul 25 12:23:54 2019 +0530
@@ -69,7 +69,9 @@
   Monitor* _cbl_mon;  // Protects the fields below.
   BufferNode* _completed_buffers_head;
   BufferNode* _completed_buffers_tail;
-  volatile size_t _n_completed_buffers;
+
+  // Number of actual entries in the list of completed buffers.
+  volatile size_t _num_entries_in_completed_buffers;
 
   size_t _process_completed_buffers_threshold;
   volatile bool _process_completed_buffers;
@@ -77,8 +79,6 @@
   // If true, notify_all on _cbl_mon when the threshold is reached.
   bool _notify_when_complete;
 
-  void assert_completed_buffers_list_len_correct_locked() NOT_DEBUG_RETURN;
-
   void abandon_completed_buffers();
 
   // Apply the closure to the elements of "node" from it's index to
@@ -150,8 +150,17 @@
   // return a completed buffer from the list.  Otherwise, return NULL.
   BufferNode* get_completed_buffer(size_t stop_at = 0);
 
-  // The number of buffers in the list.  Racy...
-  size_t completed_buffers_num() const { return _n_completed_buffers; }
+  // The number of buffers in the list. Derived as an approximation from the number
+  // of entries in the buffers. Racy.
+  size_t num_completed_buffers() const {
+    return (num_entries_in_completed_buffers() + buffer_size() - 1) / buffer_size();
+  }
+  // The number of entries in completed buffers. Read without synchronization.
+  size_t num_entries_in_completed_buffers() const { return _num_entries_in_completed_buffers; }
+
+  // Verify that _num_entries_in_completed_buffers is equal to the sum of actual entries
+  // in the completed buffers.
+  void verify_num_entries_in_completed_buffers() const NOT_DEBUG_RETURN;
 
   bool process_completed_buffers() { return _process_completed_buffers; }
   void set_process_completed_buffers(bool x) { _process_completed_buffers = x; }
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp	Thu Jul 25 12:23:54 2019 +0530
@@ -86,8 +86,14 @@
   _gc_par_phases[MergeLB] = new WorkerDataArray<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):");
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp	Thu Jul 25 12:23:54 2019 +0530
@@ -100,6 +100,11 @@
     ScanHRUsedMemory
   };
 
+  enum GCMergeHCCWorkItems {
+    MergeHCCDirtyCards,
+    MergeHCCSkippedCards
+  };
+
   enum GCMergeLBWorkItems {
     MergeLBProcessedBuffers,
     MergeLBDirtyCards,
@@ -121,6 +126,9 @@
   WorkerDataArray<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;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+
+#include "gc/g1/g1ParallelCleaning.hpp"
+#if INCLUDE_JVMCI
+#include "jvmci/jvmci.hpp"
+#endif
+
+#if INCLUDE_JVMCI
+JVMCICleaningTask::JVMCICleaningTask() :
+  _cleaning_claimed(0) {
+}
+
+bool JVMCICleaningTask::claim_cleaning_task() {
+  if (_cleaning_claimed) {
+    return false;
+  }
+
+  return Atomic::cmpxchg(1, &_cleaning_claimed, 0) == 0;
+}
+
+void JVMCICleaningTask::work(bool unloading_occurred) {
+  // One worker will clean JVMCI metadata handles.
+  if (unloading_occurred && EnableJVMCI && claim_cleaning_task()) {
+    JVMCI::do_unloading(unloading_occurred);
+  }
+}
+#endif // INCLUDE_JVMCI
+
+G1ParallelCleaningTask::G1ParallelCleaningTask(BoolObjectClosure* is_alive,
+                                               uint num_workers,
+                                               bool unloading_occurred,
+                                               bool resize_dedup_table) :
+  AbstractGangTask("G1 Parallel Cleaning"),
+  _unloading_occurred(unloading_occurred),
+  _string_dedup_task(is_alive, NULL, resize_dedup_table),
+  _code_cache_task(num_workers, is_alive, unloading_occurred),
+  JVMCI_ONLY(_jvmci_cleaning_task() COMMA)
+  _klass_cleaning_task() {
+}
+
+// The parallel work done by all worker threads.
+void G1ParallelCleaningTask::work(uint worker_id) {
+  // Clean JVMCI metadata handles.
+  // Execute this task first because it is serial task.
+  JVMCI_ONLY(_jvmci_cleaning_task.work(_unloading_occurred);)
+
+  // Do first pass of code cache cleaning.
+  _code_cache_task.work(worker_id);
+
+  // Clean the string dedup data structures.
+  _string_dedup_task.work(worker_id);
+
+  // Clean all klasses that were not unloaded.
+  // The weak metadata in klass doesn't need to be
+  // processed if there was no unloading.
+  if (_unloading_occurred) {
+    _klass_cleaning_task.work();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/g1ParallelCleaning.hpp	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_GC_G1_G1PARALLELCLEANING_HPP
+#define SHARE_GC_G1_G1PARALLELCLEANING_HPP
+
+#include "gc/shared/parallelCleaning.hpp"
+
+#if INCLUDE_JVMCI
+class JVMCICleaningTask : public StackObj {
+  volatile int       _cleaning_claimed;
+
+public:
+  JVMCICleaningTask();
+  // Clean JVMCI metadata handles.
+  void work(bool unloading_occurred);
+
+private:
+  bool claim_cleaning_task();
+};
+#endif
+
+// Do cleanup of some weakly held data in the same parallel task.
+// Assumes a non-moving context.
+class G1ParallelCleaningTask : public AbstractGangTask {
+private:
+  bool                    _unloading_occurred;
+  StringDedupCleaningTask _string_dedup_task;
+  CodeCacheUnloadingTask  _code_cache_task;
+#if INCLUDE_JVMCI
+  JVMCICleaningTask       _jvmci_cleaning_task;
+#endif
+  KlassCleaningTask       _klass_cleaning_task;
+
+public:
+  // The constructor is run in the VMThread.
+  G1ParallelCleaningTask(BoolObjectClosure* is_alive,
+                         uint num_workers,
+                         bool unloading_occurred,
+                         bool resize_dedup_table);
+
+  void work(uint worker_id);
+};
+
+#endif // SHARE_GC_G1_G1PARALLELCLEANING_HPP
--- a/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp	Thu Jul 25 12:23:54 2019 +0530
@@ -31,15 +31,15 @@
 // G1RedirtyCardsBufferList
 
 G1RedirtyCardsBufferList::G1RedirtyCardsBufferList() :
-  _head(NULL), _tail(NULL), _count(0) {}
+  _head(NULL), _tail(NULL), _entry_count(0) {}
 
 G1RedirtyCardsBufferList::G1RedirtyCardsBufferList(BufferNode* head,
                                                    BufferNode* tail,
-                                                   size_t count) :
-  _head(head), _tail(tail), _count(count)
+                                                   size_t entry_count) :
+  _head(head), _tail(tail), _entry_count(entry_count)
 {
   assert((_head == NULL) == (_tail == NULL), "invariant");
-  assert((_head == NULL) == (_count == 0), "invariant");
+  assert((_head == NULL) == (_entry_count == 0), "invariant");
 }
 
 // G1RedirtyCardsQueueBase::LocalQSet
@@ -55,11 +55,11 @@
 G1RedirtyCardsQueueBase::LocalQSet::~LocalQSet() {
   assert(_buffers._head == NULL, "unflushed qset");
   assert(_buffers._tail == NULL, "invariant");
-  assert(_buffers._count == 0, "invariant");
+  assert(_buffers._entry_count == 0, "invariant");
 }
 
 void G1RedirtyCardsQueueBase::LocalQSet::enqueue_completed_buffer(BufferNode* node) {
-  ++_buffers._count;
+  _buffers._entry_count += buffer_size() - node->index();
   node->set_next(_buffers._head);
   _buffers._head = node;
   if (_buffers._tail == NULL) {
@@ -67,8 +67,7 @@
   }
 }
 
-G1RedirtyCardsBufferList
-G1RedirtyCardsQueueBase::LocalQSet::take_all_completed_buffers() {
+G1RedirtyCardsBufferList G1RedirtyCardsQueueBase::LocalQSet::take_all_completed_buffers() {
   G1RedirtyCardsBufferList result = _buffers;
   _buffers = G1RedirtyCardsBufferList();
   return result;
@@ -103,7 +102,7 @@
 G1RedirtyCardsQueueSet::G1RedirtyCardsQueueSet() :
   PtrQueueSet(),
   _list(),
-  _count(0),
+  _entry_count(0),
   _tail(NULL)
   DEBUG_ONLY(COMMA _collecting(true))
 {}
@@ -116,7 +115,7 @@
 void G1RedirtyCardsQueueSet::verify_empty() const {
   assert(_list.empty(), "precondition");
   assert(_tail == NULL, "invariant");
-  assert(_count == 0, "invariant");
+  assert(_entry_count == 0, "invariant");
 }
 #endif // ASSERT
 
@@ -127,9 +126,9 @@
 
 G1RedirtyCardsBufferList G1RedirtyCardsQueueSet::take_all_completed_buffers() {
   DEBUG_ONLY(_collecting = false;)
-  G1RedirtyCardsBufferList result(_list.pop_all(), _tail, _count);
+  G1RedirtyCardsBufferList result(_list.pop_all(), _tail, _entry_count);
   _tail = NULL;
-  _count = 0;
+  _entry_count = 0;
   DEBUG_ONLY(_collecting = true;)
   return result;
 }
@@ -146,7 +145,7 @@
 
 void G1RedirtyCardsQueueSet::enqueue_completed_buffer(BufferNode* node) {
   assert(_collecting, "precondition");
-  Atomic::inc(&_count);
+  Atomic::add(buffer_size() - node->index(), &_entry_count);
   _list.push(*node);
   update_tail(node);
 }
@@ -156,7 +155,7 @@
   const G1RedirtyCardsBufferList from = src->take_all_completed_buffers();
   if (from._head != NULL) {
     assert(from._tail != NULL, "invariant");
-    Atomic::add(from._count, &_count);
+    Atomic::add(from._entry_count, &_entry_count);
     _list.prepend(*from._head, *from._tail);
     update_tail(from._tail);
   }
--- a/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp	Thu Jul 25 12:23:54 2019 +0530
@@ -36,10 +36,10 @@
 struct G1RedirtyCardsBufferList {
   BufferNode* _head;
   BufferNode* _tail;
-  size_t _count;
+  size_t _entry_count;
 
   G1RedirtyCardsBufferList();
-  G1RedirtyCardsBufferList(BufferNode* head, BufferNode* tail, size_t count);
+  G1RedirtyCardsBufferList(BufferNode* head, BufferNode* tail, size_t entry_count);
 };
 
 // Provide G1RedirtyCardsQueue with a thread-local qset.  It provides an
@@ -100,7 +100,7 @@
   DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
   BufferNode::Stack _list;
   DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, sizeof(size_t));
-  volatile size_t _count;
+  volatile size_t _entry_count;
   DEFINE_PAD_MINUS_SIZE(3, DEFAULT_CACHE_LINE_SIZE, sizeof(BufferNode*));
   BufferNode* _tail;
   DEBUG_ONLY(mutable bool _collecting;)
--- a/src/hotspot/share/gc/g1/g1RemSet.cpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1RemSet.cpp	Thu Jul 25 12:23:54 2019 +0530
@@ -94,24 +94,35 @@
   // to (>=) HeapRegion::CardsPerRegion (completely scanned).
   uint volatile* _card_table_scan_state;
 
-  // Random power of two number of cards we want to claim per thread. This corresponds
-  // to a 64k of memory work chunk area for every thread.
-  // We use the same claim size as Parallel GC. No particular measurements have been
-  // performed to determine an optimal number.
-  static const uint CardsPerChunk = 128;
+  // Return "optimal" number of chunks per region we want to use for claiming areas
+  // within a region to claim. Dependent on the region size as proxy for the heap
+  // size, we limit the total number of chunks to limit memory usage and maintenance
+  // effort of that table vs. granularity of distributing scanning work.
+  // Testing showed that 8 for 1M/2M region, 16 for 4M/8M regions, 32 for 16/32M regions
+  // seems to be such a good trade-off.
+  static uint get_chunks_per_region(uint log_region_size) {
+    // Limit the expected input values to current known possible values of the
+    // (log) region size. Adjust as necessary after testing if changing the permissible
+    // values for region size.
+    assert(log_region_size >= 20 && log_region_size <= 25,
+           "expected value in [20,25], but got %u", log_region_size);
+    return 1u << (log_region_size / 2 - 7);
+  }
 
-  uint _scan_chunks_per_region;
+  uint _scan_chunks_per_region;         // Number of chunks per region.
+  uint8_t _log_scan_chunks_per_region;  // Log of number of chunks per region.
   bool* _region_scan_chunks;
-  uint8_t _scan_chunks_shift;
+  size_t _num_total_scan_chunks;        // Total number of elements in _region_scan_chunks.
+  uint8_t _scan_chunks_shift;           // For conversion between card index and chunk index.
 public:
   uint scan_chunk_size() const { return (uint)1 << _scan_chunks_shift; }
 
   // Returns whether the chunk corresponding to the given region/card in region contain a
   // dirty card, i.e. actually needs scanning.
   bool chunk_needs_scan(uint const region_idx, uint const card_in_region) const {
-    size_t const idx = (size_t)region_idx * _scan_chunks_per_region + (card_in_region >> _scan_chunks_shift);
-    assert(idx < (_max_regions * _scan_chunks_per_region), "Index " SIZE_FORMAT " out of bounds " SIZE_FORMAT,
-           idx, _max_regions * _scan_chunks_per_region);
+    size_t const idx = ((size_t)region_idx << _log_scan_chunks_per_region) + (card_in_region >> _scan_chunks_shift);
+    assert(idx < _num_total_scan_chunks, "Index " SIZE_FORMAT " out of bounds " SIZE_FORMAT,
+           idx, _num_total_scan_chunks);
     return _region_scan_chunks[idx];
   }
 
@@ -286,8 +297,10 @@
     _max_regions(0),
     _collection_set_iter_state(NULL),
     _card_table_scan_state(NULL),
-    _scan_chunks_per_region((uint)(HeapRegion::CardsPerRegion / CardsPerChunk)),
+    _scan_chunks_per_region(get_chunks_per_region(HeapRegion::LogOfHRGrainBytes)),
+    _log_scan_chunks_per_region(log2_uint(_scan_chunks_per_region)),
     _region_scan_chunks(NULL),
+    _num_total_scan_chunks(0),
     _scan_chunks_shift(0),
     _all_dirty_regions(NULL),
     _next_dirty_regions(NULL),
@@ -306,7 +319,8 @@
     _max_regions = max_regions;
     _collection_set_iter_state = NEW_C_HEAP_ARRAY(G1RemsetIterState, max_regions, mtGC);
     _card_table_scan_state = NEW_C_HEAP_ARRAY(uint, max_regions, mtGC);
-    _region_scan_chunks = NEW_C_HEAP_ARRAY(bool, max_regions * _scan_chunks_per_region, mtGC);
+    _num_total_scan_chunks = max_regions * _scan_chunks_per_region;
+    _region_scan_chunks = NEW_C_HEAP_ARRAY(bool, _num_total_scan_chunks, mtGC);
 
     _scan_chunks_shift = (uint8_t)log2_intptr(HeapRegion::CardsPerRegion / _scan_chunks_per_region);
     _scan_top = NEW_C_HEAP_ARRAY(HeapWord*, max_regions, mtGC);
@@ -333,7 +347,7 @@
       _card_table_scan_state[i] = 0;
     }
 
-    ::memset(_region_scan_chunks, false, _max_regions * _scan_chunks_per_region * sizeof(*_region_scan_chunks));
+    ::memset(_region_scan_chunks, false, _num_total_scan_chunks * sizeof(*_region_scan_chunks));
   }
 
   // Returns whether the given region contains cards we need to scan. The remembered
@@ -349,12 +363,12 @@
 
   size_t num_visited_cards() const {
     size_t result = 0;
-    for (uint i = 0; i < _max_regions * _scan_chunks_per_region; i++) {
+    for (uint i = 0; i < _num_total_scan_chunks; i++) {
       if (_region_scan_chunks[i]) {
         result++;
       }
     }
-    return result * CardsPerChunk;
+    return result * (HeapRegion::CardsPerRegion / _scan_chunks_per_region);
   }
 
   size_t num_cards_in_dirty_regions() const {
@@ -369,9 +383,9 @@
   }
 
   void set_chunk_dirty(size_t const card_idx) {
-    assert((card_idx >> _scan_chunks_shift) < (_max_regions * _scan_chunks_per_region),
+    assert((card_idx >> _scan_chunks_shift) < _num_total_scan_chunks,
            "Trying to access index " SIZE_FORMAT " out of bounds " SIZE_FORMAT,
-           card_idx >> _scan_chunks_shift, _max_regions * _scan_chunks_per_region);
+           card_idx >> _scan_chunks_shift, _num_total_scan_chunks);
     size_t const chunk_idx = card_idx >> _scan_chunks_shift;
     if (!_region_scan_chunks[chunk_idx]) {
       _region_scan_chunks[chunk_idx] = true;
@@ -1133,6 +1147,9 @@
       G1GCParPhaseTimesTracker x(p, G1GCPhaseTimes::MergeHCC, worker_id);
       G1MergeLogBufferCardsClosure cl(g1h, _scan_state);
       g1h->iterate_hcc_closure(&cl, worker_id);
+
+      p->record_thread_work_item(G1GCPhaseTimes::MergeHCC, worker_id, cl.cards_dirty(), G1GCPhaseTimes::MergeHCCDirtyCards);
+      p->record_thread_work_item(G1GCPhaseTimes::MergeHCC, worker_id, cl.cards_skipped(), G1GCPhaseTimes::MergeHCCSkippedCards);
     }
 
     // Now apply the closure to all remaining log entries.
--- a/src/hotspot/share/gc/shared/parallelCleaning.cpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/gc/shared/parallelCleaning.cpp	Thu Jul 25 12:23:54 2019 +0530
@@ -30,9 +30,6 @@
 #include "logging/log.hpp"
 #include "memory/resourceArea.hpp"
 #include "logging/log.hpp"
-#if INCLUDE_JVMCI
-#include "jvmci/jvmci.hpp"
-#endif
 
 StringDedupCleaningTask::StringDedupCleaningTask(BoolObjectClosure* is_alive,
                                                  OopClosure* keep_alive,
@@ -160,56 +157,3 @@
     clean_klass(klass);
   }
 }
-
-#if INCLUDE_JVMCI
-JVMCICleaningTask::JVMCICleaningTask() :
-  _cleaning_claimed(0) {
-}
-
-bool JVMCICleaningTask::claim_cleaning_task() {
-  if (_cleaning_claimed) {
-    return false;
-  }
-
-  return Atomic::cmpxchg(1, &_cleaning_claimed, 0) == 0;
-}
-
-void JVMCICleaningTask::work(bool unloading_occurred) {
-  // One worker will clean JVMCI metadata handles.
-  if (unloading_occurred && EnableJVMCI && claim_cleaning_task()) {
-    JVMCI::do_unloading(unloading_occurred);
-  }
-}
-#endif // INCLUDE_JVMCI
-
-ParallelCleaningTask::ParallelCleaningTask(BoolObjectClosure* is_alive,
-                                           uint num_workers,
-                                           bool unloading_occurred,
-                                           bool resize_dedup_table) :
-  AbstractGangTask("Parallel Cleaning"),
-  _unloading_occurred(unloading_occurred),
-  _string_dedup_task(is_alive, NULL, resize_dedup_table),
-  _code_cache_task(num_workers, is_alive, unloading_occurred),
-  JVMCI_ONLY(_jvmci_cleaning_task() COMMA)
-  _klass_cleaning_task() {
-}
-
-// The parallel work done by all worker threads.
-void ParallelCleaningTask::work(uint worker_id) {
-  // Clean JVMCI metadata handles.
-  // Execute this task first because it is serial task.
-  JVMCI_ONLY(_jvmci_cleaning_task.work(_unloading_occurred);)
-
-  // Do first pass of code cache cleaning.
-  _code_cache_task.work(worker_id);
-
-  // Clean the string dedup data structures.
-  _string_dedup_task.work(worker_id);
-
-  // Clean all klasses that were not unloaded.
-  // The weak metadata in klass doesn't need to be
-  // processed if there was no unloading.
-  if (_unloading_occurred) {
-    _klass_cleaning_task.work();
-  }
-}
--- a/src/hotspot/share/gc/shared/parallelCleaning.hpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/gc/shared/parallelCleaning.hpp	Thu Jul 25 12:23:54 2019 +0530
@@ -31,8 +31,6 @@
 #include "gc/shared/stringdedup/stringDedup.hpp"
 #include "gc/shared/workgroup.hpp"
 
-class ParallelCleaningTask;
-
 class StringDedupCleaningTask : public AbstractGangTask {
   StringDedupUnlinkOrOopsDoClosure _dedup_closure;
 
@@ -87,40 +85,4 @@
   void work();
 };
 
-#if INCLUDE_JVMCI
-class JVMCICleaningTask : public StackObj {
-  volatile int       _cleaning_claimed;
-
-public:
-  JVMCICleaningTask();
-  // Clean JVMCI metadata handles.
-  void work(bool unloading_occurred);
-
-private:
-  bool claim_cleaning_task();
-};
-#endif
-
-// Do cleanup of some weakly held data in the same parallel task.
-// Assumes a non-moving context.
-class ParallelCleaningTask : public AbstractGangTask {
-private:
-  bool                    _unloading_occurred;
-  StringDedupCleaningTask _string_dedup_task;
-  CodeCacheUnloadingTask  _code_cache_task;
-#if INCLUDE_JVMCI
-  JVMCICleaningTask       _jvmci_cleaning_task;
-#endif
-  KlassCleaningTask       _klass_cleaning_task;
-
-public:
-  // The constructor is run in the VMThread.
-  ParallelCleaningTask(BoolObjectClosure* is_alive,
-                       uint num_workers,
-                       bool unloading_occurred,
-                       bool resize_dedup_table);
-
-  void work(uint worker_id);
-};
-
 #endif // SHARE_GC_SHARED_PARALLELCLEANING_HPP
--- a/src/hotspot/share/oops/constantPool.cpp	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/hotspot/share/oops/constantPool.cpp	Thu Jul 25 12:23:54 2019 +0530
@@ -760,6 +760,10 @@
     // return the method type signature in the error message
     message = this_cp->method_type_signature_at(which);
     break;
+  case JVM_CONSTANT_Dynamic:
+    // return the name of the condy in the error message
+    message = this_cp->uncached_name_ref_at(which);
+    break;
   default:
     ShouldNotReachHere();
   }
--- a/src/java.base/share/classes/java/lang/invoke/MemberName.java	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java	Thu Jul 25 12:23:54 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -521,7 +521,7 @@
     public boolean isAccessibleFrom(Class<?> lookupClass) {
         int mode = (ALL_ACCESS|MethodHandles.Lookup.PACKAGE|MethodHandles.Lookup.MODULE);
         return VerifyAccess.isMemberAccessible(this.getDeclaringClass(), this.getDeclaringClass(), flags,
-                                               lookupClass, mode);
+                                               lookupClass, null, mode);
     }
 
     /**
@@ -930,13 +930,21 @@
                 message += ", from public Lookup";
             } else {
                 Module m;
+                Class<?> plc;
                 if (from instanceof MethodHandles.Lookup) {
                     MethodHandles.Lookup lookup = (MethodHandles.Lookup)from;
+                    from = lookup.lookupClass();
                     m = lookup.lookupClass().getModule();
+                    plc = lookup.previousLookupClass();
                 } else {
-                    m = from.getClass().getModule();
+                    m = ((Class<?>)from).getModule();
+                    plc = null;
                 }
                 message += ", from " + from + " (" + m + ")";
+                if (plc != null) {
+                    message += ", previous lookup " +
+                        plc.getName() + " (" + plc.getModule() + ")";
+                }
             }
         }
         return new IllegalAccessException(message);
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Thu Jul 25 12:23:54 2019 +0530
@@ -125,7 +125,7 @@
 
     /**
      * Returns a {@link Lookup lookup object} which is trusted minimally.
-     * The lookup has the {@code PUBLIC} and {@code UNCONDITIONAL} modes.
+     * The lookup has the {@code UNCONDITIONAL} mode.
      * It can only be used to create method handles to public members of
      * public classes in packages that are exported unconditionally.
      * <p>
@@ -134,14 +134,14 @@
      *
      * @apiNote The use of Object is conventional, and because the lookup modes are
      * limited, there is no special access provided to the internals of Object, its package
-     * or its module. Consequently, the lookup context of this lookup object will be the
-     * bootstrap class loader, which means it cannot find user classes.
+     * or its module.  This public lookup object or other lookup object with
+     * {@code UNCONDITIONAL} mode assumes readability. Consequently, the lookup class
+     * is not used to determine the lookup context.
      *
      * <p style="font-size:smaller;">
      * <em>Discussion:</em>
      * The lookup class can be changed to any other class {@code C} using an expression of the form
      * {@link Lookup#in publicLookup().in(C.class)}.
-     * but may change the lookup context by virtue of changing the class loader.
      * A public lookup object is always subject to
      * <a href="MethodHandles.Lookup.html#secmgr">security manager checks</a>.
      * Also, it cannot access
@@ -156,64 +156,106 @@
     }
 
     /**
-     * Returns a {@link Lookup lookup object} with full capabilities to emulate all
-     * supported bytecode behaviors, including <a href="MethodHandles.Lookup.html#privacc">
-     * private access</a>, on a target class.
-     * This method checks that a caller, specified as a {@code Lookup} object, is allowed to
-     * do <em>deep reflection</em> on the target class. If {@code m1} is the module containing
-     * the {@link Lookup#lookupClass() lookup class}, and {@code m2} is the module containing
-     * the target class, then this check ensures that
+     * Returns a {@link Lookup lookup} object on a target class to emulate all supported
+     * bytecode behaviors, including <a href="MethodHandles.Lookup.html#privacc"> private access</a>.
+     * The returned lookup object can provide access to classes in modules and packages,
+     * and members of those classes, outside the normal rules of Java access control,
+     * instead conforming to the more permissive rules for modular <em>deep reflection</em>.
+     * <p>
+     * A caller, specified as a {@code Lookup} object, in module {@code M1} is
+     * allowed to do deep reflection on module {@code M2} and package of the target class
+     * if and only if all of the following conditions are {@code true}:
      * <ul>
-     *     <li>{@code m1} {@link Module#canRead reads} {@code m2}.</li>
-     *     <li>{@code m2} {@link Module#isOpen(String,Module) opens} the package containing
-     *     the target class to at least {@code m1}.</li>
-     *     <li>The lookup has the {@link Lookup#MODULE MODULE} lookup mode.</li>
+     * <li>If there is a security manager, its {@code checkPermission} method is
+     * called to check {@code ReflectPermission("suppressAccessChecks")} and
+     * that must return normally.
+     * <li>The caller lookup object must have the {@link Lookup#MODULE MODULE} lookup mode.
+     * (This is because otherwise there would be no way to ensure the original lookup
+     * creator was a member of any particular module, and so any subsequent checks
+     * for readability and qualified exports would become ineffective.)
+     * <li>The caller lookup object must have {@link Lookup#PRIVATE PRIVATE} access.
+     * (This is because an application intending to share intra-module access
+     * using {@link Lookup#MODULE MODULE} alone will inadvertently also share
+     * deep reflection to its own module.)
+     * <li>The target class must be a proper class, not a primitive or array class.
+     * (Thus, {@code M2} is well-defined.)
+     * <li>If the caller module {@code M1} differs from
+     * the target module {@code M2} then both of the following must be true:
+     *   <ul>
+     *     <li>{@code M1} {@link Module#canRead reads} {@code M2}.</li>
+     *     <li>{@code M2} {@link Module#isOpen(String,Module) opens} the package
+     *         containing the target class to at least {@code M1}.</li>
+     *   </ul>
      * </ul>
      * <p>
-     * If there is a security manager, its {@code checkPermission} method is called to
-     * check {@code ReflectPermission("suppressAccessChecks")}.
-     * @apiNote The {@code MODULE} lookup mode serves to authenticate that the lookup object
-     * was created by code in the caller module (or derived from a lookup object originally
-     * created by the caller). A lookup object with the {@code MODULE} lookup mode can be
-     * shared with trusted parties without giving away {@code PRIVATE} and {@code PACKAGE}
-     * access to the caller.
+     * If any of the above checks is violated, this method fails with an
+     * exception.
+     * <p>
+     * Otherwise, if {@code M1} and {@code M2} are the same module, this method
+     * returns a {@code Lookup} on {@code targetClass} with full capabilities and
+     * {@code null} previous lookup class.
+     * <p>
+     * Otherwise, {@code M1} and {@code M2} are two different modules.  This method
+     * returns a {@code Lookup} on {@code targetClass} that records
+     * the lookup class of the caller as the new previous lookup class and
+     * drops {@code MODULE} access from the full capabilities mode.
+     *
      * @param targetClass the target class
-     * @param lookup the caller lookup object
+     * @param caller the caller lookup object
      * @return a lookup object for the target class, with private access
-     * @throws IllegalArgumentException if {@code targetClass} is a primitve type or array class
+     * @throws IllegalArgumentException if {@code targetClass} is a primitive type or array class
      * @throws NullPointerException if {@code targetClass} or {@code caller} is {@code null}
-     * @throws IllegalAccessException if the access check specified above fails
      * @throws SecurityException if denied by the security manager
+     * @throws IllegalAccessException if any of the other access checks specified above fails
      * @since 9
      * @spec JPMS
      * @see Lookup#dropLookupMode
+     * @see <a href="MethodHandles.Lookup.html#cross-module-lookup">Cross-module lookups</a>
      */
-    public static Lookup privateLookupIn(Class<?> targetClass, Lookup lookup) throws IllegalAccessException {
+    public static Lookup privateLookupIn(Class<?> targetClass, Lookup caller) throws IllegalAccessException {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
         if (targetClass.isPrimitive())
             throw new IllegalArgumentException(targetClass + " is a primitive class");
         if (targetClass.isArray())
             throw new IllegalArgumentException(targetClass + " is an array class");
-        Module targetModule = targetClass.getModule();
-        Module callerModule = lookup.lookupClass().getModule();
-        if (!callerModule.canRead(targetModule))
-            throw new IllegalAccessException(callerModule + " does not read " + targetModule);
-        if (targetModule.isNamed()) {
-            String pn = targetClass.getPackageName();
-            assert !pn.isEmpty() : "unnamed package cannot be in named module";
-            if (!targetModule.isOpen(pn, callerModule))
-                throw new IllegalAccessException(targetModule + " does not open " + pn + " to " + callerModule);
+        // Ensure that we can reason accurately about private and module access.
+        if ((caller.lookupModes() & Lookup.PRIVATE) == 0)
+            throw new IllegalAccessException("caller does not have PRIVATE lookup mode");
+        if ((caller.lookupModes() & Lookup.MODULE) == 0)
+            throw new IllegalAccessException("caller does not have MODULE lookup mode");
+
+        // previous lookup class is never set if it has MODULE access
+        assert caller.previousLookupClass() == null;
+
+        Class<?> callerClass = caller.lookupClass();
+        Module callerModule = callerClass.getModule();  // M1
+        Module targetModule = targetClass.getModule();  // M2
+        Class<?> newPreviousClass = null;
+        int newModes = Lookup.FULL_POWER_MODES;
+
+        if (targetModule != callerModule) {
+            if (!callerModule.canRead(targetModule))
+                throw new IllegalAccessException(callerModule + " does not read " + targetModule);
+            if (targetModule.isNamed()) {
+                String pn = targetClass.getPackageName();
+                assert !pn.isEmpty() : "unnamed package cannot be in named module";
+                if (!targetModule.isOpen(pn, callerModule))
+                    throw new IllegalAccessException(targetModule + " does not open " + pn + " to " + callerModule);
+            }
+
+            // M2 != M1, set previous lookup class to M1 and drop MODULE access
+            newPreviousClass = callerClass;
+            newModes &= ~Lookup.MODULE;
         }
-        if ((lookup.lookupModes() & Lookup.MODULE) == 0)
-            throw new IllegalAccessException("lookup does not have MODULE lookup mode");
+
         if (!callerModule.isNamed() && targetModule.isNamed()) {
             IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger();
             if (logger != null) {
-                logger.logIfOpenedForIllegalAccess(lookup, targetClass);
+                logger.logIfOpenedForIllegalAccess(caller, targetClass);
             }
         }
-        return new Lookup(targetClass);
+        return Lookup.newLookup(targetClass, newPreviousClass, newModes);
     }
 
     /**
@@ -533,6 +575,514 @@
      * whose <a href="MethodHandles.Lookup.html#equiv">bytecode behaviors</a> and Java language access permissions
      * can be reliably determined and emulated by method handles.
      *
+     * <h2><a id="cross-module-lookup"></a>Cross-module lookups</h2>
+     * When a lookup class in one module {@code M1} accesses a class in another module
+     * {@code M2}, extra access checking is performed beyond the access mode bits.
+     * A {@code Lookup} with {@link #PUBLIC} mode and a lookup class in {@code M1}
+     * can access public types in {@code M2} when {@code M2} is readable to {@code M1}
+     * and when the type is in a package of {@code M2} that is exported to
+     * at least {@code M1}.
+     * <p>
+     * A {@code Lookup} on {@code C} can also <em>teleport</em> to a target class
+     * via {@link #in(Class) Lookup.in} and {@link MethodHandles#privateLookupIn(Class, Lookup)
+     * MethodHandles.privateLookupIn} methods.
+     * Teleporting across modules will always record the original lookup class as
+     * the <em>{@linkplain #previousLookupClass() previous lookup class}</em>
+     * and drops {@link Lookup#MODULE MODULE} access.
+     * If the target class is in the same module as the lookup class {@code C},
+     * then the target class becomes the new lookup class
+     * and there is no change to the previous lookup class.
+     * If the target class is in a different module from {@code M1} ({@code C}'s module),
+     * {@code C} becomes the new previous lookup class
+     * and the target class becomes the new lookup class.
+     * In that case, if there was already a previous lookup class in {@code M0},
+     * and it differs from {@code M1} and {@code M2}, then the resulting lookup
+     * drops all privileges.
+     * For example,
+     * <blockquote><pre>
+     * {@code
+     * Lookup lookup = MethodHandles.lookup();   // in class C
+     * Lookup lookup2 = lookup.in(D.class);
+     * MethodHandle mh = lookup2.findStatic(E.class, "m", MT);
+     * }</pre></blockquote>
+     * <p>
+     * The {@link #lookup()} factory method produces a {@code Lookup} object
+     * with {@code null} previous lookup class.
+     * {@link Lookup#in lookup.in(D.class)} transforms the {@code lookup} on class {@code C}
+     * to class {@code D} without elevation of privileges.
+     * If {@code C} and {@code D} are in the same module,
+     * {@code lookup2} records {@code D} as the new lookup class and keeps the
+     * same previous lookup class as the original {@code lookup}, or
+     * {@code null} if not present.
+     * <p>
+     * When a {@code Lookup} teleports from a class
+     * in one nest to another nest, {@code PRIVATE} access is dropped.
+     * When a {@code Lookup} teleports from a class in one package to
+     * another package, {@code PACKAGE} access is dropped.
+     * When a {@code Lookup} teleports from a class in one module to another module,
+     * {@code MODULE} access is dropped.
+     * Teleporting across modules drops the ability to access non-exported classes
+     * in both the module of the new lookup class and the module of the old lookup class
+     * and the resulting {@code Lookup} remains only {@code PUBLIC} access.
+     * A {@code Lookup} can teleport back and forth to a class in the module of
+     * the lookup class and the module of the previous class lookup.
+     * Teleporting across modules can only decrease access but cannot increase it.
+     * Teleporting to some third module drops all accesses.
+     * <p>
+     * In the above example, if {@code C} and {@code D} are in different modules,
+     * {@code lookup2} records {@code D} as its lookup class and
+     * {@code C} as its previous lookup class and {@code lookup2} has only
+     * {@code PUBLIC} access. {@code lookup2} can teleport to other class in
+     * {@code C}'s module and {@code D}'s module.
+     * If class {@code E} is in a third module, {@code lookup2.in(E.class)} creates
+     * a {@code Lookup} on {@code E} with no access and {@code lookup2}'s lookup
+     * class {@code D} is recorded as its previous lookup class.
+     * <p>
+     * Teleporting across modules restricts access to the public types that
+     * both the lookup class and the previous lookup class can equally access
+     * (see below).
+     * <p>
+     * {@link MethodHandles#privateLookupIn(Class, Lookup) MethodHandles.privateLookupIn(T.class, lookup)}
+     * can be used to teleport a {@code lookup} from class {@code C} to class {@code T}
+     * and create a new {@code Lookup} with <a href="#privcc">private access</a>
+     * if the lookup class is allowed to do <em>deep reflection</em> on {@code T}.
+     * The {@code lookup} must have {@link #MODULE} and {@link #PRIVATE} access
+     * to call {@code privateLookupIn}.
+     * A {@code lookup} on {@code C} in module {@code M1} is allowed to do deep reflection
+     * on all classes in {@code M1}.  If {@code T} is in {@code M1}, {@code privateLookupIn}
+     * produces a new {@code Lookup} on {@code T} with full capabilities.
+     * A {@code lookup} on {@code C} is also allowed
+     * to do deep reflection on {@code T} in another module {@code M2} if
+     * {@code M1} reads {@code M2} and {@code M2} {@link Module#isOpen(String,Module) opens}
+     * the package containing {@code T} to at least {@code M1}.
+     * {@code T} becomes the new lookup class and {@code C} becomes the new previous
+     * lookup class and {@code MODULE} access is dropped from the resulting {@code Lookup}.
+     * The resulting {@code Lookup} can be used to do member lookup or teleport
+     * to another lookup class by calling {@link #in Lookup::in}.  But
+     * it cannot be used to obtain another private {@code Lookup} by calling
+     * {@link MethodHandles#privateLookupIn(Class, Lookup) privateLookupIn}
+     * because it has no {@code MODULE} access.
+     *
+     * <h2><a id="module-access-check"></a>Cross-module access checks</h2>
+     *
+     * A {@code Lookup} with {@link #PUBLIC} or with {@link #UNCONDITIONAL} mode
+     * allows cross-module access. The access checking is performed with respect
+     * to both the lookup class and the previous lookup class if present.
+     * <p>
+     * A {@code Lookup} with {@link #UNCONDITIONAL} mode can access public type
+     * in all modules when the type is in a package that is {@linkplain Module#isExported(String)
+     * exported unconditionally}.
+     * <p>
+     * If a {@code Lookup} on {@code LC} in {@code M1} has no previous lookup class,
+     * the lookup with {@link #PUBLIC} mode can access all public types in modules
+     * that are readable to {@code M1} and the type is in a package that is exported
+     * at least to {@code M1}.
+     * <p>
+     * If a {@code Lookup} on {@code LC} in {@code M1} has a previous lookup class
+     * {@code PLC} on {@code M0}, the lookup with {@link #PUBLIC} mode can access
+     * the intersection of all public types that are accessible to {@code M1}
+     * with all public types that are accessible to {@code M0}. {@code M0}
+     * reads {@code M1} and hence the set of accessible types includes:
+     *
+     * <table class="striped">
+     * <caption style="display:none">
+     * Public types in the following packages are accessible to the
+     * lookup class and the previous lookup class.
+     * </caption>
+     * <thead>
+     * <tr>
+     * <th scope="col">Equally accessible types to {@code M0} and {@code M1}</th>
+     * </tr>
+     * </thead>
+     * <tbody>
+     * <tr>
+     * <th scope="row" style="text-align:left">unconditional-exported packages from {@code M1}</th>
+     * </tr>
+     * <tr>
+     * <th scope="row" style="text-align:left">unconditional-exported packages from {@code M0} if {@code M1} reads {@code M0}</th>
+     * </tr>
+     * <tr>
+     * <th scope="row" style="text-align:left">unconditional-exported packages from a third module {@code M2}
+     * if both {@code M0} and {@code M1} read {@code M2}</th>
+     * </tr>
+     * <tr>
+     * <th scope="row" style="text-align:left">qualified-exported packages from {@code M1} to {@code M0}</th>
+     * </tr>
+     * <tr>
+     * <th scope="row" style="text-align:left">qualified-exported packages from {@code M0} to {@code M1}
+     * if {@code M1} reads {@code M0}</th>
+     * </tr>
+     * <tr>
+     * <th scope="row" style="text-align:left">qualified-exported packages from a third module {@code M2} to
+     * both {@code M0} and {@code M1} if both {@code M0} and {@code M1} read {@code M2}</th>
+     * </tr>
+     * </tbody>
+     * </table>
+     *
+     * <h2><a id="access-modes"></a>Access modes</h2>
+     *
+     * The table below shows the access modes of a {@code Lookup} produced by
+     * any of the following factory or transformation methods:
+     * <ul>
+     * <li>{@link #lookup() MethodHandles.lookup()}</li>
+     * <li>{@link #publicLookup() MethodHandles.publicLookup()}</li>
+     * <li>{@link #privateLookupIn(Class, Lookup) MethodHandles.privateLookupIn}</li>
+     * <li>{@link Lookup#in}</li>
+     * <li>{@link Lookup#dropLookupMode(int)}</li>
+     * </ul>
+     *
+     * <table class="striped">
+     * <caption style="display:none">
+     * Access mode summary
+     * </caption>
+     * <thead>
+     * <tr>
+     * <th scope="col">Lookup object</th>
+     * <th style="text-align:center">protected</th>
+     * <th style="text-align:center">private</th>
+     * <th style="text-align:center">package</th>
+     * <th style="text-align:center">module</th>
+     * <th style="text-align:center">public</th>
+     * </tr>
+     * </thead>
+     * <tbody>
+     * <tr>
+     * <th scope="row" style="text-align:left">{@code CL = MethodHandles.lookup()} in {@code C}</th>
+     * <td style="text-align:center">PRO</td>
+     * <td style="text-align:center">PRI</td>
+     * <td style="text-align:center">PAC</td>
+     * <td style="text-align:center">MOD</td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <th scope="row" style="text-align:left">{@code CL.in(C1)} same package</th>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">PAC</td>
+     * <td style="text-align:center">MOD</td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <th scope="row" style="text-align:left">{@code CL.in(C1)} same module</th>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">MOD</td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <th scope="row" style="text-align:left">{@code CL.in(D)} different module</th>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">2R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code CL.in(D).in(C)} hop back to module</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">2R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI1 = privateLookupIn(C1,CL)}</td>
+     * <td style="text-align:center">PRO</td>
+     * <td style="text-align:center">PRI</td>
+     * <td style="text-align:center">PAC</td>
+     * <td style="text-align:center">MOD</td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI1a = privateLookupIn(C,PRI1)}</td>
+     * <td style="text-align:center">PRO</td>
+     * <td style="text-align:center">PRI</td>
+     * <td style="text-align:center">PAC</td>
+     * <td style="text-align:center">MOD</td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI1.in(C1)} same package</td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">PAC</td>
+     * <td style="text-align:center">MOD</td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI1.in(C1)} different package</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">MOD</td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI1.in(D)} different module</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">2R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI1.dropLookupMode(PROTECTED)}</td>
+     * <td></td>
+     * <td style="text-align:center">PRI</td>
+     * <td style="text-align:center">PAC</td>
+     * <td style="text-align:center">MOD</td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI1.dropLookupMode(PRIVATE)}</td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">PAC</td>
+     * <td style="text-align:center">MOD</td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI1.dropLookupMode(PACKAGE)}</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">MOD</td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI1.dropLookupMode(MODULE)}</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI1.dropLookupMode(PUBLIC)}</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">none</td>
+     * <tr>
+     * <td>{@code PRI2 = privateLookupIn(D,CL)}</td>
+     * <td style="text-align:center">PRO</td>
+     * <td style="text-align:center">PRI</td>
+     * <td style="text-align:center">PAC</td>
+     * <td></td>
+     * <td style="text-align:center">2R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code privateLookupIn(D,PRI1)}</td>
+     * <td style="text-align:center">PRO</td>
+     * <td style="text-align:center">PRI</td>
+     * <td style="text-align:center">PAC</td>
+     * <td></td>
+     * <td style="text-align:center">2R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code privateLookupIn(C,PRI2)} fails</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">IAE</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI2.in(D2)} same package</td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">PAC</td>
+     * <td></td>
+     * <td style="text-align:center">2R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI2.in(D2)} different package</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">2R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI2.in(C1)} hop back to module</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">2R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI2.in(E)} hop to third module</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">none</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI2.dropLookupMode(PROTECTED)}</td>
+     * <td></td>
+     * <td style="text-align:center">PRI</td>
+     * <td style="text-align:center">PAC</td>
+     * <td></td>
+     * <td style="text-align:center">2R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI2.dropLookupMode(PRIVATE)}</td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">PAC</td>
+     * <td></td>
+     * <td style="text-align:center">2R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI2.dropLookupMode(PACKAGE)}</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">2R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI2.dropLookupMode(MODULE)}</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">2R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PRI2.dropLookupMode(PUBLIC)}</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">none</td>
+     * </tr>
+     * <tr>
+     * <td>{@code CL.dropLookupMode(PROTECTED)}</td>
+     * <td></td>
+     * <td style="text-align:center">PRI</td>
+     * <td style="text-align:center">PAC</td>
+     * <td style="text-align:center">MOD</td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code CL.dropLookupMode(PRIVATE)}</td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">PAC</td>
+     * <td style="text-align:center">MOD</td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code CL.dropLookupMode(PACKAGE)}</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">MOD</td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code CL.dropLookupMode(MODULE)}</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">1R</td>
+     * </tr>
+     * <tr>
+     * <td>{@code CL.dropLookupMode(PUBLIC)}</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">none</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PUB = publicLookup()}</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">U</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PUB.in(D)} different module</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">U</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PUB.in(D).in(E)} third module</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">U</td>
+     * </tr>
+     * <tr>
+     * <td>{@code PUB.dropLookupMode(UNCONDITIONAL)}</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">none</td>
+     * </tr>
+     * <tr>
+     * <td>{@code privateLookupIn(C1,PUB)} fails</td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">IAE</td>
+     * </tr>
+     * <tr>
+     * <td>{@code ANY.in(X)}, for inaccessible <code>X</code></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td></td>
+     * <td style="text-align:center">none</td>
+     * </tr>
+     * </tbody>
+     * </table>
+     *
+     * <p>
+     * Notes:
+     * <ul>
+     * <li>Class {@code C} and class {@code C1} are in module {@code M1},
+     *     but {@code D} and {@code D2} are in module {@code M2}, and {@code E}
+     *     is in module {@code M3}. {@code X} stands for class which is inaccessible
+     *     to the lookup. {@code ANY} stands for any of the example lookups.</li>
+     * <li>{@code PRO} indicates {@link #PROTECTED} bit set,
+     *     {@code PRI} indicates {@link #PRIVATE} bit set,
+     *     {@code PAC} indicates {@link #PACKAGE} bit set,
+     *     {@code MOD} indicates {@link #MODULE} bit set,
+     *     {@code 1R} and {@code 2R} indicate {@link #PUBLIC} bit set,
+     *     {@code U} indicates {@link #UNCONDITIONAL} bit set,
+     *     {@code IAE} indicates {@code IllegalAccessException} thrown.</li>
+     * <li>Public access comes in three kinds:
+     * <ul>
+     * <li>unconditional ({@code U}): the lookup assumes readability.
+     *     The lookup has {@code null} previous lookup class.
+     * <li>one-module-reads ({@code 1R}): the module access checking is
+     *     performed with respect to the lookup class.  The lookup has {@code null}
+     *     previous lookup class.
+     * <li>two-module-reads ({@code 2R}): the module access checking is
+     *     performed with respect to the lookup class and the previous lookup class.
+     *     The lookup has a non-null previous lookup class which is in a
+     *     different module from the current lookup class.
+     * </ul>
+     * <li>Any attempt to reach a third module loses all access.</li>
+     * <li>If a target class {@code X} is not accessible to {@code Lookup::in}
+     * all access modes are dropped.</li>
+     * </ul>
+     *
      * <h2><a id="secmgr"></a>Security manager interactions</h2>
      * Although bytecode instructions can only refer to classes in
      * a related class loader, this API can search for methods in any
@@ -645,6 +1195,9 @@
         /** The class on behalf of whom the lookup is being performed. */
         private final Class<?> lookupClass;
 
+        /** previous lookup class */
+        private final Class<?> prevLookupClass;
+
         /** The allowed sorts of members which may be looked up (PUBLIC, etc.). */
         private final int allowedModes;
 
@@ -656,6 +1209,10 @@
          *  which may contribute to the result of {@link #lookupModes lookupModes}.
          *  The value, {@code 0x01}, happens to be the same as the value of the
          *  {@code public} {@linkplain java.lang.reflect.Modifier#PUBLIC modifier bit}.
+         *  <p>
+         *  A {@code Lookup} with this lookup mode performs cross-module access check
+         *  with respect to the {@linkplain #lookupClass() lookup class} and
+         *  {@linkplain #previousLookupClass() previous lookup class} if present.
          */
         public static final int PUBLIC = Modifier.PUBLIC;
 
@@ -680,7 +1237,7 @@
          */
         public static final int PACKAGE = Modifier.STATIC;
 
-        /** A single-bit mask representing {@code module} access (default access),
+        /** A single-bit mask representing {@code module} access,
          *  which may contribute to the result of {@link #lookupModes lookupModes}.
          *  The value is {@code 0x10}, which does not correspond meaningfully to
          *  any particular {@linkplain java.lang.reflect.Modifier modifier bit}.
@@ -688,6 +1245,10 @@
          *  with this lookup mode can access all public types in the module of the
          *  lookup class and public types in packages exported by other modules
          *  to the module of the lookup class.
+         *  <p>
+         *  If this lookup mode is set, the {@linkplain #previousLookupClass()
+         *  previous lookup class} is always {@code null}.
+         *
          *  @since 9
          *  @spec JPMS
          */
@@ -699,10 +1260,14 @@
          *  any particular {@linkplain java.lang.reflect.Modifier modifier bit}.
          *  A {@code Lookup} with this lookup mode assumes {@linkplain
          *  java.lang.Module#canRead(java.lang.Module) readability}.
-         *  In conjunction with the {@code PUBLIC} modifier bit, a {@code Lookup}
-         *  with this lookup mode can access all public members of public types
-         *  of all modules where the type is in a package that is {@link
+         *  This lookup mode can access all public members of public types
+         *  of all modules when the type is in a package that is {@link
          *  java.lang.Module#isExported(String) exported unconditionally}.
+         *
+         *  <p>
+         *  If this lookup mode is set, the {@linkplain #previousLookupClass()
+         *  previous lookup class} is always {@code null}.
+         *
          *  @since 9
          *  @spec JPMS
          *  @see #publicLookup()
@@ -713,24 +1278,55 @@
         private static final int FULL_POWER_MODES = (ALL_MODES & ~UNCONDITIONAL);
         private static final int TRUSTED   = -1;
 
+        /*
+         * Adjust PUBLIC => PUBLIC|MODULE|UNCONDITIONAL
+         * Adjust 0 => PACKAGE
+         */
         private static int fixmods(int mods) {
             mods &= (ALL_MODES - PACKAGE - MODULE - UNCONDITIONAL);
-            return (mods != 0) ? mods : (PACKAGE | MODULE | UNCONDITIONAL);
+            if (Modifier.isPublic(mods))
+                mods |= UNCONDITIONAL;
+            return (mods != 0) ? mods : PACKAGE;
         }
 
         /** Tells which class is performing the lookup.  It is this class against
          *  which checks are performed for visibility and access permissions.
          *  <p>
+         *  If this lookup object has a {@linkplain #previousLookupClass() previous lookup class},
+         *  access checks are performed against both the lookup class and the previous lookup class.
+         *  <p>
          *  The class implies a maximum level of access permission,
          *  but the permissions may be additionally limited by the bitmask
          *  {@link #lookupModes lookupModes}, which controls whether non-public members
          *  can be accessed.
          *  @return the lookup class, on behalf of which this lookup object finds members
+         *  @see <a href="#cross-module-lookup">Cross-module lookups</a>
          */
         public Class<?> lookupClass() {
             return lookupClass;
         }
 
+        /** Reports a lookup class in another module that this lookup object
+         * was previously teleported from, or {@code null}.
+         * <p>
+         * A {@code Lookup} object produced by the factory methods, such as the
+         * {@link #lookup() lookup()} and {@link #publicLookup() publicLookup()} method,
+         * has {@code null} previous lookup class.
+         * A {@code Lookup} object has a non-null previous lookup class
+         * when this lookup was teleported from an old lookup class
+         * in one module to a new lookup class in another module.
+         *
+         * @return the lookup class in another module that this lookup object was
+         *         previously teleported from, or {@code null}
+         * @since 14
+         * @see #in(Class)
+         * @see MethodHandles#privateLookupIn(Class, Lookup)
+         * @see <a href="#cross-module-lookup">Cross-module lookups</a>
+         */
+        public Class<?> previousLookupClass() {
+            return prevLookupClass;
+        }
+
         // This is just for calling out to MethodHandleImpl.
         private Class<?> lookupClassOrNull() {
             return (allowedModes == TRUSTED) ? null : lookupClass;
@@ -774,48 +1370,69 @@
          * which in turn is called by a method not in this package.
          */
         Lookup(Class<?> lookupClass) {
-            this(lookupClass, FULL_POWER_MODES);
+            this(lookupClass, null, FULL_POWER_MODES);
             // make sure we haven't accidentally picked up a privileged class:
             checkUnprivilegedlookupClass(lookupClass);
         }
 
-        private Lookup(Class<?> lookupClass, int allowedModes) {
+        private Lookup(Class<?> lookupClass, Class<?> prevLookupClass, int allowedModes) {
+            assert prevLookupClass == null || ((allowedModes & MODULE) == 0
+                    && prevLookupClass.getModule() != lookupClass.getModule());
+
             this.lookupClass = lookupClass;
+            this.prevLookupClass = prevLookupClass;
             this.allowedModes = allowedModes;
         }
 
+        private static Lookup newLookup(Class<?> lookupClass, Class<?> prevLookupClass, int allowedModes) {
+            // make sure we haven't accidentally picked up a privileged class:
+            checkUnprivilegedlookupClass(lookupClass);
+            return new Lookup(lookupClass, prevLookupClass, allowedModes);
+        }
+
         /**
          * Creates a lookup on the specified new lookup class.
          * The resulting object will report the specified
          * class as its own {@link #lookupClass() lookupClass}.
+         *
          * <p>
          * 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>If the old lookup class is in a {@link Module#isNamed() named} module, and
-         * the new lookup class is in a different module {@code M}, then no members, not
-         * even public members in {@code M}'s exported packages, will be accessible.
-         * The exception to this is when this lookup is {@link #publicLookup()
-         * publicLookup}, in which case {@code PUBLIC} access is not lost.
-         * <li>If the old lookup class is in an unnamed module, and the new lookup class
-         * is a different module then {@link #MODULE MODULE} access is lost.
-         * <li>If the new lookup class differs from the old one then {@code UNCONDITIONAL} is lost.
+         * <li>If the new lookup class is in a different module from the old one,
+         * i.e. {@link #MODULE MODULE} access is lost.
          * <li>If the new lookup class is in a different package
-         * than the old one, protected and default (package) members will not be accessible.
+         * than the old one, protected and default (package) members will not be accessible,
+         * i.e. {@link #PROTECTED PROTECTED} and {@link #PACKAGE PACKAGE} access are lost.
          * <li>If the new lookup class is not within the same package member
          * as the old one, private members will not be accessible, and protected members
-         * will not be accessible by virtue of inheritance.
+         * will not be accessible by virtue of inheritance,
+         * i.e. {@link #PRIVATE PRIVATE} access is lost.
          * (Protected members may continue to be accessible because of package sharing.)
-         * <li>If the new lookup class is not accessible to the old lookup class,
-         * then no members, not even public members, will be accessible.
-         * (In all other cases, public members will continue to be accessible.)
+         * <li>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.
+         * <li>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.
          * </ul>
          * <p>
+         * The new previous lookup class is chosen as follows:
+         * <ul>
+         * <li>If the new lookup object has {@link #UNCONDITIONAL UNCONDITIONAL} bit,
+         * the new previous lookup class is {@code null}.
+         * <li>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.
+         * <li>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.
+         *</ul>
+         * <p>
          * The resulting lookup's capabilities for loading classes
          * (used during {@link #findClass} invocations)
          * are determined by the lookup class' loader,
          * which may change due to this operation.
-         *
+         * <p>
          * @param requestedLookupClass the desired lookup class for the new lookup object
          * @return a lookup object which reports the desired lookup class, or the same object
          * if there is no change
@@ -823,22 +1440,32 @@
          *
          * @revised 9
          * @spec JPMS
+         * @see #accessClass(Class)
+         * @see <a href="#cross-module-lookup">Cross-module lookups</a>
          */
         public Lookup in(Class<?> requestedLookupClass) {
             Objects.requireNonNull(requestedLookupClass);
             if (allowedModes == TRUSTED)  // IMPL_LOOKUP can make any lookup at all
-                return new Lookup(requestedLookupClass, FULL_POWER_MODES);
+                return new Lookup(requestedLookupClass, null, FULL_POWER_MODES);
             if (requestedLookupClass == this.lookupClass)
                 return this;  // keep same capabilities
             int newModes = (allowedModes & FULL_POWER_MODES);
-            if (!VerifyAccess.isSameModule(this.lookupClass, requestedLookupClass)) {
-                // Need to drop all access when teleporting from a named module to another
-                // module. The exception is publicLookup where PUBLIC is not lost.
-                if (this.lookupClass.getModule().isNamed()
-                    && (this.allowedModes & UNCONDITIONAL) == 0)
+            Module fromModule = this.lookupClass.getModule();
+            Module targetModule = requestedLookupClass.getModule();
+            Class<?> plc = this.previousLookupClass();
+            if ((this.allowedModes & UNCONDITIONAL) != 0) {
+                assert plc == null;
+                newModes = UNCONDITIONAL;
+            } else if (fromModule != targetModule) {
+                if (plc != null && !VerifyAccess.isSameModule(plc, requestedLookupClass)) {
+                    // allow hopping back and forth between fromModule and plc's module
+                    // but not the third module
                     newModes = 0;
-                else
-                    newModes &= ~(MODULE|PACKAGE|PRIVATE|PROTECTED);
+                }
+                // drop MODULE access
+                newModes &= ~(MODULE|PACKAGE|PRIVATE|PROTECTED);
+                // teleport from this lookup class
+                plc = this.lookupClass;
             }
             if ((newModes & PACKAGE) != 0
                 && !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) {
@@ -849,29 +1476,39 @@
                 && !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) {
                 newModes &= ~(PRIVATE|PROTECTED);
             }
-            if ((newModes & PUBLIC) != 0
-                && !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass, allowedModes)) {
+            if ((newModes & (PUBLIC|UNCONDITIONAL)) != 0
+                && !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass, this.prevLookupClass, allowedModes)) {
                 // The requested class it not accessible from the lookup class.
                 // No permissions.
                 newModes = 0;
             }
-
-            checkUnprivilegedlookupClass(requestedLookupClass);
-            return new Lookup(requestedLookupClass, newModes);
+            return newLookup(requestedLookupClass, plc, newModes);
         }
 
-
         /**
          * Creates a lookup on the same lookup class which this lookup object
          * finds members, but with a lookup mode that has lost the given lookup mode.
          * The lookup mode to drop is one of {@link #PUBLIC PUBLIC}, {@link #MODULE
          * MODULE}, {@link #PACKAGE PACKAGE}, {@link #PROTECTED PROTECTED} or {@link #PRIVATE PRIVATE}.
-         * {@link #PROTECTED PROTECTED} and {@link #UNCONDITIONAL UNCONDITIONAL} are always
-         * dropped and so the resulting lookup mode will never have these access capabilities.
+         * {@link #PROTECTED PROTECTED} is always
+         * dropped and so the resulting lookup mode will never have this access capability.
          * When dropping {@code PACKAGE} then the resulting lookup will not have {@code PACKAGE}
          * or {@code PRIVATE} access. When dropping {@code MODULE} then the resulting lookup will
          * not have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code PUBLIC}
+         * is dropped then the resulting lookup has no access. If {@code UNCONDITIONAL}
          * is dropped then the resulting lookup has no access.
+         *
+         * @apiNote
+         * A lookup with {@code PACKAGE} but not {@code PRIVATE} mode can safely
+         * delegate non-public access within the package of the lookup class without
+         * conferring private access.  A lookup with {@code MODULE} but not
+         * {@code PACKAGE} mode can safely delegate {@code PUBLIC} access within
+         * the module of the lookup class without conferring package access.
+         * A lookup with a {@linkplain #previousLookupClass() previous lookup class}
+         * (and {@code PUBLIC} but not {@code MODULE} mode) can safely delegate access
+         * to public classes accessible to both the module of the lookup class
+         * and the module of the previous lookup class.
+         *
          * @param modeToDrop the lookup mode to drop
          * @return a lookup object which lacks the indicated mode, or the same object if there is no change
          * @throws IllegalArgumentException if {@code modeToDrop} is not one of {@code PUBLIC},
@@ -881,9 +1518,9 @@
          */
         public Lookup dropLookupMode(int modeToDrop) {
             int oldModes = lookupModes();
-            int newModes = oldModes & ~(modeToDrop | PROTECTED | UNCONDITIONAL);
+            int newModes = oldModes & ~(modeToDrop | PROTECTED);
             switch (modeToDrop) {
-                case PUBLIC: newModes &= ~(ALL_MODES); break;
+                case PUBLIC: newModes &= ~(FULL_POWER_MODES); break;
                 case MODULE: newModes &= ~(PACKAGE | PRIVATE); break;
                 case PACKAGE: newModes &= ~(PRIVATE); break;
                 case PROTECTED:
@@ -892,7 +1529,7 @@
                 default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop");
             }
             if (newModes == oldModes) return this;  // return self if no change
-            return new Lookup(lookupClass(), newModes);
+            return newLookup(lookupClass(), previousLookupClass(), newModes);
         }
 
         /**
@@ -997,13 +1634,13 @@
         static { IMPL_NAMES.getClass(); }
 
         /** Package-private version of lookup which is trusted. */
-        static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED);
+        static final Lookup IMPL_LOOKUP = new Lookup(Object.class, null, TRUSTED);
 
         /** Version of lookup which is trusted minimally.
          *  It can only be used to create method handles to publicly accessible
          *  members in packages that are exported unconditionally.
          */
-        static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, (PUBLIC|UNCONDITIONAL));
+        static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, null, UNCONDITIONAL);
 
         private static void checkUnprivilegedlookupClass(Class<?> lookupClass) {
             String name = lookupClass.getName();
@@ -1013,6 +1650,8 @@
 
         /**
          * Displays the name of the class from which lookups are to be made.
+         * followed with "/" and the name of the {@linkplain #previousLookupClass()
+         * previous lookup class} if present.
          * (The name is the one reported by {@link java.lang.Class#getName() Class.getName}.)
          * If there are restrictions on the access permitted to this lookup,
          * this is indicated by adding a suffix to the class name, consisting
@@ -1020,14 +1659,14 @@
          * allowed access, and is chosen as follows:
          * <ul>
          * <li>If no access is allowed, the suffix is "/noaccess".
+         * <li>If only unconditional access is allowed, the suffix is "/publicLookup".
          * <li>If only public access to types in exported packages is allowed, the suffix is "/public".
-         * <li>If only public access and unconditional access are allowed, the suffix is "/publicLookup".
          * <li>If only public and module access are allowed, the suffix is "/module".
-         * <li>If only public, module and package access are allowed, the suffix is "/package".
-         * <li>If only public, module, package, and private access are allowed, the suffix is "/private".
+         * <li>If public and package access are allowed, the suffix is "/package".
+         * <li>If public, package, and private access are allowed, the suffix is "/private".
          * </ul>
-         * If none of the above cases apply, it is the case that full
-         * access (public, module, package, private, and protected) is allowed.
+         * If none of the above cases apply, it is the case that full access
+         * (public, module, package, private, and protected) is allowed.
          * In this case, no suffix is added.
          * This is true only of an object obtained originally from
          * {@link java.lang.invoke.MethodHandles#lookup MethodHandles.lookup}.
@@ -1047,20 +1686,25 @@
         @Override
         public String toString() {
             String cname = lookupClass.getName();
+            if (prevLookupClass != null)
+                cname += "/" + prevLookupClass.getName();
             switch (allowedModes) {
             case 0:  // no privileges
                 return cname + "/noaccess";
+            case UNCONDITIONAL:
+                return cname + "/publicLookup";
             case PUBLIC:
                 return cname + "/public";
-            case PUBLIC|UNCONDITIONAL:
-                return cname  + "/publicLookup";
             case PUBLIC|MODULE:
                 return cname + "/module";
+            case PUBLIC|PACKAGE:
             case PUBLIC|MODULE|PACKAGE:
                 return cname + "/package";
-            case FULL_POWER_MODES & ~PROTECTED:
-                return cname + "/private";
+            case FULL_POWER_MODES & (~PROTECTED):
+            case FULL_POWER_MODES & ~(PROTECTED|MODULE):
+                    return cname + "/private";
             case FULL_POWER_MODES:
+            case FULL_POWER_MODES & (~MODULE):
                 return cname;
             case TRUSTED:
                 return "/trusted";  // internal only; not exported
@@ -1301,24 +1945,75 @@
         }
 
         /**
-         * Determines if a class can be accessed from the lookup context defined by this {@code Lookup} object. The
-         * static initializer of the class is not run.
+         * Determines if a class can be accessed from the lookup context defined by
+         * this {@code Lookup} object. The static initializer of the class is not run.
+         * <p>
+         * If the {@code targetClass} is in the same module as the lookup class,
+         * the lookup class is {@code LC} in module {@code M1} and
+         * the previous lookup class is in module {@code M0} or
+         * {@code null} if not present,
+         * {@code targetClass} is accessible if and only if one of the following is true:
+         * <ul>
+         * <li>If this lookup has {@link #PRIVATE} access, {@code targetClass} is
+         *     {@code LC} or other class in the same nest of {@code LC}.</li>
+         * <li>If this lookup has {@link #PACKAGE} access, {@code targetClass} is
+         *     in the same runtime package of {@code LC}.</li>
+         * <li>If this lookup has {@link #MODULE} access, {@code targetClass} is
+         *     a public type in {@code M1}.</li>
+         * <li>If this lookup has {@link #PUBLIC} access, {@code targetClass} is
+         *     a public type in a package exported by {@code M1} to at least  {@code M0}
+         *     if the previous lookup class is present; otherwise, {@code targetClass}
+         *     is a public type in a package exported by {@code M1} unconditionally.</li>
+         * </ul>
+         *
+         * <p>
+         * Otherwise, if this lookup has {@link #UNCONDITIONAL} access, this lookup
+         * can access public types in all modules when the type is in a package
+         * that is exported unconditionally.
          * <p>
-         * The lookup context here is determined by the {@linkplain #lookupClass() lookup class} and the
-         * {@linkplain #lookupModes() lookup modes}.
+         * Otherwise, the target class is in a different module from {@code lookupClass},
+         * and if this lookup does not have {@code PUBLIC} access, {@code lookupClass}
+         * is inaccessible.
+         * <p>
+         * Otherwise, if this lookup has no {@linkplain #previousLookupClass() previous lookup class},
+         * {@code M1} is the module containing {@code lookupClass} and
+         * {@code M2} is the module containing {@code targetClass},
+         * then {@code targetClass} is accessible if and only if
+         * <ul>
+         * <li>{@code M1} reads {@code M2}, and
+         * <li>{@code targetClass} is public and in a package exported by
+         *     {@code M2} at least to {@code M1}.
+         * </ul>
+         * <p>
+         * Otherwise, if this lookup has a {@linkplain #previousLookupClass() previous lookup class},
+         * {@code M1} and {@code M2} are as before, and {@code M0} is the module
+         * containing the previous lookup class, then {@code targetClass} is accessible
+         * if and only if one of the following is true:
+         * <ul>
+         * <li>{@code targetClass} is in {@code M0} and {@code M1}
+         *     {@linkplain Module#reads reads} {@code M0} and the type is
+         *     in a package that is exported to at least {@code M1}.
+         * <li>{@code targetClass} is in {@code M1} and {@code M0}
+         *     {@linkplain Module#reads reads} {@code M1} and the type is
+         *     in a package that is exported to at least {@code M0}.
+         * <li>{@code targetClass} is in a third module {@code M2} and both {@code M0}
+         *     and {@code M1} reads {@code M2} and the type is in a package
+         *     that is exported to at least both {@code M0} and {@code M2}.
+         * </ul>
+         * <p>
+         * Otherwise, {@code targetClass} is not accessible.
          *
          * @param targetClass the class to be access-checked
-         *
          * @return the class that has been access-checked
-         *
-         * @throws IllegalAccessException if the class is not accessible from the lookup class, using the allowed access
-         * modes.
+         * @throws IllegalAccessException if the class is not accessible from the lookup class
+         * and previous lookup class, if present, using the allowed access modes.
          * @exception SecurityException if a security manager is present and it
          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
          * @since 9
+         * @see <a href="#cross-module-lookup">Cross-module lookups</a>
          */
         public Class<?> accessClass(Class<?> targetClass) throws IllegalAccessException {
-            if (!VerifyAccess.isClassAccessible(targetClass, lookupClass, allowedModes)) {
+            if (!VerifyAccess.isClassAccessible(targetClass, lookupClass, prevLookupClass, allowedModes)) {
                 throw new MemberName(targetClass).makeAccessException("access violation", this);
             }
             checkSecurityManager(targetClass, null);
@@ -2083,7 +2778,7 @@
         boolean isClassAccessible(Class<?> refc) {
             Objects.requireNonNull(refc);
             Class<?> caller = lookupClassOrNull();
-            return caller == null || VerifyAccess.isClassAccessible(refc, caller, allowedModes);
+            return caller == null || VerifyAccess.isClassAccessible(refc, caller, prevLookupClass, allowedModes);
         }
 
         /** Check name for an illegal leading "&lt;" character. */
@@ -2220,7 +2915,7 @@
             int requestedModes = fixmods(mods);  // adjust 0 => PACKAGE
             if ((requestedModes & allowedModes) != 0) {
                 if (VerifyAccess.isMemberAccessible(refc, m.getDeclaringClass(),
-                                                    mods, lookupClass(), allowedModes))
+                                                    mods, lookupClass(), previousLookupClass(), allowedModes))
                     return;
             } else {
                 // Protected members can also be checked as if they were package-private.
@@ -2239,9 +2934,10 @@
                                (defc == refc ||
                                 Modifier.isPublic(refc.getModifiers())));
             if (!classOK && (allowedModes & PACKAGE) != 0) {
-                classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), FULL_POWER_MODES) &&
+                // ignore previous lookup class to check if default package access
+                classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), null, FULL_POWER_MODES) &&
                            (defc == refc ||
-                            VerifyAccess.isClassAccessible(refc, lookupClass(), FULL_POWER_MODES)));
+                            VerifyAccess.isClassAccessible(refc, lookupClass(), null, FULL_POWER_MODES)));
             }
             if (!classOK)
                 return "class is not public";
--- a/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java	Wed Jul 24 12:49:44 2019 +0530
+++ b/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java	Thu Jul 25 12:23:54 2019 +0530
@@ -88,18 +88,20 @@
      * @param defc the class in which the proposed member is actually defined
      * @param mods modifier flags for the proposed member
      * @param lookupClass the class for which the access check is being made
+     * @param prevLookupClass the class for which the access check is being made
+     * @param allowedModes allowed modes
      * @return true iff the accessing class can access such a member
      */
     public static boolean isMemberAccessible(Class<?> refc,  // symbolic ref class
                                              Class<?> defc,  // actual def class
                                              int      mods,  // actual member mods
                                              Class<?> lookupClass,
+                                             Class<?> prevLookupClass,
                                              int      allowedModes) {
         if (allowedModes == 0)  return false;
-        assert((allowedModes & PUBLIC) != 0 &&
-               (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0);
+        assert((allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0);
         // The symbolic reference class (refc) must always be fully verified.
-        if (!isClassAccessible(refc, lookupClass, allowedModes)) {
+        if (!isClassAccessible(refc, lookupClass, prevLookupClass, allowedModes)) {
             return false;
         }
         // Usually refc and defc are the same, but verify defc also in case they differ.
@@ -109,6 +111,7 @@
 
         switch (mods & ALL_ACCESS_MODES) {
         case PUBLIC:
+            assert (allowedModes & PUBLIC) != 0 || (allowedModes & UNCONDITIONAL_ALLOWED) != 0;
             return true;  // already checked above
         case PROTECTED:
             assert !defc.isInterface(); // protected members aren't allowed in interfaces
@@ -175,14 +178,23 @@
      * package that is exported to the module that contains D.
      * <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 @@
                 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;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/gc/g1/TestNoUseHCC.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package gc.g1;
+
+/*
+ * @test TestNoUseHCC
+ * @summary Check that G1 survives a GC without HCC enabled
+ * @requires vm.gc.G1
+ * @key gc
+ * @modules java.base/jdk.internal.misc
+ * @library /test/lib
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -Xlog:gc+phases=debug -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC -Xmx64M -XX:G1ConcRSLogCacheSize=0 gc.g1.TestNoUseHCC
+ */
+
+import sun.hotspot.WhiteBox;
+
+public class TestNoUseHCC {
+
+    private static final WhiteBox WB = WhiteBox.getWhiteBox();
+
+    public static void main(String [] args) {
+        WB.youngGC();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/condy/staticInit/Example.jasm	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// This class gets an initialization error in a condy invokestatic.  Need jasm so that StaticInit isn't
+// initialized before the condy call.
+// Test that second invocation gets same error as first.
+
+public class Example
+        version 55:0
+{
+
+
+static Method $jacocoInit:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;"
+        stack 1 locals 3
+{
+                invokestatic        Method StaticInit.get:"()Ljava/lang/Object;";
+                areturn;
+}
+
+public static Method foo:"()V"
+        stack 1 locals 2
+{
+                ldc        Dynamic REF_invokeStatic:Example.$jacocoInit:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;":$jacocoData:"Ljava/lang/Object;";
+                astore_1;
+                return;
+}
+
+public static Method main:"([Ljava/lang/String;)V"
+        stack 1 locals 2
+{
+                try t0;
+                invokestatic        Method Example.foo:"()V";
+                endtry t0;
+                goto        L7;
+                catch t0 java/lang/Error;
+                stack_frame_type stack1;
+                stack_map class java/lang/Error;
+                astore_1;
+                aload_1;
+                invokevirtual        Method java/lang/Error.printStackTrace:"()V";
+        L7:        stack_frame_type same;
+                invokestatic        Method Example.foo:"()V";
+                return;
+}
+} // end Class Example
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/condy/staticInit/StaticInit.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+class StaticInit {
+    static {
+        if (true)
+          throw new RuntimeException();
+    }
+
+    static Object get() {
+        return new Object();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/condy/staticInit/TestInitException.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8228485
+ * @summary Correctly handle initialization error for Condy BSM.
+ * @modules java.base/jdk.internal.misc
+ * @library /test/lib
+ * @compile Example.jasm
+ * @compile StaticInit.java
+ * @run main/othervm TestInitException
+ */
+
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class TestInitException {
+    public static void main(java.lang.String[] unused) throws Exception {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("Example");
+        OutputAnalyzer oa = new OutputAnalyzer(pb.start());
+        // First call stack trace
+        oa.shouldContain("at Example.$jacocoInit(Example.jasm)");
+        oa.shouldContain("Caused by: java.lang.RuntimeException");
+        oa.shouldContain("at StaticInit.<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);
+    }
+}
+
--- a/test/jdk/java/lang/invoke/AccessControlTest.java	Wed Jul 24 12:49:44 2019 +0530
+++ b/test/jdk/java/lang/invoke/AccessControlTest.java	Thu Jul 25 12:23:54 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,6 @@
 import java.lang.reflect.*;
 import java.lang.reflect.Modifier;
 import java.util.*;
-import org.testng.*;
 import org.testng.annotations.*;
 
 import static java.lang.invoke.MethodHandles.*;
@@ -62,23 +61,28 @@
     private class LookupCase implements Comparable<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 int compareTo(LookupCase that) {
             Class<?> c1 = this.lookupClass();
             Class<?> c2 = that.lookupClass();
+            Class<?> p1 = this.prevLookupClass();
+            Class<?> p2 = that.prevLookupClass();
             if (c1 != c2) {
                 int cmp = c1.getName().compareTo(c2.getName());
                 if (cmp != 0)  return cmp;
                 cmp = numberOf(c1.getClassLoader()) - numberOf(c2.getClassLoader());
                 assert(cmp != 0);
                 return cmp;
+            } else if (p1 != p2){
+                if (p1 == null)
+                    return 1;
+                else if (p2 == null)
+                    return -1;
+                int cmp = p1.getName().compareTo(p2.getName());
+                if (cmp != 0)  return cmp;
+                cmp = numberOf(p1.getClassLoader()) - numberOf(p2.getClassLoader());
+                assert(cmp != 0);
+                return cmp;
             }
             return -(this.lookupModes() - that.lookupModes());
         }
@@ -102,6 +118,7 @@
         }
         public boolean equals(LookupCase that) {
             return (this.lookupClass() == that.lookupClass() &&
+                    this.prevLookupClass() == that.prevLookupClass() &&
                     this.lookupModes() == that.lookupModes());
         }
 
@@ -113,20 +130,25 @@
         /** Simulate all assertions in the spec. for Lookup.toString. */
         private String lookupString() {
             String name = lookupClass.getName();
+            if (prevLookupClass != null)
+                name += "/" + prevLookupClass.getName();
             String suffix = "";
             if (lookupModes == 0)
                 suffix = "/noaccess";
             else if (lookupModes == PUBLIC)
                 suffix = "/public";
-             else if (lookupModes == (PUBLIC|UNCONDITIONAL))
+             else if (lookupModes == UNCONDITIONAL)
                 suffix = "/publicLookup";
             else if (lookupModes == (PUBLIC|MODULE))
                 suffix = "/module";
-            else if (lookupModes == (PUBLIC|MODULE|PACKAGE))
+            else if (lookupModes == (PUBLIC|PACKAGE)
+                     || lookupModes == (PUBLIC|MODULE|PACKAGE))
                 suffix = "/package";
-            else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE))
+            else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE)
+                    || lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE))
                 suffix = "/private";
-            else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED))
+            else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE|PROTECTED)
+                     || lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED))
                 suffix = "";
             else
                 suffix = "/#"+Integer.toHexString(lookupModes);
@@ -138,41 +160,50 @@
          * Creates a lookup on the specified new lookup class.
          * [A1] The resulting object will report the specified
          * class as its own {@link #lookupClass lookupClass}.
-         * <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 @@
             assert(samePackage  || !sameTopLevel);
             assert(sameTopLevel || !sameClass);
             boolean accessible = sameClass;
-            if ((m1 & PACKAGE) != 0)  accessible |= samePackage;
-            if ((m1 & PUBLIC ) != 0)  accessible |= (c2.getModifiers() & PUBLIC) != 0;
-            if (!sameModule) {
-                if (c1.getModule().isNamed() && (m1 & UNCONDITIONAL) == 0) {
-                    accessible = false;  // [A3]
-                } else {
-                    changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED);    // [A3] [A4]
-                }
+
+            if ((modes1 & PACKAGE) != 0)  accessible |= samePackage;
+            if ((modes1 & PUBLIC ) != 0)  {
+                if (isModuleAccessible(c2))
+                    accessible |= (c2.getModifiers() & PUBLIC) != 0;
+                else
+                    accessible = false;
+            }
+            if ((modes1 & UNCONDITIONAL) != 0) {
+                if (m2.isExported(c2.getPackageName()))
+                    accessible |= (c2.getModifiers() & PUBLIC) != 0;
+                else
+                    accessible = false;
             }
             if (!accessible) {
-                // Different package and no access to c2; lose all access.
-                changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED);  // [A8]
+                // no access to c2; lose all access.
+                changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED|UNCONDITIONAL);  // [A6]
+            }
+            if (m2 != m1 && m0 != m1) {
+                // hop to a third module; lose all access
+                changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED);  // [A7]
+            }
+            if (!sameModule) {
+                changed |= MODULE;  // [A3]
             }
             if (!samePackage) {
                 // Different package; loose PACKAGE and lower access.
-                changed |= (PACKAGE|PRIVATE|PROTECTED);  // [A6]
+                changed |= (PACKAGE|PRIVATE|PROTECTED);  // [A4]
             }
             if (!sameTopLevel) {
                 // Different top-level class.  Lose PRIVATE and PROTECTED access.
-                changed |= (PRIVATE|PROTECTED);  // [A5] [A7]
+                changed |= (PRIVATE|PROTECTED);  // [A5]
             }
-            if (!sameClass) {
-                changed |= (UNCONDITIONAL);     // [A5]
-            } else {
-                assert(changed == 0);       // [A10] (no deprivation if same class)
+            if (sameClass) {
+                assert(changed == 0);       // [A11] (no deprivation if same class)
             }
-            if (accessible)  assert((changed & PUBLIC) == 0);  // [A9]
-            int m2 = m1 & ~changed;
-            LookupCase l2 = new LookupCase(c2, m2);
-            assert(l2.lookupClass() == c2); // [A1]
-            assert((m1 | m2) == m1);        // [A2] (no elevation of access)
+
+            if (accessible)  assert((changed & PUBLIC) == 0);
+            int modes2 = modes1 & ~changed;
+            Class<?> plc = (m1 == m2) ? prevLookupClass() : c1; // [A9] [A10]
+            if ((modes1 & UNCONDITIONAL) != 0) plc = null;      // [A8]
+            LookupCase l2 = new LookupCase(c2, plc, modes2);
+            assert(l2.lookupClass() == c2);         // [A1]
+            assert((modes1 | modes2) == modes1);    // [A2] (no elevation of access)
+            assert(l2.prevLookupClass() == null || (modes2 & MODULE) == 0);
             return l2;
         }
 
+        LookupCase dropLookupMode(int modeToDrop) {
+            int oldModes = lookupModes();
+            int newModes = oldModes & ~(modeToDrop | PROTECTED);
+            switch (modeToDrop) {
+                case PUBLIC: newModes &= ~(MODULE|PACKAGE|PROTECTED|PRIVATE); break;
+                case MODULE: newModes &= ~(PACKAGE|PRIVATE); break;
+                case PACKAGE: newModes &= ~(PRIVATE); break;
+                case PROTECTED:
+                case PRIVATE:
+                case UNCONDITIONAL: break;
+                default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop");
+            }
+            if (newModes == oldModes) return this;  // return self if no change
+            LookupCase l2 = new LookupCase(lookupClass(), prevLookupClass(), newModes);
+            assert((oldModes | newModes) == oldModes);    // [A2] (no elevation of access)
+            assert(l2.prevLookupClass() == null || (newModes & MODULE) == 0);
+            return l2;
+        }
+
+        boolean isModuleAccessible(Class<?> c) {
+            Module m1 = lookupClass().getModule();
+            Module m2 = c.getModule();
+            Module m0 = prevLookupClass() != null ? prevLookupClass.getModule() : m1;
+            String pn = c.getPackageName();
+            boolean accessible = m1.canRead(m2) && m2.isExported(pn, m1);
+            if (m1 != m0) {
+                accessible = accessible && m0.canRead(m2) && m2.isExported(pn, m0);
+            }
+            return accessible;
+        }
+
         @Override
         public String toString() {
             String s = lookupClass().getSimpleName();
@@ -229,33 +305,48 @@
         public boolean willAccess(Method m) {
             Class<?> c1 = lookupClass();
             Class<?> c2 = m.getDeclaringClass();
+            Module m1 = c1.getModule();
+            Module m2 = c2.getModule();
+            Module m0 = prevLookupClass != null ? prevLookupClass.getModule() : m1;
+            // unconditional has access to all public types/members of types that is in a package
+            // are unconditionally exported
+            if ((lookupModes & UNCONDITIONAL) != 0) {
+                return m2.isExported(c2.getPackageName())
+                       && Modifier.isPublic(c2.getModifiers())
+                       && Modifier.isPublic(m.getModifiers());
+            }
 
-            // publicLookup has access to all public types/members of types in unnamed modules
-            if ((lookupModes & UNCONDITIONAL) != 0
-                && (lookupModes & PUBLIC) != 0
-                && !c2.getModule().isNamed()
-                && Modifier.isPublic(c2.getModifiers())
-                && Modifier.isPublic(m.getModifiers()))
-                return true;
+            // c1 and c2 are in different module
+            if (m1 != m2 || m0 != m2) {
+                return (lookupModes & PUBLIC) != 0
+                       && isModuleAccessible(c2)
+                       && Modifier.isPublic(c2.getModifiers())
+                       && Modifier.isPublic(m.getModifiers());
+            }
+
+            assert(m1 == m2 && prevLookupClass == null);
+
+            if (!willAccessClass(c2, false))
+                return false;
 
             LookupCase lc = this.in(c2);
-            int m1 = lc.lookupModes();
-            int m2 = fixMods(m.getModifiers());
+            int modes1 = lc.lookupModes();
+            int modes2 = fixMods(m.getModifiers());
             // allow private lookup on nestmates. Otherwise, privacy is strictly enforced
-            if (c1 != c2 && ((m2 & PRIVATE) == 0 || !c1.isNestmateOf(c2))) {
-                m1 &= ~PRIVATE;
+            if (c1 != c2 && ((modes2 & PRIVATE) == 0 || !c1.isNestmateOf(c2))) {
+                modes1 &= ~PRIVATE;
             }
             // protected access is sometimes allowed
-            if ((m2 & PROTECTED) != 0) {
-                int prev = m2;
-                m2 |= PACKAGE;  // it acts like a package method also
+            if ((modes2 & PROTECTED) != 0) {
+                int prev = modes2;
+                modes2 |= PACKAGE;  // it acts like a package method also
                 if ((lookupModes() & PROTECTED) != 0 &&
                     c2.isAssignableFrom(c1))
-                    m2 |= PUBLIC;  // from a subclass, it acts like a public method also
+                    modes2 |= PUBLIC;  // from a subclass, it acts like a public method also
             }
             if (verbosity >= 2)
-                System.out.format("%s willAccess %s m1=0x%h m2=0x%h => %s%n", this, lc, m1, m2, ((m2 & m1) != 0));
-            return (m2 & m1) != 0;
+                System.out.format("%s willAccess %s modes1=0x%h modes2=0x%h => %s%n", lookupString(), lc.lookupString(), modes1, modes2, (modes2 & modes1) != 0);
+            return (modes2 & modes1) != 0;
         }
 
         /** Predict the success or failure of accessing this class. */
@@ -268,24 +359,36 @@
                 }
             }
 
-            // publicLookup has access to all public types/members of types in unnamed modules
-            if ((lookupModes & UNCONDITIONAL) != 0
-                && (lookupModes & PUBLIC) != 0
-                && (!c2.getModule().isNamed())
-                && Modifier.isPublic(c2.getModifiers()))
-                return true;
+            Module m1 = c1.getModule();
+            Module m2 = c2.getModule();
+            Module m0 = prevLookupClass != null ? prevLookupClass.getModule() : m1;
+            // unconditional has access to all public types that is in an unconditionally exported package
+            if ((lookupModes & UNCONDITIONAL) != 0) {
+                return m2.isExported(c2.getPackageName()) && Modifier.isPublic(c2.getModifiers());
+            }
+            // c1 and c2 are in different module
+            if (m1 != m2 || m0 != m2) {
+                return (lookupModes & PUBLIC) != 0
+                    && isModuleAccessible(c2)
+                    && Modifier.isPublic(c2.getModifiers());
+            }
+
+            assert(m1 == m2 && prevLookupClass == null);
 
             LookupCase lc = this.in(c2);
-            int m1 = lc.lookupModes();
+            int modes1 = lc.lookupModes();
             boolean r = false;
-            if (m1 == 0) {
+            if (modes1 == 0) {
                 r = false;
             } else {
-                int m2 = fixMods(c2.getModifiers());
-                if ((m2 & PUBLIC) != 0) {
-                    r = true;
-                } else if ((m1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage()) {
-                    r = true;
+                if (Modifier.isPublic(c2.getModifiers())) {
+                    if ((modes1 & MODULE) != 0)
+                        r = true;
+                    else if ((modes1 & PUBLIC) != 0)
+                        r = m1.isExported(c2.getPackageName());
+                } else {
+                    if ((modes1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage())
+                        r = true;
                 }
             }
             if (verbosity >= 2) {
@@ -328,7 +431,7 @@
         return i+1;
     }
 
-    private void addLookupEdge(LookupCase l1, Class<?> c2, LookupCase l2) {
+    private void addLookupEdge(LookupCase l1, Class<?> c2, LookupCase l2, int dropAccess) {
         TreeSet<LookupCase> edges = CASE_EDGES.get(l2);
         if (edges == null)  CASE_EDGES.put(l2, edges = new TreeSet<>());
         if (edges.add(l1)) {
@@ -337,7 +440,7 @@
             int m1 = l1.lookupModes();
             int m2 = l2.lookupModes();
             assert((m1 | m2) == m1);        // [A2] (no elevation of access)
-            LookupCase expect = l1.in(c2);
+            LookupCase expect = dropAccess == 0 ? l1.in(c2) : l1.in(c2).dropLookupMode(dropAccess);
             if (!expect.equals(l2))
                 System.out.println("*** expect "+l1+" => "+expect+" but got "+l2);
             assertEquals(l2, expect);
@@ -358,9 +461,14 @@
         for (int lastCount = -1; lastCount != CASES.size(); ) {
             lastCount = CASES.size();  // if CASES grow in the loop we go round again
             for (LookupCase lc1 : CASES.toArray(new LookupCase[0])) {
+                for (int mode : ACCESS_CASES) {
+                    LookupCase lc2 = new LookupCase(lc1.lookup().dropLookupMode(mode));
+                    addLookupEdge(lc1, lc1.lookupClass(), lc2, mode);
+                    CASES.add(lc2);
+                }
                 for (Class<?> c2 : classes) {
                     LookupCase lc2 = new LookupCase(lc1.lookup().in(c2));
-                    addLookupEdge(lc1, c2, lc2);
+                    addLookupEdge(lc1, c2, lc2, 0);
                     CASES.add(lc2);
                 }
             }
@@ -386,8 +494,8 @@
         if (verbosity > 0) {
             verbosity += 9;
             Method pro_in_self = targetMethod(THIS_CLASS, PROTECTED, methodType(void.class));
-            testOneAccess(lookupCase("AccessControlTest/public"),  pro_in_self, "find");
-            testOneAccess(lookupCase("Remote_subclass/public"),    pro_in_self, "find");
+            testOneAccess(lookupCase("AccessControlTest/module"),  pro_in_self, "find");
+            testOneAccess(lookupCase("Remote_subclass/module"),    pro_in_self, "find");
             testOneAccess(lookupCase("Remote_subclass"),           pro_in_self, "find");
             verbosity -= 9;
         }
@@ -398,6 +506,8 @@
             String targetPlace = placeName(targetClass);
             if (targetPlace == null)  continue;  // Object, String, not a target
             for (int targetAccess : ACCESS_CASES) {
+                if (targetAccess == MODULE || targetAccess == UNCONDITIONAL)
+                    continue;
                 MethodType methodType = methodType(void.class);
                 Method method = targetMethod(targetClass, targetAccess, methodType);
                 // Try to access target method from various contexts.
@@ -457,7 +567,6 @@
     }
 
     static Method targetMethod(Class<?> targetClass, int targetAccess, MethodType methodType) {
-        assert targetAccess != MODULE;
         String methodName = accessName(targetAccess)+placeName(targetClass);
         if (verbosity >= 2)
             System.out.println(targetClass.getSimpleName()+"."+methodName+methodType);
@@ -491,10 +600,13 @@
         assert(false);
         return "?";
     }
-    // MODULE not a test case at this time
     private static final int[] ACCESS_CASES = {
-        PUBLIC, PACKAGE, PRIVATE, PROTECTED
+        PUBLIC, PACKAGE, PRIVATE, PROTECTED, MODULE, UNCONDITIONAL
     };
+    /*
+     * Adjust PUBLIC => PUBLIC|MODULE|UNCONDITIONAL
+     * Adjust 0 => PACKAGE
+     */
     /** Return one of the ACCESS_CASES. */
     static int fixMods(int mods) {
         mods &= (PUBLIC|PRIVATE|PROTECTED);
--- a/test/jdk/java/lang/invoke/DropLookupModeTest.java	Wed Jul 24 12:49:44 2019 +0530
+++ b/test/jdk/java/lang/invoke/DropLookupModeTest.java	Thu Jul 25 12:23:54 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -106,37 +106,39 @@
         assertTrue(lookup.lookupModes() == 0);
     }
 
-    /**
-     * Test dropLookupMode on the public Lookup.
-     */
-    public void testPublicLookup() {
-        final Lookup publicLookup = MethodHandles.publicLookup();
-        final Class<?> lc = publicLookup.lookupClass();
-        assertTrue(publicLookup.lookupModes() == (PUBLIC|UNCONDITIONAL));
-
-        Lookup lookup = publicLookup.dropLookupMode(PRIVATE);
-        assertTrue(lookup.lookupClass() == lc);
-        assertTrue(lookup.lookupModes() == PUBLIC);
-
-        lookup = publicLookup.dropLookupMode(PROTECTED);
-        assertTrue(lookup.lookupClass() == lc);
-        assertTrue(lookup.lookupModes() == PUBLIC);
+    @DataProvider(name = "unconditionals")
+    public Object[][] unconditionals() {
+        Lookup publicLookup = MethodHandles.publicLookup();
+        return new Object[][] {
+            { publicLookup, Object.class },
+            { publicLookup.in(String.class), String.class },
+            { publicLookup.in(DropLookupModeTest.class), DropLookupModeTest.class },
+        };
+    }
 
-        lookup = publicLookup.dropLookupMode(PACKAGE);
-        assertTrue(lookup.lookupClass() == lc);
-        assertTrue(lookup.lookupModes() == PUBLIC);
-
-        lookup = publicLookup.dropLookupMode(MODULE);
-        assertTrue(lookup.lookupClass() == lc);
-        assertTrue(lookup.lookupModes() == PUBLIC);
+    /**
+     * Test dropLookupMode on the lookup with public lookup
+     * and UNCONDITIONAL
+     */
+    @Test(dataProvider = "unconditionals")
+    public void testUnconditionalLookup(Lookup unconditionalLookup, Class<?> expected) {
+        assertTrue(unconditionalLookup.lookupModes() == UNCONDITIONAL);
 
-        lookup = publicLookup.dropLookupMode(PUBLIC);
-        assertTrue(lookup.lookupClass() == lc);
-        assertTrue(lookup.lookupModes() == 0);
+        assertPublicLookup(unconditionalLookup.dropLookupMode(PRIVATE), expected);
+        assertPublicLookup(unconditionalLookup.dropLookupMode(PROTECTED), expected);
+        assertPublicLookup(unconditionalLookup.dropLookupMode(PACKAGE), expected);
+        assertPublicLookup(unconditionalLookup.dropLookupMode(MODULE), expected);
+        assertPublicLookup(unconditionalLookup.dropLookupMode(PUBLIC), expected);
 
-        lookup = publicLookup.dropLookupMode(UNCONDITIONAL);
-        assertTrue(lookup.lookupClass() == lc);
-        assertTrue(lookup.lookupModes() == PUBLIC);
+        // drop all access
+        Lookup lookup = unconditionalLookup.dropLookupMode(UNCONDITIONAL);
+        assertTrue(lookup.lookupClass() == expected);
+        assertTrue(lookup.lookupModes() == 0);
+    }
+
+    private void assertPublicLookup(Lookup lookup, Class<?> expected) {
+        assertTrue(lookup.lookupClass() == expected);
+        assertTrue(lookup.lookupModes() == UNCONDITIONAL);
     }
 
     @DataProvider(name = "badInput")
@@ -157,4 +159,4 @@
         MethodHandles.lookup().dropLookupMode(modeToDrop);
     }
 
-}
\ No newline at end of file
+}
--- a/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java	Wed Jul 24 12:49:44 2019 +0530
+++ b/test/jdk/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java	Thu Jul 25 12:23:54 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -82,6 +82,7 @@
     }
 
     // Invoke MethodHandles.privateLookupIn with a reduced-power caller
+    @Test(expectedExceptions = {IllegalAccessException.class})
     public void testReducedAccessCallerSameModule() throws Throwable {
         Lookup caller = MethodHandles.lookup().dropLookupMode(PACKAGE);
         assertTrue((caller.lookupModes() & PRIVATE) == 0);
@@ -89,12 +90,6 @@
         assertTrue((caller.lookupModes() & MODULE) != 0);
 
         Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, caller);
-        assertTrue(lookup.lookupClass() == nonPublicType);
-        assertTrue(lookup.hasPrivateAccess());
-
-        // use it
-        MethodHandle mh = lookup.findStaticGetter(nonPublicType, "obj", Object.class);
-        Object obj = mh.invokeExact();
     }
 
     // Invoke MethodHandles.privateLookupIn with the public lookup as caller
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/Driver1.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8173978
+ * @build m3/* m4/* m5/* Unnamed Unnamed1
+ * @run testng/othervm m3/jdk.test.ModuleAccessTest
+ * @summary Basic test case for module access checks and Lookup.in and
+ *          MethodHandles.privateLookupIn
+ */
--- a/test/jdk/java/lang/invoke/modules/Unnamed.java	Wed Jul 24 12:49:44 2019 +0530
+++ b/test/jdk/java/lang/invoke/modules/Unnamed.java	Thu Jul 25 12:23:54 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -21,4 +21,11 @@
  * questions.
  */
 
-public class Unnamed { }
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+
+public class Unnamed {
+    public static Lookup lookup() {
+        return MethodHandles.lookup();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/Unnamed1.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public class Unnamed1 { }
--- a/test/jdk/java/lang/invoke/modules/m1/p1/Main.java	Wed Jul 24 12:49:44 2019 +0530
+++ b/test/jdk/java/lang/invoke/modules/m1/p1/Main.java	Thu Jul 25 12:23:54 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,7 +45,7 @@
     private Class<?> p2_Type2;        // m1, not exported
     private Class<?> q1_Type1;        // m2, exported
     private Class<?> q2_Type2;        // m2, not exported
-    private Class<?> x500NameClass;   // java.base, not exported
+    private Class<?> signalClass;     // java.base, not exported
     private Class<?> unnamedClass;    // class in unnamed module
 
     @BeforeTest
@@ -55,7 +55,7 @@
             p2_Type2 = Class.forName("p2.Type2");
             q1_Type1 = Class.forName("q1.Type1");
             q2_Type2 = Class.forName("q2.Type2");
-            x500NameClass = Class.forName("sun.security.x509.X500Name");
+            signalClass = Class.forName("jdk.internal.misc.Signal");
             unnamedClass = Class.forName("Unnamed");
         } catch (ClassNotFoundException e) {
             throw new AssertionError(e);
@@ -105,7 +105,7 @@
 
         // java.base
         findConstructor(lookup, Object.class, void.class); // [A2]
-        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // [A3]
+        findConstructorExpectingIAE(lookup, signalClass, void.class, String.class); // [A3]
 
         // unnamed
         findConstructor(lookup, unnamedClass, void.class);  // [A3]
@@ -130,7 +130,7 @@
 
         // java.base
         findConstructor(lookup, Object.class, void.class);
-        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
+        findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 
         // unnamed
         findConstructor(lookup, unnamedClass, void.class);
@@ -139,51 +139,70 @@
     /**
      * Hop to lookup class in another named module
      *
-     * [A0] has no access
+     * [A0] has PUBLIC access if accessible; otherwise no access
+     * [A1] old lookup class becomes previous lookup class
      */
     public void testFromNamedToNamedModule() throws Exception {
+        // m2/q1_Type1 is accessible to m1 whereas m2/q_Type2 is not accessible
         Lookup lookup = MethodHandles.lookup().in(q1_Type1);
-        assertTrue(lookup.lookupModes() == 0); // [A0]
+        assertTrue(lookup.lookupModes() == PUBLIC); // [A0]
+        assertTrue(lookup.previousLookupClass() == Main.class); // [A1]
+
+        Lookup lookup2 = MethodHandles.lookup().in(q2_Type2);
+        assertTrue(lookup2.lookupModes() == 0);      // [A0]
+        assertTrue(lookup2.previousLookupClass() == Main.class); // [A1]
 
         // m1
         findConstructorExpectingIAE(lookup, p1_Type1, void.class);
         findConstructorExpectingIAE(lookup, p2_Type2, void.class);
 
+        findConstructorExpectingIAE(lookup2, p1_Type1, void.class);
+        findConstructorExpectingIAE(lookup2, p2_Type2, void.class);
+
         // m2
-        findConstructorExpectingIAE(lookup, q1_Type1, void.class);
+        findConstructor(lookup, q1_Type1, void.class);  // m2/q1 is exported
         findConstructorExpectingIAE(lookup, q2_Type2, void.class);
 
+        findConstructorExpectingIAE(lookup2, q1_Type1, void.class);
+        findConstructorExpectingIAE(lookup2, q2_Type2, void.class);
+
         // java.base
-        findConstructorExpectingIAE(lookup, Object.class, void.class);
-        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
+        findConstructor(lookup, Object.class, void.class);
+        findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
+
+        findConstructorExpectingIAE(lookup2, Object.class, void.class);
+        findConstructorExpectingIAE(lookup2, signalClass, void.class, String.class);
 
         // unnamed
         findConstructorExpectingIAE(lookup, unnamedClass, void.class);
+
+        findConstructorExpectingIAE(lookup2, unnamedClass, void.class);
+
     }
 
     /**
      * Hop to lookup class in an unnamed module
      *
-     * [A0] has no access
+     * [A0] has PUBLIC access
      */
     public void testFromNamedToUnnamedModule() throws Exception {
         Lookup lookup = MethodHandles.lookup().in(unnamedClass);
-        assertTrue(lookup.lookupModes() == 0); // [A0]
+        assertTrue(lookup.lookupModes() == PUBLIC); // [A0]
 
         // m1
-        findConstructorExpectingIAE(lookup, p1_Type1, void.class);
+        findConstructor(lookup, p1_Type1, void.class);      // p1 is exported
         findConstructorExpectingIAE(lookup, p2_Type2, void.class);
 
         // m2
-        findConstructorExpectingIAE(lookup, q1_Type1, void.class);
+        findConstructor(lookup, q1_Type1, void.class);
         findConstructorExpectingIAE(lookup, q2_Type2, void.class);
 
         // java.base
-        findConstructorExpectingIAE(lookup, Object.class, void.class);
-        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
+        findConstructor(lookup, Object.class, void.class);
+        findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 
         // unnamed
-        findConstructorExpectingIAE(lookup, unnamedClass, void.class);
+        findConstructor(lookup, unnamedClass, void.class);
     }
 
     /**
@@ -206,7 +225,7 @@
 
         // java.base
         findConstructor(lookup, Object.class, void.class);
-        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
+        findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 
         // unnamed
         findConstructor(lookup, unnamedClass, void.class);
@@ -215,11 +234,11 @@
     /**
      * MethodHandles.publicLookup()
      *
-     * [A0] has PUBLIC|UNCONDITIONAL access
+     * [A0] has UNCONDITIONAL access
      */
     public void testPublicLookup() throws Exception {
         Lookup lookup = MethodHandles.publicLookup();
-        assertTrue(lookup.lookupModes() == (PUBLIC|UNCONDITIONAL)); // A0
+        assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0
 
         // m1
         findConstructor(lookup, p1_Type1, void.class);
@@ -231,7 +250,7 @@
 
         // java.base
         findConstructor(lookup, Object.class, void.class);
-        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
+        findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 
         // unnamed
         findConstructor(lookup, unnamedClass, void.class);
@@ -239,36 +258,12 @@
 
     /**
      * Hop from publicLookup to accessible type in java.base
+     *
+     * [A0] has UNCONDITIONAL access
      */
     public void testPublicLookupToBaseModule() throws Exception {
         Lookup lookup = MethodHandles.publicLookup().in(String.class);
-        assertTrue(lookup.lookupModes() == PUBLIC); // A0
-
-        // m1
-        findConstructorExpectingIAE(lookup, p1_Type1, void.class);
-        findConstructorExpectingIAE(lookup, p2_Type2, void.class);
-
-        // m2
-        findConstructorExpectingIAE(lookup, q1_Type1, void.class);
-        findConstructorExpectingIAE(lookup, q2_Type2, void.class);
-
-        // java.base
-        findConstructor(lookup, Object.class, void.class);
-        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
-
-        // unnamed
-        findConstructorExpectingIAE(lookup, unnamedClass, void.class);
-    }
-
-
-    /**
-     * Hop from publicLookup to accessible type in named module.
-     *
-     * [A0] has PUBLIC access
-     */
-    public void testPublicLookupToAccessibleTypeInNamedModule() throws Exception {
-        Lookup lookup = MethodHandles.publicLookup().in(p1_Type1);
-        assertTrue(lookup.lookupModes() == PUBLIC); // A0
+        assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0
 
         // m1
         findConstructor(lookup, p1_Type1, void.class);
@@ -280,7 +275,33 @@
 
         // java.base
         findConstructor(lookup, Object.class, void.class);
-        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
+        findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
+
+        // unnamed
+        findConstructor(lookup, unnamedClass, void.class);
+    }
+
+
+    /**
+     * Hop from publicLookup to accessible type in named module.
+     *
+     * [A0] has UNCONDITIONAL access
+     */
+    public void testPublicLookupToAccessibleTypeInNamedModule() throws Exception {
+        Lookup lookup = MethodHandles.publicLookup().in(p1_Type1);
+        assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0
+
+        // m1
+        findConstructor(lookup, p1_Type1, void.class);
+        findConstructorExpectingIAE(lookup, p2_Type2, void.class);
+
+        // m2
+        findConstructor(lookup, q1_Type1, void.class);
+        findConstructorExpectingIAE(lookup, q2_Type2, void.class);
+
+        // java.base
+        findConstructor(lookup, Object.class, void.class);
+        findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 
         // unnamed
         findConstructor(lookup, unnamedClass, void.class);
@@ -305,7 +326,7 @@
 
         // java.base
         findConstructorExpectingIAE(lookup, Object.class, void.class);
-        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
+        findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 
         // unnamed
         findConstructorExpectingIAE(lookup, unnamedClass, void.class);
@@ -314,11 +335,11 @@
     /**
      * Teleport from publicLookup to public type in unnamed module
      *
-     * [A0] has PUBLIC access
+     * [A0] has UNCONDITIONAL access
      */
     public void testPublicLookupToUnnamedModule() throws Exception {
         Lookup lookup = MethodHandles.publicLookup().in(unnamedClass);
-        assertTrue(lookup.lookupModes() == PUBLIC); // A0
+        assertTrue(lookup.lookupModes() == UNCONDITIONAL); // A0
 
         // m1
         findConstructor(lookup, p1_Type1, void.class);
@@ -330,7 +351,7 @@
 
         // java.base
         findConstructor(lookup, Object.class, void.class);
-        findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class);
+        findConstructorExpectingIAE(lookup, signalClass, void.class, String.class);
 
         // unnamed
         findConstructor(lookup, unnamedClass, void.class);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m3/c1/C1.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package c1;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+
+public class C1 {
+    public C1() { }
+
+    public static Lookup lookup() {
+        return MethodHandles.lookup();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m3/c1/C2.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package c1;
+
+public class C2 {
+    public C2() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m3/c2/C3.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package c2;
+
+public class C3{
+    public C3() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m3/jdk/test/ModuleAccessTest.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,568 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import e1.CrackM5Access;
+
+import static java.lang.invoke.MethodHandles.Lookup.*;
+import static org.testng.Assert.*;
+
+public class ModuleAccessTest {
+    static ModuleLookup m3;
+    static ModuleLookup m4;
+    static ModuleLookup m5;
+    static Map<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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m3/module-info.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m3 {
+    requires m4;
+    requires m5;
+    requires testng;
+    requires java.management;
+    exports c1;
+    opens c2 to m5;
+    exports jdk.test;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m4/d1/D1.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package d1;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+
+public class D1 {
+    public D1() { }
+
+    public static Lookup lookup() {
+        return MethodHandles.lookup();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m4/d1/D2.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package d1;
+
+public class D2 {
+    public D2() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m4/d2/D3.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package d2;
+
+public class D3 {
+    public D3() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m4/module-info.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m4 {
+    requires m5;
+    opens d1;
+    exports d2 to m3;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m5/e1/CrackM5Access.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package e1;
+
+public class CrackM5Access {
+    private static void privateMethod() { }
+
+    static void packageMethod() { }
+
+    public static void addReads(Module m) {
+        CrackM5Access.class.getModule().addReads(m);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m5/e1/E1.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package e1;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+
+public class E1 {
+    public E1() { }
+
+    public static Lookup lookup() {
+        return MethodHandles.lookup();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m5/e1/E2.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package e1;
+
+public class E2 {
+    public E2() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m5/e1/NonPublic.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package e1;
+
+class NonPublic {
+    public static void publicStatic() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m5/e1/Statics.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package e1;
+
+public class Statics {
+    private static void privateMethod() { }
+
+    static void packageMethod() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m5/e2/E3.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package e2;
+
+public class E3 {
+    public E3() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/modules/m5/module-info.java	Thu Jul 25 12:23:54 2019 +0530
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m5 {
+    exports e1 to m3;
+    opens e1 to m3, m4;
+    exports e2 to m3;
+}
--- a/test/jdk/java/net/NetworkInterface/NetworkInterfaceRetrievalTests.java	Wed Jul 24 12:49:44 2019 +0530
+++ b/test/jdk/java/net/NetworkInterface/NetworkInterfaceRetrievalTests.java	Thu Jul 25 12:23:54 2019 +0530
@@ -24,6 +24,7 @@
 /**
  * @test
  * @bug 8179559 8225239
+ * @modules java.base/java.net:open
  */
 
 import java.net.InetAddress;