changeset 12667:40d9f4c7daf7

Merge
author jwilhelm
date Mon, 27 Feb 2017 18:24:19 +0100
parents 9211c2e89c1c (current diff) 606c35b6fac5 (diff)
children 492ed7f0906d
files
diffstat 13 files changed, 298 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/arm/vm/c1_Runtime1_arm.cpp	Fri Feb 24 19:48:33 2017 +0100
+++ b/src/cpu/arm/vm/c1_Runtime1_arm.cpp	Mon Feb 27 18:24:19 2017 +0100
@@ -618,7 +618,7 @@
         Address buffer(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() +
                                          DirtyCardQueue::byte_offset_of_buf()));
 
-        AddressLiteral cardtable((address)ct->byte_map_base);
+        AddressLiteral cardtable((address)ct->byte_map_base, relocInfo::none);
         assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
 
         // save at least the registers that need saving if the runtime is called
@@ -645,7 +645,7 @@
         // Note: there is a comment in x86 code about not using
         // ExternalAddress / lea, due to relocation not working
         // properly for that address. Should be OK for arm, where we
-        // explicitly specify that 'cartable' has a relocInfo::none
+        // explicitly specify that 'cardtable' has a relocInfo::none
         // type.
         __ lea(r_card_base_1, cardtable);
         __ add(r_card_addr_0, r_card_base_1, AsmOperand(r_obj_0, lsr, CardTableModRefBS::card_shift));
--- a/src/share/vm/classfile/classLoaderData.cpp	Fri Feb 24 19:48:33 2017 +0100
+++ b/src/share/vm/classfile/classLoaderData.cpp	Mon Feb 27 18:24:19 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017, 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
@@ -93,7 +93,7 @@
   _keep_alive((is_anonymous || h_class_loader.is_null()) ? 1 : 0),
   _metaspace(NULL), _unloading(false), _klasses(NULL),
   _modules(NULL), _packages(NULL),
-  _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL),
+  _claimed(0), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
   _next(NULL), _dependencies(dependencies),
   _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
                             Monitor::_safepoint_check_never)) {
@@ -112,6 +112,76 @@
   _list_head = oopFactory::new_objectArray(2, CHECK);
 }
 
+ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() {
+  Chunk* c = _head;
+  while (c != NULL) {
+    Chunk* next = c->_next;
+    delete c;
+    c = next;
+  }
+}
+
+oop* ClassLoaderData::ChunkedHandleList::add(oop o) {
+  if (_head == NULL || _head->_size == Chunk::CAPACITY) {
+    Chunk* next = new Chunk(_head);
+    OrderAccess::release_store_ptr(&_head, next);
+  }
+  oop* handle = &_head->_data[_head->_size];
+  *handle = o;
+  OrderAccess::release_store(&_head->_size, _head->_size + 1);
+  return handle;
+}
+
+inline void ClassLoaderData::ChunkedHandleList::oops_do_chunk(OopClosure* f, Chunk* c, const juint size) {
+  for (juint i = 0; i < size; i++) {
+    if (c->_data[i] != NULL) {
+      f->do_oop(&c->_data[i]);
+    }
+  }
+}
+
+void ClassLoaderData::ChunkedHandleList::oops_do(OopClosure* f) {
+  Chunk* head = (Chunk*) OrderAccess::load_ptr_acquire(&_head);
+  if (head != NULL) {
+    // Must be careful when reading size of head
+    oops_do_chunk(f, head, OrderAccess::load_acquire(&head->_size));
+    for (Chunk* c = head->_next; c != NULL; c = c->_next) {
+      oops_do_chunk(f, c, c->_size);
+    }
+  }
+}
+
+#ifdef ASSERT
+class VerifyContainsOopClosure : public OopClosure {
+  oop* _target;
+  bool _found;
+
+ public:
+  VerifyContainsOopClosure(oop* target) : _target(target), _found(false) {}
+
+  void do_oop(oop* p) {
+    if (p == _target) {
+      _found = true;
+    }
+  }
+
+  void do_oop(narrowOop* p) {
+    // The ChunkedHandleList should not contain any narrowOop
+    ShouldNotReachHere();
+  }
+
+  bool found() const {
+    return _found;
+  }
+};
+
+bool ClassLoaderData::ChunkedHandleList::contains(oop* p) {
+  VerifyContainsOopClosure cl(p);
+  oops_do(&cl);
+  return cl.found();
+}
+#endif
+
 bool ClassLoaderData::claim() {
   if (_claimed == 1) {
     return false;
@@ -146,9 +216,9 @@
 
   f->do_oop(&_class_loader);
   _dependencies.oops_do(f);
-  if (_handles != NULL) {
-    _handles->oops_do(f);
-  }
+
+  _handles.oops_do(f);
+
   if (klass_closure != NULL) {
     classes_do(klass_closure);
   }
@@ -484,12 +554,6 @@
     _metaspace = NULL;
     delete m;
   }
-  // release the handles
-  if (_handles != NULL) {
-    JNIHandleBlock::release_block(_handles);
-    _handles = NULL;
-  }
-
   // Clear all the JNI handles for methods
   // These aren't deallocated and are going to look like a leak, but that's
   // needed because we can't really get rid of jmethodIDs because we don't
@@ -563,19 +627,14 @@
   return metaspace;
 }
 
-JNIHandleBlock* ClassLoaderData::handles() const           { return _handles; }
-void ClassLoaderData::set_handles(JNIHandleBlock* handles) { _handles = handles; }
-
 jobject ClassLoaderData::add_handle(Handle h) {
   MutexLockerEx ml(metaspace_lock(),  Mutex::_no_safepoint_check_flag);
-  if (handles() == NULL) {
-    set_handles(JNIHandleBlock::allocate_block());
-  }
-  return handles()->allocate_handle(h());
+  return (jobject) _handles.add(h());
 }
 
-void ClassLoaderData::remove_handle(jobject h) {
-  _handles->release_handle(h);
+void ClassLoaderData::remove_handle_unsafe(jobject h) {
+  assert(_handles.contains((oop*) h), "Got unexpected handle " PTR_FORMAT, p2i((oop*) h));
+  *((oop*) h) = NULL;
 }
 
 // Add this metadata pointer to be freed when it's safe.  This is only during
@@ -645,7 +704,6 @@
       p2i(class_loader() != NULL ? class_loader()->klass() : NULL), loader_name());
   if (claimed()) out->print(" claimed ");
   if (is_unloading()) out->print(" unloading ");
-  out->print(" handles " INTPTR_FORMAT, p2i(handles()));
   out->cr();
   if (metaspace_or_null() != NULL) {
     out->print_cr("metaspace: " INTPTR_FORMAT, p2i(metaspace_or_null()));
--- a/src/share/vm/classfile/classLoaderData.hpp	Fri Feb 24 19:48:33 2017 +0100
+++ b/src/share/vm/classfile/classLoaderData.hpp	Mon Feb 27 18:24:19 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,7 +52,6 @@
 
 class ClassLoaderData;
 class JNIMethodBlock;
-class JNIHandleBlock;
 class Metadebug;
 class ModuleEntry;
 class PackageEntry;
@@ -160,6 +159,34 @@
     void oops_do(OopClosure* f);
   };
 
+  class ChunkedHandleList VALUE_OBJ_CLASS_SPEC {
+    struct Chunk : public CHeapObj<mtClass> {
+      static const size_t CAPACITY = 32;
+
+      oop _data[CAPACITY];
+      volatile juint _size;
+      Chunk* _next;
+
+      Chunk(Chunk* c) : _next(c), _size(0) { }
+    };
+
+    Chunk* _head;
+
+    void oops_do_chunk(OopClosure* f, Chunk* c, const juint size);
+
+   public:
+    ChunkedHandleList() : _head(NULL) {}
+    ~ChunkedHandleList();
+
+    // Only one thread at a time can add, guarded by ClassLoaderData::metaspace_lock().
+    // However, multiple threads can execute oops_do concurrently with add.
+    oop* add(oop o);
+#ifdef ASSERT
+    bool contains(oop* p);
+#endif
+    void oops_do(OopClosure* f);
+  };
+
   friend class ClassLoaderDataGraph;
   friend class ClassLoaderDataGraphKlassIteratorAtomic;
   friend class ClassLoaderDataGraphMetaspaceIterator;
@@ -185,8 +212,8 @@
   volatile int _claimed;   // true if claimed, for example during GC traces.
                            // To avoid applying oop closure more than once.
                            // Has to be an int because we cas it.
-  JNIHandleBlock* _handles; // Handles to constant pool arrays, Modules, etc, which
-                            // have the same life cycle of the corresponding ClassLoader.
+  ChunkedHandleList _handles; // Handles to constant pool arrays, Modules, etc, which
+                              // have the same life cycle of the corresponding ClassLoader.
 
   Klass* volatile _klasses;              // The classes defined by the class loader.
   PackageEntryTable* volatile _packages; // The packages defined by the class loader.
@@ -217,9 +244,6 @@
   ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies);
   ~ClassLoaderData();
 
-  JNIHandleBlock* handles() const;
-  void set_handles(JNIHandleBlock* handles);
-
   // GC interface.
   void clear_claimed()          { _claimed = 0; }
   bool claimed() const          { return _claimed == 1; }
@@ -312,7 +336,7 @@
   const char* loader_name();
 
   jobject add_handle(Handle h);
-  void remove_handle(jobject h);
+  void remove_handle_unsafe(jobject h);
   void add_class(Klass* k, bool publicize = true);
   void remove_class(Klass* k);
   bool contains_klass(Klass* k);
--- a/src/share/vm/classfile/moduleEntry.cpp	Fri Feb 24 19:48:33 2017 +0100
+++ b/src/share/vm/classfile/moduleEntry.cpp	Mon Feb 27 18:24:19 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, 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
@@ -87,11 +87,11 @@
 // Set the shared ProtectionDomain atomically
 void ModuleEntry::set_shared_protection_domain(ClassLoaderData *loader_data,
                                                Handle pd_h) {
-  // Create a JNI handle for the shared ProtectionDomain and save it atomically.
-  // If someone beats us setting the _pd cache, the created JNI handle is destroyed.
+  // Create a handle for the shared ProtectionDomain and save it atomically.
+  // If someone beats us setting the _pd cache, the created handle is destroyed.
   jobject obj = loader_data->add_handle(pd_h);
   if (Atomic::cmpxchg_ptr(obj, &_pd, NULL) != NULL) {
-    loader_data->remove_handle(obj);
+    loader_data->remove_handle_unsafe(obj);
   }
 }
 
--- a/src/share/vm/jvmci/vmStructs_jvmci.cpp	Fri Feb 24 19:48:33 2017 +0100
+++ b/src/share/vm/jvmci/vmStructs_jvmci.cpp	Mon Feb 27 18:24:19 2017 +0100
@@ -305,6 +305,7 @@
   static_field(StubRoutines,                _crc32c_table_addr,                               address)                               \
   static_field(StubRoutines,                _updateBytesCRC32C,                               address)                               \
   static_field(StubRoutines,                _updateBytesAdler32,                              address)                               \
+  static_field(StubRoutines,                _multiplyToLen,                                   address)                               \
   static_field(StubRoutines,                _squareToLen,                                     address)                               \
   static_field(StubRoutines,                _mulAdd,                                          address)                               \
   static_field(StubRoutines,                _montgomeryMultiply,                              address)                               \
--- a/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java	Fri Feb 24 19:48:33 2017 +0100
+++ b/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java	Mon Feb 27 18:24:19 2017 +0100
@@ -20,10 +20,19 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
+/**
+ * @test
+ * @modules jdk.aot/jdk.tools.jaotc
+ *          jdk.aot/jdk.tools.jaotc.collect
+ * @run junit/othervm jdk.tools.jaotc.test.collect.ClassSearchTest
+ */
+
 package jdk.tools.jaotc.test.collect;
 
 
 import jdk.tools.jaotc.LoadedClass;
+import jdk.tools.jaotc.collect.*;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -32,45 +41,90 @@
 import java.util.List;
 import java.util.Set;
 import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
 
 public class ClassSearchTest {
     @Test(expected = InternalError.class)
     public void itShouldThrowExceptionIfNoProvidersAvailable() {
         ClassSearch target = new ClassSearch();
         SearchPath searchPath = new SearchPath();
-        target.search(list("foo"), searchPath);
+        target.search(list(new SearchFor("foo")), searchPath);
     }
 
     @Test
     public void itShouldFindAProviderForEachEntry() {
         Set<String> searched = new HashSet<>();
         ClassSearch target = new ClassSearch();
-        target.addProvider(new SourceProvider() {
-            @Override
-            public ClassSource findSource(String name, SearchPath searchPath) {
+        target.addProvider(provider("", (name, searchPath) -> {
                 searched.add(name);
                 return new NoopSource();
+        }));
+        target.search(searchForList("foo", "bar", "foobar"), null);
+        Assert.assertEquals(hashset("foo", "bar", "foobar"), searched);
+    }
+
+    private SourceProvider provider(String supports, BiFunction<String, SearchPath, ClassSource> fn) {
+        return new SourceProvider() {
+            @Override
+            public ClassSource findSource(String name, SearchPath searchPath) {
+                return fn.apply(name, searchPath);
             }
-        });
-        target.search(list("foo", "bar", "foobar"), null);
-        Assert.assertEquals(hashset("foo", "bar", "foobar"), searched);
+
+            @Override
+            public boolean supports(String type) {
+                return supports.equals(type);
+            }
+        };
     }
 
     @Test
-    public void itShouldSearchAllProviders() {
+    public void itShouldOnlySearchSupportedProvidersForKnownType() {
         Set<String> visited = new HashSet<>();
         ClassSearch target = new ClassSearch();
-        target.addProvider((name, searchPath) -> {
+
+        target.addProvider(provider("jar", (name, searchPath) -> {
+            visited.add("jar");
+            return null;
+        }));
+
+        target.addProvider(provider("dir", (name, searchPath) -> {
+            visited.add("dir");
+            return null;
+        }));
+
+        try {
+            target.search(list(new SearchFor("some", "dir")), null);
+        } catch (InternalError e) {
+            // throws because no provider gives a source
+        }
+
+        Assert.assertEquals(hashset("dir"), visited);
+    }
+
+    @Test(expected = InternalError.class)
+    public void itShouldThrowErrorIfMultipleSourcesAreAvailable() {
+        ClassSearch target = new ClassSearch();
+        target.addProvider(provider("", (name, searchPath) -> consumer -> Assert.fail()));
+        target.addProvider(provider("", (name, searchPath) -> consumer -> Assert.fail()));
+
+        target.search(searchForList("somethign"), null);
+    }
+
+    @Test
+    public void itShouldSearchAllProvidersForUnknownType() {
+        Set<String> visited = new HashSet<>();
+        ClassSearch target = new ClassSearch();
+        target.addProvider(provider("", (name, searchPath) -> {
             visited.add("1");
             return null;
-        });
-        target.addProvider((name, searchPath) -> {
+        }));
+        target.addProvider(provider("", (name, searchPath) -> {
             visited.add("2");
             return null;
-        });
+        }));
 
         try {
-            target.search(list("foo"), null);
+            target.search(searchForList("foo"), null);
         } catch (InternalError e) {
             // throws because no provider gives a source
         }
@@ -85,6 +139,11 @@
         ClassSearch target = new ClassSearch();
         target.addProvider(new SourceProvider() {
             @Override
+            public boolean supports(String type) {
+                return true;
+            }
+
+            @Override
             public ClassSource findSource(String name, SearchPath searchPath) {
                 return new ClassSource() {
                     @Override
@@ -101,7 +160,7 @@
             }
         });
 
-        java.util.List<LoadedClass> search = target.search(list("/tmp/something"), null);
+        java.util.List<LoadedClass> search = target.search(searchForList("/tmp/something"), null);
         Assert.assertEquals(list(new LoadedClass("foo.Bar", null)), search);
     }
 
@@ -115,8 +174,16 @@
         };
 
         ClassSearch target = new ClassSearch();
-        target.addProvider((name, searchPath) -> consumer -> consumer.accept("foo.Bar", classLoader));
-        target.search(list("foobar"), null);
+        target.addProvider(provider("", (name, searchPath) -> consumer -> consumer.accept("foo.Bar", classLoader)));
+        target.search(searchForList("foobar"), null);
+    }
+
+    private List<SearchFor> searchForList(String... entries) {
+        List<SearchFor> list = new ArrayList<>();
+        for (String entry : entries) {
+            list.add(new SearchFor(entry));
+        }
+        return list;
     }
 
     private <T> List<T> list(T... entries) {
--- a/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java	Fri Feb 24 19:48:33 2017 +0100
+++ b/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java	Mon Feb 27 18:24:19 2017 +0100
@@ -20,6 +20,14 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
+/**
+ * @test
+ * @modules jdk.aot/jdk.tools.jaotc
+ *          jdk.aot/jdk.tools.jaotc.collect
+ * @run junit/othervm jdk.tools.jaotc.test.collect.ClassSourceTest
+ */
+
 package jdk.tools.jaotc.test.collect;
 
 import org.junit.Assert;
--- a/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java	Fri Feb 24 19:48:33 2017 +0100
+++ b/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java	Mon Feb 27 18:24:19 2017 +0100
@@ -27,6 +27,8 @@
 import java.util.HashSet;
 import java.util.Set;
 
+import jdk.tools.jaotc.collect.FileSupport;
+
 public class FakeFileSupport extends FileSupport {
     private final Set<String> exists = new HashSet<>();
     private final Set<String> directories = new HashSet<>();
--- a/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java	Fri Feb 24 19:48:33 2017 +0100
+++ b/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java	Mon Feb 27 18:24:19 2017 +0100
@@ -22,6 +22,8 @@
  */
 package jdk.tools.jaotc.test.collect;
 
+import jdk.tools.jaotc.collect.SearchPath;
+
 import java.nio.file.FileSystem;
 import java.nio.file.Path;
 import java.nio.file.Paths;
--- a/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java	Fri Feb 24 19:48:33 2017 +0100
+++ b/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java	Mon Feb 27 18:24:19 2017 +0100
@@ -20,6 +20,17 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
+/**
+ * @test
+ * @modules jdk.aot/jdk.tools.jaotc
+ *          jdk.aot/jdk.tools.jaotc.collect
+ *
+ * @build jdk.tools.jaotc.test.collect.Utils
+ * @build jdk.tools.jaotc.test.collect.FakeFileSupport
+ * @run junit/othervm jdk.tools.jaotc.test.collect.SearchPathTest
+ */
+
 package jdk.tools.jaotc.test.collect;
 
 import org.junit.Before;
@@ -30,6 +41,8 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 
+import jdk.tools.jaotc.collect.*;
+
 import static jdk.tools.jaotc.test.collect.Utils.set;
 import static org.junit.Assert.*;
 
--- a/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java	Fri Feb 24 19:48:33 2017 +0100
+++ b/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java	Mon Feb 27 18:24:19 2017 +0100
@@ -21,11 +21,22 @@
  * questions.
  */
 
+/**
+ * @test
+ * @modules jdk.aot/jdk.tools.jaotc
+ *          jdk.aot/jdk.tools.jaotc.collect
+ *          jdk.aot/jdk.tools.jaotc.collect.directory
+ * @compile ../Utils.java
+ * @compile ../FakeFileSupport.java
+ * @run junit/othervm jdk.tools.jaotc.test.collect.directory.DirectorySourceProviderTest
+ */
+
 package jdk.tools.jaotc.test.collect.directory;
 
 import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.directory.DirectorySourceProvider;
 import jdk.tools.jaotc.test.collect.FakeFileSupport;
-import jdk.tools.jaotc.test.collect.FileSupport;
+import jdk.tools.jaotc.collect.FileSupport;
 import org.junit.Assert;
 import org.junit.Test;
 
--- a/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java	Fri Feb 24 19:48:33 2017 +0100
+++ b/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java	Mon Feb 27 18:24:19 2017 +0100
@@ -20,9 +20,23 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
+/**
+ * @test
+ * @modules jdk.aot/jdk.tools.jaotc
+ *          jdk.aot/jdk.tools.jaotc.collect
+ *          jdk.aot/jdk.tools.jaotc.collect.jar
+ * @compile ../Utils.java
+ * @compile ../FakeFileSupport.java
+ * @compile ../FakeSearchPath.java
+ *
+ * @run junit/othervm jdk.tools.jaotc.test.collect.jar.JarSourceProviderTest
+ */
+
 package jdk.tools.jaotc.test.collect.jar;
 
 import jdk.tools.jaotc.collect.ClassSource;
+import jdk.tools.jaotc.collect.jar.JarSourceProvider;
 import jdk.tools.jaotc.test.collect.FakeFileSupport;
 import jdk.tools.jaotc.test.collect.FakeSearchPath;
 import org.junit.Assert;
--- a/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java	Fri Feb 24 19:48:33 2017 +0100
+++ b/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java	Mon Feb 27 18:24:19 2017 +0100
@@ -20,15 +20,31 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
+/**
+ * @test
+ * @modules jdk.aot/jdk.tools.jaotc
+ *          jdk.aot/jdk.tools.jaotc.collect
+ *          jdk.aot/jdk.tools.jaotc.collect.module
+ * @compile ../Utils.java
+ * @run junit/othervm jdk.tools.jaotc.test.collect.module.ModuleSourceProviderTest
+ */
+
 package jdk.tools.jaotc.test.collect.module;
 
-import jdk.tools.jaotc.*;
-import jdk.tools.jaotc.test.collect.FakeSearchPath;
+import jdk.tools.jaotc.collect.FileSupport;
+import jdk.tools.jaotc.collect.module.ModuleSource;
+import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
 import jdk.tools.jaotc.test.collect.Utils;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.io.IOException;
+import java.nio.file.FileSystem;
 import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.function.BiFunction;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
@@ -36,28 +52,42 @@
 public class ModuleSourceProviderTest {
     private ClassLoader classLoader;
     private ModuleSourceProvider target;
+    private FileSupport fileSupport;
+    private BiFunction<Path, Path, Path> getSubDirectory = null;
 
     @Before
     public void setUp() {
         classLoader = new FakeClassLoader();
-        target = new ModuleSourceProvider(FileSystems.getDefault(), classLoader);
+        fileSupport = new FileSupport() {
+
+            @Override
+            public boolean isDirectory(Path path) {
+                return true;
+            }
+
+            @Override
+            public Path getSubDirectory(FileSystem fileSystem, Path root, Path path) throws IOException {
+                if (getSubDirectory == null) {
+                    throw new IOException("Nope");
+                }
+                return getSubDirectory.apply(root, path);
+            }
+        };
+        target = new ModuleSourceProvider(FileSystems.getDefault(), classLoader, fileSupport);
     }
 
     @Test
-    public void itShouldUseSearchPath() {
-        FakeSearchPath searchPath = new FakeSearchPath("blah/java.base");
-        ModuleSource source = (ModuleSource) target.findSource("java.base", searchPath);
-        assertEquals(Utils.set("java.base"), searchPath.entries);
-        assertEquals("blah/java.base", source.getModulePath().toString());
-        assertEquals("module:blah/java.base", source.toString());
-    }
+    public void itShouldUseFileSupport() {
+        getSubDirectory = (root, path) -> {
+            if (root.toString().equals("modules") && path.toString().equals("test.module")) {
+                return Paths.get("modules/test.module");
+            }
+            return null;
+        };
 
-    @Test
-    public void itShouldReturnNullIfSearchPathReturnsNull() {
-        FakeSearchPath searchPath = new FakeSearchPath(null);
-        ModuleSource source = (ModuleSource) target.findSource("jdk.base", searchPath);
-        assertEquals(Utils.set("jdk.base"), searchPath.entries);
-        assertNull(source);
+        ModuleSource source = (ModuleSource) target.findSource("test.module", null);
+        assertEquals("modules/test.module", source.getModulePath().toString());
+        assertEquals("module:modules/test.module", source.toString());
     }
 
     private static class FakeClassLoader extends ClassLoader {