Merge branch 'master' into BETA_JAVA9

Conflicts:
	org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors.jar
diff --git a/org.eclipse.jdt.apt.tests/src/org/eclipse/jdt/apt/tests/TestAll.java b/org.eclipse.jdt.apt.tests/src/org/eclipse/jdt/apt/tests/TestAll.java
index 0487245..8298b12 100644
--- a/org.eclipse.jdt.apt.tests/src/org/eclipse/jdt/apt/tests/TestAll.java
+++ b/org.eclipse.jdt.apt.tests/src/org/eclipse/jdt/apt/tests/TestAll.java
@@ -1,10 +1,14 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2014 BEA Systems, Inc.
+ * Copyright (c) 2005, 2015 BEA Systems, Inc.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *    wharley@bea.com - initial API and implementation
  *    het@google.com - Bug 441790
@@ -24,7 +28,11 @@
  * the name of an annotation processor factory class implemented in this plugin.
  */
 public class TestAll extends TestCase {
-	
+
+	static {
+		System.setProperty("modules", "java.base");
+	}
+
 	public TestAll(String testName) 
 	{
 		super(testName);
diff --git a/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors.jar b/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors.jar
index 8c8a101..e97fd1d 100644
--- a/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors.jar
+++ b/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors.jar
Binary files differ
diff --git a/org.eclipse.jdt.compiler.apt.tests/processors/org/eclipse/jdt/compiler/apt/tests/processors/elements/ElementProc.java b/org.eclipse.jdt.compiler.apt.tests/processors/org/eclipse/jdt/compiler/apt/tests/processors/elements/ElementProc.java
index 8a172e69..7f16660 100644
--- a/org.eclipse.jdt.compiler.apt.tests/processors/org/eclipse/jdt/compiler/apt/tests/processors/elements/ElementProc.java
+++ b/org.eclipse.jdt.compiler.apt.tests/processors/org/eclipse/jdt/compiler/apt/tests/processors/elements/ElementProc.java
@@ -1,10 +1,14 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2012 BEA Systems, Inc. and others
+ * Copyright (c) 2007, 2015 BEA Systems, Inc. and others
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *    wharley@bea.com - initial API and implementation
  *    akurtakov@gmail.com - fix compilation with Java 7
@@ -148,6 +152,9 @@
 		if(!bug300408()) {
 			return false;
 		}
+		if (!examineTypesInPackage()) {
+			return false;
+		}
 		
 		reportSuccess();
 		return false;
@@ -1009,4 +1016,13 @@
 		}
 		return true;
 	}
+	private boolean examineTypesInPackage() {
+		PackageElement pack = _elementUtils.getPackageElement("java.util.concurrent");
+		List<? extends Element> enclosedElements = pack.getEnclosedElements();
+		if (enclosedElements.size() == 0) {
+			reportError("Should find types in package java.util.concurrent");
+			return false;
+		}
+		return true;
+	}
 }
diff --git a/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/FileManagerTests.java b/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/FileManagerTests.java
index f1af4b2..3d5859f 100644
--- a/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/FileManagerTests.java
+++ b/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/FileManagerTests.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *    wharley@bea.com - initial API and implementation
  *    IBM Corporation - fixed a resource leak warning
@@ -24,6 +28,7 @@
 import java.util.Locale;
 import java.util.Set;
 
+import javax.lang.model.SourceVersion;
 import javax.tools.JavaFileManager;
 import javax.tools.JavaFileObject;
 import javax.tools.StandardJavaFileManager;
@@ -166,6 +171,7 @@
 	}
 
 	public void testBug460085() {
+		if (isOnJRE9()) return;
 		try {
 			boolean found = false;
 			EclipseFileManager fileManager = null;
@@ -182,10 +188,17 @@
 			fileManager.close();
 			assertTrue("rt.jar not found", found);
 		} catch (IOException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
+			fail(e.getMessage());
 		} 
 	}
+	private boolean isOnJRE9() {
+		try {
+			SourceVersion.valueOf("RELEASE_9");
+		} catch(IllegalArgumentException iae) {
+			return false;
+		}
+		return true;
+	}
 
 	public void testBug466878_getResource_defaultPackage() throws Exception {
 		EclipseFileManager fileManager = new EclipseFileManager(Locale.getDefault(), Charset.defaultCharset());
diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Archive.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Archive.java
index aad37bb..4f4b2b5 100644
--- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Archive.java
+++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Archive.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -23,6 +27,8 @@
 import java.util.zip.ZipException;
 import java.util.zip.ZipFile;
 
+import org.eclipse.jdt.internal.compiler.apt.util.ArchiveFileObject;
+
 /**
  * Used as a zip file cache.
  */
@@ -33,9 +39,9 @@
 	ZipFile zipFile;
 	File file;
 
-	protected Hashtable<String, ArrayList<String>> packagesCache;
+	protected Hashtable<String, ArrayList<String[]>> packagesCache;
 	
-	private Archive() {
+	protected Archive() {
 		// used to construct UNKNOWN_ARCHIVE
 	}
 
@@ -56,23 +62,23 @@
 			// extract the package name
 			String packageName = fileName.substring(0, last + 1);
 			String typeName = fileName.substring(last + 1);
-			ArrayList<String> types = this.packagesCache.get(packageName);
+			ArrayList<String[]> types = this.packagesCache.get(packageName);
 			if (types == null) {
 				// might be empty if this is a directory entry
 				if (typeName.length() == 0) {
 					continue nextEntry;
 				}
 				types = new ArrayList<>();
-				types.add(typeName);
+				types.add(new String[]{typeName, null});
 				this.packagesCache.put(packageName, types);
 			} else {
-				types.add(typeName);
+				types.add(new String[]{typeName, null});
 			}
 		}
 	}
 	
-	public ArchiveFileObject getArchiveFileObject(String entryName, Charset charset) {
-		return new ArchiveFileObject(this.file, entryName, charset);
+	public ArchiveFileObject getArchiveFileObject(String fileName, String module, Charset charset) {
+		return new ArchiveFileObject(this.file, fileName, charset);
 	}
 	
 	public boolean contains(String entryName) {
@@ -86,13 +92,13 @@
 		return this.packagesCache.keySet();
 	}
 	
-	public List<String> getTypes(String packageName) {
+	public List<String[]> getTypes(String packageName) {
 		// package name is expected to ends with '/'
 		if (this.packagesCache == null) {
 			try {
 				this.zipFile = new ZipFile(this.file);
 			} catch(IOException e) {
-				return Collections.<String>emptyList();
+				return Collections.<String[]>emptyList();
 			}
 			this.initialize();
 		}
diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/ArchiveFileObject.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/ArchiveFileObject.java
index 16ca0b8..27e98ff 100644
--- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/ArchiveFileObject.java
+++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/ArchiveFileObject.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -34,10 +38,10 @@
  * Implementation of a Java file object that corresponds to an entry in a zip/jar file
  */
 public class ArchiveFileObject implements JavaFileObject {
-	private String entryName;
-	private File file;
-	private ZipFile zipFile;
-	private Charset charset;
+	protected String entryName;
+	protected File file;
+	protected ZipFile zipFile;
+	protected Charset charset;
 
 	public ArchiveFileObject(File file, String entryName, Charset charset) {
 		this.entryName = entryName;
@@ -66,16 +70,7 @@
 		if (getKind() != Kind.CLASS) {
 			return null;
 		}
-		ClassFileReader reader = null;
-		try {
-			try (ZipFile zip = new ZipFile(this.file)) {
-				reader = ClassFileReader.read(zip, this.entryName);
-			}
-		} catch (ClassFormatException e) {
-			// ignore
-		} catch (IOException e) {
-			// ignore
-		}
+		ClassFileReader reader = getClassReader();
 
 		if (reader == null) {
 			return null;
@@ -93,6 +88,20 @@
 		return null;
 	}
 
+	protected ClassFileReader getClassReader() {
+		ClassFileReader reader = null;
+		try {
+			try (ZipFile zip = new ZipFile(this.file)) {
+				reader = ClassFileReader.read(zip, this.entryName);
+			}
+		} catch (ClassFormatException e) {
+			// ignore
+		} catch (IOException e) {
+			// ignore
+		}
+		return reader;
+	}
+
 	/* (non-Javadoc)
 	 * @see javax.tools.JavaFileObject#getKind()
 	 */
@@ -118,16 +127,7 @@
 		case SOURCE :
 			return NestingKind.TOP_LEVEL;
 		case CLASS :
-			ClassFileReader reader = null;
-			try {
-				try (ZipFile zip = new ZipFile(this.file)) {
-					reader = ClassFileReader.read(zip, this.entryName);
-				}
-			} catch (ClassFormatException e) {
-				// ignore
-			} catch (IOException e) {
-				// ignore
-			}
+			ClassFileReader reader = getClassReader();
 			if (reader == null) {
 				return null;
 			}
diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java
index b59f8d8..6511b3d 100644
--- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java
+++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -136,24 +140,24 @@
 			if (recurse) {
 				for (String packageName : archive.allPackages()) {
 					if (packageName.startsWith(key)) {
-						List<String> types = archive.getTypes(packageName);
+						List<String[]> types = archive.getTypes(packageName);
 						if (types != null) {
-							for (String typeName : types) {
-								final Kind kind = getKind(getExtension(typeName));
+							for (String[] entry : types) {
+								final Kind kind = getKind(getExtension(entry[0]));
 								if (kinds.contains(kind)) {
-									collector.add(archive.getArchiveFileObject(packageName + typeName, this.charset));
+									collector.add(archive.getArchiveFileObject(packageName + entry[0], entry[1], this.charset));
 								}
 							}
 						}
 					}
 				}
 			} else {
-				List<String> types = archive.getTypes(key);
+				List<String[]> types = archive.getTypes(key);
 				if (types != null) {
-					for (String typeName : types) {
-						final Kind kind = getKind(getExtension(typeName));
+					for (String[] entry : types) {
+						final Kind kind = getKind(getExtension(entry[0]));
 						if (kinds.contains(kind)) {
-							collector.add(archive.getArchiveFileObject(key + typeName, this.charset));
+							collector.add(archive.getArchiveFileObject(key + entry[0], entry[1], this.charset));
 						}
 					}
 				}
@@ -344,7 +348,7 @@
 				Archive archive = getArchive(file);
 				if (archive != Archive.UNKNOWN_ARCHIVE) {
 					if (archive.contains(normalizedFileName)) {
-						return archive.getArchiveFileObject(normalizedFileName, this.charset);
+						return archive.getArchiveFileObject(normalizedFileName, null, this.charset);
 					}
 				}
 			}
@@ -411,7 +415,7 @@
 				Archive archive = getArchive(file);
 				if (archive != Archive.UNKNOWN_ARCHIVE) {
 					if (archive.contains(normalizedFileName)) {
-						return archive.getArchiveFileObject(normalizedFileName, this.charset);
+						return archive.getArchiveFileObject(normalizedFileName, null, this.charset);
 					}
 				}
 			}
diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Jimage.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Jimage.java
new file mode 100644
index 0000000..4c951c7
--- /dev/null
+++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Jimage.java
@@ -0,0 +1,261 @@
+/*******************************************************************************
+ * Copyright (c) 2015 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.apt.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.ZipException;
+
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+
+public class Jimage extends Archive {
+
+	private static URI JRT_URI = URI.create("jrt:/"); //$NON-NLS-1$
+	
+	private static final String BOOT_MODULE = "bootmodules.jimage"; //$NON-NLS-1$
+	
+	private static final String MODULES_SUBDIR = "/modules"; //$NON-NLS-1$
+	
+	private static final String DEFAULT_PACKAGE = ""; //$NON-NLS-1$
+
+	private Set<String> typesCache = null;
+	
+	public Jimage(File file) throws ZipException, IOException {
+		this.file = file;
+		initialize();
+	}
+	
+	private void initialize() throws IOException {
+		// initialize packages
+		this.packagesCache = new Hashtable<>();
+		this.typesCache = new HashSet<>();
+		if (!this.file.getName().equals(BOOT_MODULE)) return;
+		java.nio.file.FileSystem fs = FileSystems.getFileSystem(JRT_URI);
+		Iterable<java.nio.file.Path> roots = fs.getRootDirectories();
+		for (java.nio.file.Path path : roots) {
+			try (DirectoryStream<java.nio.file.Path> stream = Files.newDirectoryStream(path)) {
+				for (final java.nio.file.Path subdir: stream) {
+					if (subdir.toString().equals(MODULES_SUBDIR)) {
+						Files.walkFileTree(subdir, new FileVisitor<java.nio.file.Path>() {
+
+							@Override
+							public FileVisitResult preVisitDirectory(java.nio.file.Path entry, BasicFileAttributes attrs)
+									throws IOException {
+								int count = entry.getNameCount();
+								if (count < 2) return FileVisitResult.CONTINUE;
+								return FileVisitResult.CONTINUE;
+							}
+
+							@Override
+							public FileVisitResult visitFile(java.nio.file.Path entry, BasicFileAttributes attrs) throws IOException {
+								int count = entry.getNameCount();
+								if (entry == subdir || count < 3) return FileVisitResult.CONTINUE;
+								if (count == 3) {
+									cacheTypes(DEFAULT_PACKAGE, entry.getName(2).toString(), entry.getName(1).toString());
+								} else {
+									cacheTypes(entry.subpath(2, count - 1).toString(), 
+										entry.getName(count - 1).toString(), entry.getName(1).toString());
+								}
+								return FileVisitResult.CONTINUE;
+							}
+
+							@Override
+							public FileVisitResult visitFileFailed(java.nio.file.Path entry, IOException exc) throws IOException {
+								return FileVisitResult.CONTINUE;
+							}
+
+							@Override
+							public FileVisitResult postVisitDirectory(java.nio.file.Path entry, IOException exc) throws IOException {
+								return FileVisitResult.CONTINUE;
+							}
+						});
+					}
+				}
+			} catch (Exception e) {
+				throw new IOException(e.getMessage());
+			}
+		}
+	}
+	
+	@Override
+	public ArchiveFileObject getArchiveFileObject(String fileName, String module, Charset charset) {
+		return new JimageFileObject(this.file, fileName, module, charset);
+	}
+	public ArchiveFileObject getArchiveFileObject(String fileName, Charset charset) {
+		return new JimageFileObject(this.file, fileName, null, charset);
+	}
+	
+	@Override
+	public boolean contains(String entryName) {
+		return this.typesCache.contains(entryName);
+	}
+
+	protected void cacheTypes(String packageName, String typeName, String module) {
+		int length = packageName.length();
+		if (length > 0 && packageName.charAt(packageName.length() - 1) != '/') {
+			packageName = packageName + '/'; 
+		}
+		ArrayList<String[]> types = this.packagesCache.get(packageName);
+		if (typeName == null) return;
+		if (types == null) {
+			types = new ArrayList<>();
+			types.add(new String[]{typeName, module});
+			this.packagesCache.put(packageName, types);
+		} else {
+			types.add(new String[]{typeName, module});
+		}
+		this.typesCache.add(packageName + typeName);
+	}
+	@Override
+	public List<String[]> getTypes(String packageName) {
+		// package name is expected to ends with '/'
+		if (this.packagesCache == null) {
+			try {
+				this.initialize();
+			} catch(IOException e) {
+				return Collections.<String[]>emptyList();
+			}
+		}
+		return this.packagesCache.get(packageName);
+	}
+	
+	@Override
+	public String toString() {
+		return "Jimage: " + (this.file == null ? "UNKNOWN_ARCHIVE" : this.file.getAbsolutePath()); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+	
+	class JimageFileObject extends ArchiveFileObject {
+		String module = null;
+		private JimageFileObject(File file, String fileName, String module, Charset charset) {
+			super(file, fileName, charset);
+			this.module = module;
+		}
+
+		@Override
+		protected void finalize() throws Throwable {
+			// Nothing to do here
+		}
+
+		@Override
+		protected ClassFileReader getClassReader() {
+			ClassFileReader reader = null;
+			try {
+				reader = ClassFileReader.readFromJimage(this.file, this.entryName, this.module);
+			} catch (ClassFormatException e) {
+				e.printStackTrace();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+			return reader;
+		}
+		
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#getCharContent(boolean)
+		 */
+		@Override
+		public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+			return Util.getCharContents(this, ignoreEncodingErrors,
+					org.eclipse.jdt.internal.compiler.util.JimageUtil.getClassfileContent(this.file, this.entryName, this.module),
+					this.charset.name());
+		}
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#getLastModified()
+		 */
+		@Override
+		public long getLastModified() {
+			return 0;
+		}
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#getName()
+		 */
+		@Override
+		public String getName() {
+			return this.entryName;
+		}
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#openInputStream()
+		 */
+		@Override
+		public InputStream openInputStream() throws IOException {
+			return org.eclipse.jdt.internal.compiler.util.JimageUtil.getContentFromJimage(this.file, this.entryName, null);
+		}
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#openOutputStream()
+		 */
+		@Override
+		public OutputStream openOutputStream() throws IOException {
+			throw new UnsupportedOperationException();
+		}
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#openReader(boolean)
+		 */
+		@Override
+		public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
+			throw new UnsupportedOperationException();
+		}
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#openWriter()
+		 */
+		@Override
+		public Writer openWriter() throws IOException {
+			throw new UnsupportedOperationException();
+		}
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#toUri()
+		 */
+		@Override
+		public URI toUri() {
+			try {
+				return new URI("jimage:" + this.file.toURI().getPath() + "!" + this.entryName); //$NON-NLS-1$//$NON-NLS-2$
+			} catch (URISyntaxException e) {
+				return null;
+			}
+		}
+
+
+		@Override
+		public String toString() {
+			return this.file.getAbsolutePath() + "[" + this.entryName + "]";//$NON-NLS-1$//$NON-NLS-2$
+		}	
+	}
+}
diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Archive.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Archive.java
index f6094e9..0aefafe 100644
--- a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Archive.java
+++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Archive.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -33,9 +37,9 @@
 	ZipFile zipFile;
 	File file;
 
-	protected Hashtable<String, ArrayList<String>> packagesCache;
+	protected Hashtable<String, ArrayList<String[]>> packagesCache;
 	
-	private Archive() {
+	protected Archive() {
 		// used to construct UNKNOWN_ARCHIVE
 	}
 
@@ -48,7 +52,7 @@
 	private void initialize() {
 		// initialize packages
 		this.packagesCache = new Hashtable<>();
-		nextEntry : for (Enumeration<? extends ZipEntry> e = this.zipFile.entries(); e.hasMoreElements(); ) {
+		for (Enumeration<? extends ZipEntry> e = this.zipFile.entries(); e.hasMoreElements(); ) {
 			String fileName = ((ZipEntry) e.nextElement()).getName();
 
 			// add the package name & all of its parent packages
@@ -56,23 +60,29 @@
 			// extract the package name
 			String packageName = fileName.substring(0, last + 1);
 			String typeName = fileName.substring(last + 1);
-			ArrayList<String> types = this.packagesCache.get(packageName);
-			if (types == null) {
-				// might be empty if this is a directory entry
-				if (typeName.length() == 0) {
-					continue nextEntry;
-				}
-				types = new ArrayList<>();
-				types.add(typeName);
-				this.packagesCache.put(packageName, types);
-			} else {
-				types.add(typeName);
+			// might be empty if this is a directory entry
+			if (typeName.length() == 0) {
+				continue;
 			}
+			cacheTypes(packageName, typeName);
+		}
+	}
+
+	protected void cacheTypes(String packageName, String typeName) {
+		ArrayList<String[]> types = this.packagesCache.get(packageName);
+		if (typeName == null) return;
+		if (types == null) {
+			
+			types = new ArrayList<>();
+			types.add(new String[]{typeName, null});
+			this.packagesCache.put(packageName, types);
+		} else {
+			types.add(new String[]{typeName, null});
 		}
 	}
 	
-	public ArchiveFileObject getArchiveFileObject(String entryName, Charset charset) {
-		return new ArchiveFileObject(this.file, entryName, charset);
+	public ArchiveFileObject getArchiveFileObject(String fileName, String module, Charset charset) {
+		return new ArchiveFileObject(this.file, fileName, charset);
 	}
 	
 	public boolean contains(String entryName) {
@@ -86,13 +96,19 @@
 		return this.packagesCache.keySet();
 	}
 	
-	public List<String> getTypes(String packageName) {
+	/**
+	 * Returns an array of String - the array contains exactly two elements. The first element
+	 * is the name of the type and the second being the module that contains the type. For a regular
+	 * Jar archive, the module element will be null. This is applicable only to Jimage files 
+	 * where types are contained by multiple modules.
+	 */
+	public List<String[]> getTypes(String packageName) {
 		// package name is expected to ends with '/'
 		if (this.packagesCache == null) {
 			try {
 				this.zipFile = new ZipFile(this.file);
 			} catch(IOException e) {
-				return Collections.<String>emptyList();
+				return Collections.<String[]>emptyList();
 			}
 			this.initialize();
 		}
diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/ArchiveFileObject.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/ArchiveFileObject.java
index 73ef27e..7e66e27 100644
--- a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/ArchiveFileObject.java
+++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/ArchiveFileObject.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -34,10 +38,10 @@
  * Implementation of a Java file object that corresponds to an entry in a zip/jar file
  */
 public class ArchiveFileObject implements JavaFileObject {
-	private String entryName;
-	private File file;
+	protected String entryName;
+	protected File file;
 	private ZipFile zipFile;
-	private Charset charset;
+	protected Charset charset;
 
 	public ArchiveFileObject(File file, String entryName, Charset charset) {
 		this.entryName = entryName;
@@ -66,16 +70,7 @@
 		if (getKind() != Kind.CLASS) {
 			return null;
 		}
-		ClassFileReader reader = null;
-		try {
-			try (ZipFile zip = new ZipFile(this.file)) {
-				reader = ClassFileReader.read(zip, this.entryName);
-			}
-		} catch (ClassFormatException e) {
-			// ignore
-		} catch (IOException e) {
-			// ignore
-		}
+		ClassFileReader reader = getClassReader();
 
 		if (reader == null) {
 			return null;
@@ -93,6 +88,19 @@
 		return null;
 	}
 
+	protected ClassFileReader getClassReader() {
+		ClassFileReader reader = null;
+		try {
+			try (ZipFile zip = new ZipFile(this.file)) {
+				reader = ClassFileReader.read(zip, this.entryName);
+			}
+		} catch (ClassFormatException e) {
+			// ignore
+		} catch (IOException e) {
+			// ignore
+		}
+		return reader;
+	}
 	/* (non-Javadoc)
 	 * @see javax.tools.JavaFileObject#getKind()
 	 */
@@ -118,16 +126,7 @@
 		case SOURCE :
 			return NestingKind.TOP_LEVEL;
 		case CLASS :
-			ClassFileReader reader = null;
-			try {
-				try (ZipFile zip = new ZipFile(this.file)) {
-					reader = ClassFileReader.read(zip, this.entryName);
-				}
-			} catch (ClassFormatException e) {
-				// ignore
-			} catch (IOException e) {
-				// ignore
-			}
+			ClassFileReader reader = getClassReader();
 			if (reader == null) {
 				return null;
 			}
diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java
index a5bd770..e3ea5a3 100644
--- a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java
+++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -136,24 +140,24 @@
 			if (recurse) {
 				for (String packageName : archive.allPackages()) {
 					if (packageName.startsWith(key)) {
-						List<String> types = archive.getTypes(packageName);
+						List<String[]> types = archive.getTypes(packageName);
 						if (types != null) {
-							for (String typeName : types) {
-								final Kind kind = getKind(getExtension(typeName));
+							for (String[] entry : types) {
+								final Kind kind = getKind(getExtension(entry[0]));
 								if (kinds.contains(kind)) {
-									collector.add(archive.getArchiveFileObject(packageName + typeName, this.charset));
+									collector.add(archive.getArchiveFileObject(packageName + entry[0], entry[1], this.charset));
 								}
 							}
 						}
 					}
 				}
 			} else {
-				List<String> types = archive.getTypes(key);
+				List<String[]> types = archive.getTypes(key);
 				if (types != null) {
-					for (String typeName : types) {
-						final Kind kind = getKind(getExtension(typeName));
+					for (String[] entry : types) {
+						final Kind kind = getKind(getExtension(entry[0]));
 						if (kinds.contains(kind)) {
-							collector.add(archive.getArchiveFileObject(key + typeName, this.charset));
+							collector.add(archive.getArchiveFileObject(key + entry[0], entry[1], this.charset));
 						}
 					}
 				}
@@ -191,7 +195,11 @@
 			// create a new archive
 			if (f.exists()) {
 				try {
-					archive = new Archive(f);
+					if (isJimage(f)) {
+						archive = new Jimage(f);
+					} else {
+						archive = new Archive(f);
+					}
 				} catch (ZipException e) {
 					// ignore
 				} catch (IOException e) {
@@ -344,7 +352,7 @@
 				Archive archive = getArchive(file);
 				if (archive != Archive.UNKNOWN_ARCHIVE) {
 					if (archive.contains(normalizedFileName)) {
-						return archive.getArchiveFileObject(normalizedFileName, this.charset);
+						return archive.getArchiveFileObject(normalizedFileName, null, this.charset);
 					}
 				}
 			}
@@ -401,7 +409,7 @@
 				Archive archive = getArchive(file);
 				if (archive != Archive.UNKNOWN_ARCHIVE) {
 					if (archive.contains(normalizedFileName)) {
-						return archive.getArchiveFileObject(normalizedFileName, this.charset);
+						return archive.getArchiveFileObject(normalizedFileName, null, this.charset);
 					}
 				}
 			}
@@ -708,7 +716,13 @@
 
 	private boolean isArchive(File f) {
 		String extension = getExtension(f);
-		return extension.equalsIgnoreCase(".jar") || extension.equalsIgnoreCase(".zip");//$NON-NLS-1$//$NON-NLS-2$
+		return extension.equalsIgnoreCase(".jar") || extension.equalsIgnoreCase(".zip") ||  //$NON-NLS-1$ //$NON-NLS-2$
+				extension.equalsIgnoreCase(".jimage");//$NON-NLS-1$
+	}
+	
+	private boolean isJimage(File f) {
+		String extension = getExtension(f);
+		return extension.equalsIgnoreCase(".jimage");//$NON-NLS-1$
 	}
 
 	/* (non-Javadoc)
diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Jimage.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Jimage.java
new file mode 100644
index 0000000..eb7c366
--- /dev/null
+++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Jimage.java
@@ -0,0 +1,262 @@
+/*******************************************************************************
+ * Copyright (c) 2015 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.tool;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.ZipException;
+
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+
+public class Jimage extends Archive {
+
+	private static URI JRT_URI = URI.create("jrt:/"); //$NON-NLS-1$
+	
+	private static final String BOOT_MODULE = "bootmodules.jimage"; //$NON-NLS-1$
+	
+	private static final String MODULES_SUBDIR = "/modules"; //$NON-NLS-1$
+	
+	private static final String DEFAULT_PACKAGE = ""; //$NON-NLS-1$
+
+	private Set<String> typesCache = null;
+	
+	public Jimage(File file) throws ZipException, IOException {
+		this.file = file;
+		initialize();
+	}
+	
+	@SuppressWarnings("resource")
+	private void initialize() throws IOException {
+		// initialize packages
+		this.packagesCache = new Hashtable<>();
+		this.typesCache = new HashSet<>();
+		if (!this.file.getName().equals(BOOT_MODULE)) return;
+		java.nio.file.FileSystem fs = FileSystems.getFileSystem(JRT_URI);
+		Iterable<java.nio.file.Path> roots = fs.getRootDirectories();
+		for (java.nio.file.Path path : roots) {
+			try (DirectoryStream<java.nio.file.Path> stream = Files.newDirectoryStream(path)) {
+				for (final java.nio.file.Path subdir: stream) {
+					if (subdir.toString().equals(MODULES_SUBDIR)) {
+						Files.walkFileTree(subdir, new FileVisitor<java.nio.file.Path>() {
+
+							@Override
+							public FileVisitResult preVisitDirectory(java.nio.file.Path entry, BasicFileAttributes attrs)
+									throws IOException {
+								int count = entry.getNameCount();
+								if (count < 2) return FileVisitResult.CONTINUE;
+								return FileVisitResult.CONTINUE;
+							}
+
+							@Override
+							public FileVisitResult visitFile(java.nio.file.Path entry, BasicFileAttributes attrs) throws IOException {
+								int count = entry.getNameCount();
+								if (entry == subdir || count < 3) return FileVisitResult.CONTINUE;
+								if (count == 3) {
+									cacheTypes(DEFAULT_PACKAGE, entry.getName(2).toString(), entry.getName(1).toString());
+								} else {
+									cacheTypes(entry.subpath(2, count - 1).toString(), 
+										entry.getName(count - 1).toString(), entry.getName(1).toString());
+								}
+								return FileVisitResult.CONTINUE;
+							}
+
+							@Override
+							public FileVisitResult visitFileFailed(java.nio.file.Path entry, IOException exc) throws IOException {
+								return FileVisitResult.CONTINUE;
+							}
+
+							@Override
+							public FileVisitResult postVisitDirectory(java.nio.file.Path entry, IOException exc) throws IOException {
+								return FileVisitResult.CONTINUE;
+							}
+						});
+					}
+				}
+			} catch (Exception e) {
+				throw new IOException(e.getMessage());
+			}
+		}
+	}
+	
+	@Override
+	public ArchiveFileObject getArchiveFileObject(String fileName, String module, Charset charset) {
+		return new JimageFileObject(this.file, fileName, module, charset);
+	}
+	public ArchiveFileObject getArchiveFileObject(String fileName, Charset charset) {
+		return new JimageFileObject(this.file, fileName, null, charset);
+	}
+	
+	@Override
+	public boolean contains(String entryName) {
+		return this.typesCache.contains(entryName);
+	}
+
+	protected void cacheTypes(String packageName, String typeName, String module) {
+		int length = packageName.length();
+		if (length > 0 && packageName.charAt(packageName.length() - 1) != '/') {
+			packageName = packageName + '/'; 
+		}
+		ArrayList<String[]> types = this.packagesCache.get(packageName);
+		if (typeName == null) return;
+		if (types == null) {
+			types = new ArrayList<>();
+			types.add(new String[]{typeName, module});
+			this.packagesCache.put(packageName, types);
+		} else {
+			types.add(new String[]{typeName, module});
+		}
+		this.typesCache.add(packageName + typeName);
+	}
+	@Override
+	public List<String[]> getTypes(String packageName) {
+		// package name is expected to ends with '/'
+		if (this.packagesCache == null) {
+			try {
+				this.initialize();
+			} catch(IOException e) {
+				return Collections.<String[]>emptyList();
+			}
+		}
+		return this.packagesCache.get(packageName);
+	}
+	
+	@Override
+	public String toString() {
+		return "Jimage: " + (this.file == null ? "UNKNOWN_ARCHIVE" : this.file.getAbsolutePath()); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+	
+	class JimageFileObject extends ArchiveFileObject {
+		String module = null;
+		private JimageFileObject(File file, String fileName, String module, Charset charset) {
+			super(file, fileName, charset);
+			this.module = module;
+		}
+
+		@Override
+		protected void finalize() throws Throwable {
+			// Nothing to do here
+		}
+
+		@Override
+		protected ClassFileReader getClassReader() {
+			ClassFileReader reader = null;
+			try {
+				reader = ClassFileReader.readFromJimage(this.file, this.entryName, this.module);
+			} catch (ClassFormatException e) {
+				e.printStackTrace();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+			return reader;
+		}
+		
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#getCharContent(boolean)
+		 */
+		@Override
+		public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+			return Util.getCharContents(this, ignoreEncodingErrors,
+					org.eclipse.jdt.internal.compiler.util.JimageUtil.getClassfileContent(this.file, this.entryName, this.module),
+					this.charset.name());
+		}
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#getLastModified()
+		 */
+		@Override
+		public long getLastModified() {
+			return 0;
+		}
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#getName()
+		 */
+		@Override
+		public String getName() {
+			return this.entryName;
+		}
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#openInputStream()
+		 */
+		@Override
+		public InputStream openInputStream() throws IOException {
+			return org.eclipse.jdt.internal.compiler.util.JimageUtil.getContentFromJimage(this.file, this.entryName, null);
+		}
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#openOutputStream()
+		 */
+		@Override
+		public OutputStream openOutputStream() throws IOException {
+			throw new UnsupportedOperationException();
+		}
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#openReader(boolean)
+		 */
+		@Override
+		public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
+			throw new UnsupportedOperationException();
+		}
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#openWriter()
+		 */
+		@Override
+		public Writer openWriter() throws IOException {
+			throw new UnsupportedOperationException();
+		}
+
+		/* (non-Javadoc)
+		 * @see javax.tools.FileObject#toUri()
+		 */
+		@Override
+		public URI toUri() {
+			try {
+				return new URI("jimage:" + this.file.toURI().getPath() + "!" + this.entryName); //$NON-NLS-1$//$NON-NLS-2$
+			} catch (URISyntaxException e) {
+				return null;
+			}
+		}
+
+
+		@Override
+		public String toString() {
+			return this.file.getAbsolutePath() + "[" + this.entryName + "]";//$NON-NLS-1$//$NON-NLS-2$
+		}	
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
index f3cdee8..89ec45d 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Benjamin Muskalla - Contribution for bug 239066
@@ -8911,7 +8915,7 @@
 // white-box test for internal API
 public void test218_batch_classpath_apis() {
 	assertFalse("path should be absolute",
-		new ClasspathJar(new File("relative.jar"), true, null, null).
+		new ClasspathJar(new File("relative.jar"), true, null, null, false).
 		getPath().indexOf(File.separator) == -1);
 }
 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=214731
@@ -8919,7 +8923,7 @@
 public void test219_batch_classpath_apis() {
 	assertFalse("path should be absolute",
 		CharOperation.indexOf('/',
-			new ClasspathJar(new File("relative.jar"), true, null, null).
+			new ClasspathJar(new File("relative.jar"), true, null, null, false).
 			normalizedPath()) == -1);
 }
 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=210524
@@ -14096,6 +14100,7 @@
 }
 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=419351
 public void testBug419351() {
+	if (isJRE9) return;
 	String backup = System.getProperty("java.endorsed.dirs");
 	String currentWorkingDirectoryPath = System.getProperty("user.dir");
 	if (currentWorkingDirectoryPath == null) {
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
index 0245d89..80f82b4 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java
@@ -4,7 +4,11 @@
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
- * 
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -4414,6 +4418,7 @@
 }
 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=436542 : Eclipse 4.4 compiler generates "bad class file" according to javac
 public void test436542() throws Exception {
+	if (isJRE9) return;
 	String jreDirectory = Util.getJREDirectory();
 	String jfxJar = Util.toNativePath(jreDirectory + "/lib/ext/jfxrt.jar");
 	this.runConformTest(
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
index a0069d6..ef189dd 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at

  * http://www.eclipse.org/legal/epl-v10.html

  *

+ * This is an implementation of an early-draft specification developed under the Java

+ * Community Process (JCP) and is made available for testing and evaluation purposes

+ * only. The code is not compatible with any specification of the JCP.

+ *

  * Contributors:

  *     Stephan Herrmann - initial API and implementation

  *     IBM Corporation

@@ -6779,6 +6783,7 @@
 }

 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=443467, [1.8][null]InternalError: Unexpected binding type

 public void test443467() throws Exception {

+	if (isJRE9) return;

 	String jreDirectory = Util.getJREDirectory();

 	String jfxJar = Util.toNativePath(jreDirectory + "/lib/ext/jfxrt.jar");

 	this.runNegativeTestWithExtraLibs(

diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java
index 4c2fc8e..dda5c6c 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/AbstractCompilerTest.java
@@ -1,10 +1,14 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -45,6 +49,7 @@
 
 	protected long complianceLevel;
 	protected boolean enableAPT = false;
+	protected static boolean isJRE9 = false; // Stop gap, so tests need not be run at 1.9, but some tests can be adjusted for JRE 1.9
 
 	/**
 	 * Build a test suite made of test suites for all possible running VM compliances .
@@ -304,6 +309,8 @@
 	 */
 	public static int getPossibleComplianceLevels() {
 		if (possibleComplianceLevels == UNINITIALIZED) {
+			String specVersion = System.getProperty("java.specification.version");
+			isJRE9 = CompilerOptions.VERSION_1_9.equals(specVersion);
 			String compliance = System.getProperty("compliance");
 			if (compliance != null) {
 				if (CompilerOptions.VERSION_1_3.equals(compliance)) {
@@ -331,7 +338,6 @@
 				}
 			}
 			if (possibleComplianceLevels == UNINITIALIZED) {
-				String specVersion = System.getProperty("java.specification.version");
 				if (!RUN_JAVAC) {
 					possibleComplianceLevels = F_1_3;
 					boolean canRun1_4 = !"1.0".equals(specVersion)
diff --git a/org.eclipse.jdt.core/about.html b/org.eclipse.jdt.core/about.html
index c5eab07..681522d 100644
--- a/org.eclipse.jdt.core/about.html
+++ b/org.eclipse.jdt.core/about.html
@@ -8,7 +8,7 @@
 <body lang="EN-US">
 <h2>About This Content</h2>
  
-<p>March 17, 2011</p>
+<p>April 2, 2015</p>
 <h3>License</h3>
 
 <p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;).  Unless otherwise 
@@ -29,5 +29,10 @@
 use the Disassembler to view the Assembler Mnemonics for a method, you should ensure that doing so will not violate the terms of any licenses that apply to your use of that method, as
 such licenses may not permit you to reverse engineer, decompile, or disassemble method bytecodes.</p>
 
+<h3>Beta Java 9 Support</h3>
+<p>This is an implementation of an early-draft specification developed under the Java
+Community Process (JCP) and is made available for testing and evaluation purposes
+only. The code is not compatible with any specification of the JCP.</p>
+
 </body>
 </html>
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java
index 8d56c0a..a42449c 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -16,11 +20,14 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.FileVisitResult;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
 import java.util.Enumeration;
-import java.util.Hashtable;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
@@ -30,6 +37,7 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationProvider;
 import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
+import org.eclipse.jdt.internal.compiler.util.JimageUtil;
 import org.eclipse.jdt.internal.compiler.util.ManifestAnalyzer;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.compiler.util.Util;
@@ -41,19 +49,22 @@
 protected ZipFile zipFile;
 protected ZipFile annotationZipFile;
 protected boolean closeZipFileAtEnd;
-protected Hashtable packageCache;
+private Set<String> packageCache;
 protected List<String> annotationPaths;
+protected boolean isJimage;
 
 public ClasspathJar(File file, boolean closeZipFileAtEnd,
-		AccessRuleSet accessRuleSet, String destinationPath) {
+		AccessRuleSet accessRuleSet, String destinationPath, boolean jimage) {
 	super(accessRuleSet, destinationPath);
 	this.file = file;
+	this.isJimage = jimage;
 	this.closeZipFileAtEnd = closeZipFileAtEnd;
 }
 
 public List fetchLinkedJars(FileSystem.ClasspathSectionProblemReporter problemReporter) {
 	// expected to be called once only - if multiple calls desired, consider
 	// using a cache
+	if (this.isJimage) return null;
 	InputStream inputStream = null;
 	try {
 		initialize();
@@ -77,7 +88,7 @@
 				int lastSeparator = directoryPath.lastIndexOf(File.separatorChar);
 				directoryPath = directoryPath.substring(0, lastSeparator + 1); // potentially empty (see bug 214731)
 				while (calledFilesIterator.hasNext()) {
-					result.add(new ClasspathJar(new File(directoryPath + (String) calledFilesIterator.next()), this.closeZipFileAtEnd, this.accessRuleSet, this.destinationPath));
+					result.add(new ClasspathJar(new File(directoryPath + (String) calledFilesIterator.next()), this.closeZipFileAtEnd, this.accessRuleSet, this.destinationPath, false));
 				}
 			}
 		}
@@ -102,7 +113,12 @@
 		return null; // most common case
 
 	try {
-		ClassFileReader reader = ClassFileReader.read(this.zipFile, qualifiedBinaryFileName);
+		ClassFileReader reader = null;
+		if (this.isJimage) {
+			reader = ClassFileReader.readFromJimage(this.file, qualifiedBinaryFileName);
+		} else {
+			reader = ClassFileReader.read(this.zipFile, qualifiedBinaryFileName);
+		}
 		if (reader != null) {
 			if (this.annotationPaths != null) {
 				String qualifiedClassName = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length()-SuffixConstants.EXTENSION_CLASS.length()-1);
@@ -127,31 +143,58 @@
 }
 @Override
 public boolean hasAnnotationFileFor(String qualifiedTypeName) {
+	if (this.isJimage) return false; // TODO: Revisit
 	return this.zipFile.getEntry(qualifiedTypeName+'.'+ExternalAnnotationProvider.ANNOTION_FILE_EXTENSION) != null; 
 }
-public char[][][] findTypeNames(String qualifiedPackageName) {
+public char[][][] findTypeNames(final String qualifiedPackageName) {
 	if (!isPackage(qualifiedPackageName))
 		return null; // most common case
+	final char[] packageArray = qualifiedPackageName.toCharArray();
+	final ArrayList answers = new ArrayList();
+	if (this.isJimage) {
+		try {
+			JimageUtil.walkModuleImage(this.file, new JimageUtil.JimageVisitor<java.nio.file.Path>() {
 
-	ArrayList answers = new ArrayList();
-	nextEntry : for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) {
-		String fileName = ((ZipEntry) e.nextElement()).getName();
+				@Override
+				public FileVisitResult visitPackage(java.nio.file.Path dir, java.nio.file.Path mod, BasicFileAttributes attrs) throws IOException {
+					if (qualifiedPackageName.startsWith(dir.toString())) {
+						return FileVisitResult.CONTINUE;	
+					}
+					return FileVisitResult.SKIP_SUBTREE;
+				}
 
-		// add the package name & all of its parent packages
-		int last = fileName.lastIndexOf('/');
-		while (last > 0) {
-			// extract the package name
-			String packageName = fileName.substring(0, last);
-			if (!qualifiedPackageName.equals(packageName))
-				continue nextEntry;
-			int indexOfDot = fileName.lastIndexOf('.');
-			if (indexOfDot != -1) {
-				String typeName = fileName.substring(last + 1, indexOfDot);
-				char[] packageArray = packageName.toCharArray();
-				answers.add(
-					CharOperation.arrayConcat(
-						CharOperation.splitOn('/', packageArray),
-						typeName.toCharArray()));
+				@Override
+				public FileVisitResult visitFile(java.nio.file.Path dir, java.nio.file.Path mod, BasicFileAttributes attrs) throws IOException {
+					if (!dir.getParent().toString().equals(qualifiedPackageName)) {
+						return FileVisitResult.CONTINUE;
+					}
+					String fileName = dir.getName(dir.getNameCount() - 1).toString();
+					// The path already excludes the folders and all the '/', hence the -1 for last index of '/'
+					addTypeName(answers, fileName, -1, packageArray);
+					return FileVisitResult.CONTINUE;
+				}
+
+				@Override
+				public FileVisitResult visitModule(java.nio.file.Path mod) throws IOException {
+					return FileVisitResult.CONTINUE;
+				}
+
+			}, JimageUtil.NOTIFY_ALL);
+		} catch (IOException e) {
+			// Ignore and move on
+		}
+	} else {
+		nextEntry : for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) {
+			String fileName = ((ZipEntry) e.nextElement()).getName();
+
+			// add the package name & all of its parent packages
+			int last = fileName.lastIndexOf('/');
+			if (last > 0) {
+				// extract the package name
+				String packageName = fileName.substring(0, last);
+				if (!qualifiedPackageName.equals(packageName))
+					continue nextEntry;
+				addTypeName(answers, fileName, last, packageArray);
 			}
 		}
 	}
@@ -159,37 +202,75 @@
 	if (size != 0) {
 		char[][][] result = new char[size][][];
 		answers.toArray(result);
-		return null;
+		return result;
 	}
 	return null;
 }
+
+protected void addTypeName(final ArrayList answers, String fileName, int last, char[] packageName) {
+	int indexOfDot = fileName.lastIndexOf('.');
+	if (indexOfDot != -1) {
+		String typeName = fileName.substring(last + 1, indexOfDot);
+		answers.add(
+			CharOperation.arrayConcat(
+				CharOperation.splitOn('/', packageName),
+				typeName.toCharArray()));
+	}
+}
 public void initialize() throws IOException {
-	if (this.zipFile == null) {
+	if (this.zipFile == null && !this.isJimage) {
 		this.zipFile = new ZipFile(this.file);
 	}
 }
-public boolean isPackage(String qualifiedPackageName) {
+
+protected void addToPackageCache(String fileName, boolean endsWithSep) {
+	int last = endsWithSep ? fileName.length() : fileName.lastIndexOf('/');
+	while (last > 0) {
+		// extract the package name
+		String packageName = fileName.substring(0, last);
+		if (this.packageCache.contains(packageName))
+			return;
+		this.packageCache.add(packageName);
+		last = packageName.lastIndexOf('/');
+	}
+}
+public synchronized boolean isPackage(String qualifiedPackageName) {
 	if (this.packageCache != null)
-		return this.packageCache.containsKey(qualifiedPackageName);
+		return this.packageCache.contains(qualifiedPackageName);
 
-	this.packageCache = new Hashtable(41);
-	this.packageCache.put(Util.EMPTY_STRING, Util.EMPTY_STRING);
+	this.packageCache = new HashSet<>(41);
+	this.packageCache.add(Util.EMPTY_STRING);
+	if (this.isJimage) {
+		try {
+			JimageUtil.walkModuleImage(this.file, new JimageUtil.JimageVisitor<java.nio.file.Path>() {
 
-	nextEntry : for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) {
-		String fileName = ((ZipEntry) e.nextElement()).getName();
+				@Override
+				public FileVisitResult visitPackage(java.nio.file.Path dir, java.nio.file.Path mod, BasicFileAttributes attrs) throws IOException {
+					addToPackageCache(dir.toString(), true);
+					return FileVisitResult.CONTINUE;
+				}
 
-		// add the package name & all of its parent packages
-		int last = fileName.lastIndexOf('/');
-		while (last > 0) {
-			// extract the package name
-			String packageName = fileName.substring(0, last);
-			if (this.packageCache.containsKey(packageName))
-				continue nextEntry;
-			this.packageCache.put(packageName, packageName);
-			last = packageName.lastIndexOf('/');
+				@Override
+				public FileVisitResult visitFile(java.nio.file.Path dir, java.nio.file.Path mod, BasicFileAttributes attrs) throws IOException {
+					return FileVisitResult.CONTINUE;
+				}
+
+				@Override
+				public FileVisitResult visitModule(java.nio.file.Path mod) throws IOException {
+					return FileVisitResult.CONTINUE;
+				}
+
+			}, JimageUtil.NOTIFY_PACKAGES);
+		} catch (IOException e) {
+			// Ignore and move on
+		}
+	} else {
+		for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) {
+			String fileName = ((ZipEntry) e.nextElement()).getName();
+			addToPackageCache(fileName, false);
 		}
 	}
-	return this.packageCache.containsKey(qualifiedPackageName);
+	return this.packageCache.contains(qualifiedPackageName);
 }
 public void reset() {
 	if (this.closeZipFileAtEnd) {
@@ -210,7 +291,10 @@
 			this.annotationZipFile = null;
 		}
 	}
-	this.packageCache = null;
+	if (!this.isJimage || this.annotationPaths != null) {
+		this.packageCache = null;
+		this.annotationPaths = null;
+	}
 }
 public String toString() {
 	return "Classpath for jar file " + this.file.getPath(); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathSourceJar.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathSourceJar.java
index fc94aa1..69c479c 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathSourceJar.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathSourceJar.java
@@ -1,10 +1,14 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2010 IBM Corporation and others.
+ * Copyright (c) 2006, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -25,7 +29,7 @@
 	public ClasspathSourceJar(File file, boolean closeZipFileAtEnd,
 			AccessRuleSet accessRuleSet, String encoding,
 			String destinationPath) {
-		super(file, closeZipFileAtEnd, accessRuleSet, destinationPath);
+		super(file, closeZipFileAtEnd, accessRuleSet, destinationPath, false);
 		this.encoding = encoding;
 	}
 
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java
index bcc420b..96446b4 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -15,6 +19,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -113,6 +118,7 @@
 	protected Classpath[] classpaths;
 	Set knownFileNames;
 	protected boolean annotationsFromClasspath; // should annotation files be read from the classpath (vs. explicit separate path)?
+	private static HashMap<File, Classpath> JIMAGES = null;
 
 /*
 	classPathNames is a collection is Strings representing the full path of each class path
@@ -175,7 +181,8 @@
 						convertPathSeparators(destinationPath));
 		}
 	} else {
-		if (Util.isPotentialZipArchive(classpathName)) {
+		int format = Util.archiveFormat(classpathName);
+		if (format > -1) {
 			if (isSourceOnly) {
 				// source only mode
 				result = new ClasspathSourceJar(file, true, accessRuleSet,
@@ -185,7 +192,19 @@
 						convertPathSeparators(destinationPath));
 			} else if (destinationPath == null) {
 				// class file only mode
-				result = new ClasspathJar(file, true, accessRuleSet, null);
+				if (format == Util.JIMAGE_FILE) {
+					if (JIMAGES == null) {
+						JIMAGES = new HashMap<>();
+					} else {
+						result = JIMAGES.get(file);
+					}
+					if (result == null) {
+						result = new ClasspathJar(file, true, accessRuleSet, null, true);
+						JIMAGES.put(file, result);
+					}
+				} else {
+					result = new ClasspathJar(file, true, accessRuleSet, null, false);
+				}
 			}
 		}
 	}
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
index e9f7669..6968ee2 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Tom Tromey - Contribution for bug 125961
@@ -111,6 +115,7 @@
 		private static final String CLASSPATH_FOLDER = "FOLDER"; //$NON-NLS-1$
 		private static final String CLASSPATH_ID = "id"; //$NON-NLS-1$
 		private static final String CLASSPATH_JAR = "JAR"; //$NON-NLS-1$
+		private static final String CLASSPATH_JIMAGE = "JIMAGE"; //$NON-NLS-1$
 		private static final String CLASSPATHS = "classpaths"; //$NON-NLS-1$
 		private static final String COMMAND_LINE_ARGUMENT = "argument"; //$NON-NLS-1$
 		private static final String COMMAND_LINE_ARGUMENTS = "command_line"; //$NON-NLS-1$
@@ -506,10 +511,17 @@
 						File f = new File(classpath);
 						String id = null;
 						if (f.isFile()) {
-							if (Util.isPotentialZipArchive(classpath)) {
-								id = Logger.CLASSPATH_JAR;
-							} else {
-								id = Logger.CLASSPATH_FILE;
+							int kind = Util.archiveFormat(classpath);
+							switch (kind) {
+								case Util.JIMAGE_FILE:
+									id = Logger.CLASSPATH_JIMAGE;
+									break;
+								case Util.ZIP_FILE:
+									id = Logger.CLASSPATH_JAR;
+									break;
+								default:
+									id = Logger.CLASSPATH_FILE;
+									break;
 							}
 						} else if (f.isDirectory()) {
 							id = Logger.CLASSPATH_FOLDER;
@@ -1405,7 +1417,7 @@
 public static File[][] getLibrariesFiles(File[] files) {
 	FilenameFilter filter = new FilenameFilter() {
 		public boolean accept(File dir, String name) {
-			return Util.isPotentialZipArchive(name);
+			return Util.archiveFormat(name) > -1;
 		}
 	};
 	final int filesLength = files.length;
@@ -1561,8 +1573,9 @@
 	if (NONE.equals(destPath)) {
 		destPath = NONE; // keep == comparison valid
 	}
+	
 	if (rejectDestinationPathOnJars && destPath != null &&
-			Util.isPotentialZipArchive(currentClasspathName)) {
+			Util.archiveFormat(currentClasspathName) > -1) {
 		throw new IllegalArgumentException(
 			this.bind("configure.unexpectedDestinationPathEntryFile", //$NON-NLS-1$
 						currentClasspathName));
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
index af42b73..25f27ab 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
@@ -5,6 +5,10 @@
 # which accompanies this distribution, and is available at
 # http://www.eclipse.org/legal/epl-v10.html
 #
+# This is an implementation of an early-draft specification developed under the Java
+# Community Process (JCP) and is made available for testing and evaluation purposes
+# only. The code is not compatible with any specification of the JCP.
+#
 # Contributors:
 #     IBM Corporation - initial API and implementation
 #		Benjamin Muskalla - Contribution for bug 239066
@@ -26,7 +30,7 @@
 #Format: compiler.name = word1 word2 word3
 compiler.name = Eclipse Compiler for Java(TM)
 #Format: compiler.version = (The place holders will be automatically filled. Do not remove or alter it)
-compiler.version = bundle_qualifier, bundle_version
+compiler.version = bundle_qualifier, bundle_version BETA_JAVA9
 compiler.copyright = Copyright IBM Corp 2000, 2015. All rights reserved.
 
 ### progress
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java
index 1bc40eb..3ba422e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java
@@ -1,10 +1,14 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Jesper S Moller - Contributions for
@@ -108,7 +112,7 @@
 	int MAJOR_VERSION_1_6 = 50;
 	int MAJOR_VERSION_1_7 = 51;
 	int MAJOR_VERSION_1_8 = 52;
-	int MAJOR_VERSION_1_9 = 53; // This might change
+	int MAJOR_VERSION_1_9 = 53; // At the moment, runtime don't support this class version.
 
 	int MINOR_VERSION_0 = 0;
 	int MINOR_VERSION_1 = 1;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
index e319e1d..d0024e9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -33,6 +37,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
+import org.eclipse.jdt.internal.compiler.util.JimageUtil;
 import org.eclipse.jdt.internal.compiler.util.Util;
 
 public class ClassFileReader extends ClassFileStruct implements IBinaryType {
@@ -114,6 +119,24 @@
 		return read(zip, filename, false);
 }
 
+public static ClassFileReader readFromJimage(
+		File jimage,
+		String filename)
+		throws ClassFormatException, java.io.IOException {
+
+		return readFromJimage(jimage, filename, null);
+	}
+public static ClassFileReader readFromJimage(
+		File jimage,
+		String filename,
+		String module)
+
+		throws ClassFormatException, java.io.IOException {
+		byte classFileBytes[] = JimageUtil.getClassfileContent(jimage, filename, module);
+		if (classFileBytes == null) return null;
+		return new ClassFileReader(classFileBytes, filename.toCharArray());
+	}
+
 public static ClassFileReader read(
 	java.util.zip.ZipFile zip,
 	String filename,
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
index e66fac3..c8d57d2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Benjamin Muskalla - Contribution for bug 239066
@@ -725,10 +729,6 @@
 				if (jdkLevel == ClassFileConstants.JDK1_8)
 					return VERSION_1_8;
 				break;
-			case ClassFileConstants.MAJOR_VERSION_1_9 :
-				if (jdkLevel == ClassFileConstants.JDK1_9)
-					return VERSION_1_9;
-				break;
 		}
 		return Util.EMPTY_STRING; // unknown version
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java
index b1fde15..fd2762e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java
@@ -1,10 +1,14 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -148,6 +152,8 @@
 		// since 1.7
 		{},
 		// since 1.8
+		{},
+		// since 1.9
 		{}
 	};
 	public static final char[][][] INLINE_TAGS = {
@@ -168,6 +174,8 @@
 		// since 1.7
 		{},
 		// since 1.8
+		{},
+		// since 1.9
 		{}
 	};
 	public final static int INLINE_TAGS_LENGTH = INLINE_TAGS.length;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JimageUtil.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JimageUtil.java
new file mode 100644
index 0000000..4f755d1
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JimageUtil.java
@@ -0,0 +1,327 @@
+/*******************************************************************************
+ * Copyright (c) 2015 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class JimageUtil {
+
+	public static final String JAVA_DOT = "java."; //$NON-NLS-1$
+	public static final String JAVA_BASE = "java.base"; //$NON-NLS-1$
+	static final String MODULES_SUBDIR = "/modules"; //$NON-NLS-1$
+	static final String[] DEFAULT_MODULE = new String[]{JAVA_BASE};
+	static final String[] NO_MODULE = new String[0];
+	static final String MULTIPLE = "MU"; //$NON-NLS-1$
+	static final String DEFAULT_PACKAGE = ""; //$NON-NLS-1$
+	static final String MODULES_ON_DEMAND = System.getProperty("modules"); //$NON-NLS-1$
+	static final String JRT_FS_JAR = "jrt-fs.jar"; //$NON-NLS-1$
+	static URI JRT_URI = URI.create("jrt:/"); //$NON-NLS-1$
+	public static int NOTIFY_FILES = 0x0001;
+	public static int NOTIFY_PACKAGES = 0x0002;
+	public static int NOTIFY_MODULES = 0x0004;
+	public static int NOTIFY_ALL = NOTIFY_FILES | NOTIFY_PACKAGES | NOTIFY_MODULES;
+
+	// TODO: Think about clearing the cache too.
+	private static Map<File, JimageFileSystem> images = null;
+
+	private static final Object lock = new Object();
+
+	public interface JimageVisitor<T> {
+
+		public FileVisitResult visitPackage(T dir, T mod, BasicFileAttributes attrs) throws IOException;
+
+		public FileVisitResult visitFile(T file, T mod, BasicFileAttributes attrs) throws IOException;
+		/**
+		 * Invoked when a root directory of a module being visited. The element returned 
+		 * contains only the module name segment - e.g. "java.base". Clients can use this to control
+		 * how the Jimage needs to be processed, for e.g., clients can skip a particular module
+		 * by returning FileVisitResult.SKIP_SUBTREE
+		 */
+		public FileVisitResult visitModule(T mod) throws IOException;
+	}
+
+	static abstract class AbstractFileVisitor<T> implements FileVisitor<T> {
+		@Override
+		public FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs) throws IOException {
+			return FileVisitResult.CONTINUE;
+		}
+	
+		@Override
+		public FileVisitResult visitFile(T file, BasicFileAttributes attrs) throws IOException {
+			return FileVisitResult.CONTINUE;
+		}
+	
+		@Override
+		public FileVisitResult visitFileFailed(T file, IOException exc) throws IOException {
+			return FileVisitResult.CONTINUE;
+		}
+	
+		@Override
+		public FileVisitResult postVisitDirectory(T dir, IOException exc) throws IOException {
+			return FileVisitResult.CONTINUE;
+		}
+	}
+
+	public static JimageFileSystem getJimageSystem(File image) {
+		Map<File, JimageFileSystem> i = images;
+		if (images == null) {
+			synchronized (lock) {
+	            i = images;
+	            if (i == null) {
+	            	images = i = new HashMap<>();
+	            }
+	        }
+		}
+		JimageFileSystem system = null;
+		synchronized(i) {
+			if ((system = images.get(image)) == null) {
+				try {
+					images.put(image, system = new JimageFileSystem(image));
+				} catch (IOException e) {
+					e.printStackTrace();
+					// Needs better error handling downstream? But for now, make sure 
+					// a dummy JimageFileSystem is not created.
+				}
+			}
+		}
+	    return system;
+	}
+
+	/**
+	 * Given the path of a modular image file, this method walks the archive content and
+	 * notifies the supplied visitor about packages and files visited.
+	 * Note: At the moment, there's no way to open any arbitrary image. Currently,
+	 * this method uses the JRT file system provider to look inside the JRE.
+	 *
+	 * The file system contains the following top level directories:
+	 *  /modules/$MODULE/$PATH
+	 *  /packages/$PACKAGE/$MODULE 
+	 *  The latter provides quick look up of the module that contains a particular package. However,
+	 *  this method only notifies its clients of the entries within the modules sub-directory. The
+	 *  clients can decide which notifications they want to receive. See {@link JimageUtil#NOTIFY_ALL},
+	 *  {@link JimageUtil#NOTIFY_FILES}, {@link JimageUtil#NOTIFY_PACKAGES} and {@link JimageUtil#NOTIFY_MODULES}.
+	 *  
+	 * @param image a java.io.File handle to the JRT image.
+	 * @param visitor an instance of JimageVisitor to be notified of the entries in the JRT image.
+	 * @param notify flag indicating the notifications the client is interested in.
+	 * @throws IOException
+	 */
+	public static void walkModuleImage(File image, final JimageUtil.JimageVisitor<java.nio.file.Path> visitor, int notify) throws IOException {
+		getJimageSystem(image).walkModuleImage(visitor, false, notify);
+	}
+
+	public static InputStream getContentFromJimage(File jimage, String fileName, String module) throws IOException {
+		return getJimageSystem(jimage).getContentFromJimage(fileName, module);
+	}
+
+	public static byte[] getClassfileContent(File jimage, String fileName, String module) throws IOException {
+		return getJimageSystem(jimage).getClassfileContent(fileName, module);
+	}
+}
+class JimageFileSystem {
+	private final Map<String, String> packageToModule = new HashMap<String, String>();
+
+	private final Map<String, List<String>> packageToModules = new HashMap<String, List<String>>();
+
+	FileSystem jrt = null;
+	
+	private final Set<String> notFound = new HashSet<>();
+
+	/**
+	 * As of now, the passed reference to the jimage file is not being used. Perhaps eventually
+	 * when we know how to read a particular jimage, we will make use of this.
+	 *
+	 * @param image
+	 * @throws IOException 
+	 */
+	public JimageFileSystem(File image) throws IOException {
+		initialize(image);
+	}
+	void initialize(File image) throws IOException {
+		String jdkHome = image.getParentFile().getParentFile().getParent();
+		URL url = Paths.get(jdkHome, JimageUtil.JRT_FS_JAR).toUri().toURL();
+		URLClassLoader loader = new URLClassLoader(new URL[] { url });
+		HashMap<String, ?> env = new HashMap<>();
+		this.jrt = FileSystems.newFileSystem(JimageUtil.JRT_URI, env, loader);
+		walkModuleImage(null, true, 0 /* doesn't matter */);
+	}
+
+	public String[] getModules(String fileName) {
+		int idx = fileName.lastIndexOf('/');
+		String pack = null;
+		if (idx != -1) {
+			pack = fileName.substring(0, idx);
+		} else {
+			pack = JimageUtil.DEFAULT_PACKAGE;
+		}
+		String module = this.packageToModule.get(pack);
+		if (module != null) {
+			if (module == JimageUtil.MULTIPLE) {
+				List<String> list = this.packageToModules.get(pack);
+				return list.toArray(new String[list.size()]);
+			} else {
+				return new String[]{module};
+			}
+		}
+		return JimageUtil.DEFAULT_MODULE;
+	}
+
+	public InputStream getContentFromJimage(String fileName, String module) throws IOException {
+		if (module != null) {
+			return Files.newInputStream(this.jrt.getPath(JimageUtil.MODULES_SUBDIR, module, fileName));
+		}
+		String[] modules = getModules(fileName);
+		for (String mod : modules) {
+			return Files.newInputStream(this.jrt.getPath(JimageUtil.MODULES_SUBDIR, mod, fileName));
+		}
+		return null;
+	}
+
+	public byte[] getClassfileContent(String fileName, String module) throws IOException {
+		if (this.notFound.contains(fileName)) 
+			return null;
+		if (module != null) {
+			return Files.readAllBytes(this.jrt.getPath(JimageUtil.MODULES_SUBDIR, module, fileName));
+		}
+		String[] modules = getModules(fileName);
+		for (String string : modules) {
+			try {
+				byte[] bytes = Files.readAllBytes(this.jrt.getPath(JimageUtil.MODULES_SUBDIR, string, fileName));
+				if (bytes != null) return bytes;
+			} catch(NoSuchFileException e) {
+				continue;
+			}
+		}
+		this.notFound.add(fileName);
+		return null;
+	}
+
+	void walkModuleImage(final JimageUtil.JimageVisitor<java.nio.file.Path> visitor, boolean visitPackageMapping, final int notify) throws IOException {
+		Iterable<java.nio.file.Path> roots = this.jrt.getRootDirectories();
+		for (java.nio.file.Path path : roots) {
+			try (DirectoryStream<java.nio.file.Path> stream = Files.newDirectoryStream(path)) {
+				for (final java.nio.file.Path subdir: stream) {
+					if (subdir.toString().equals(JimageUtil.MODULES_SUBDIR)) {
+						if (visitPackageMapping) continue;
+						Files.walkFileTree(subdir, new JimageUtil.AbstractFileVisitor<java.nio.file.Path>() {
+							@Override
+							public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException {
+								int count = dir.getNameCount();
+								if (count == 2) {
+									// e.g. /modules/java.base
+									java.nio.file.Path mod = dir.getName(1);
+									if (!mod.toString().startsWith(JimageUtil.JAVA_DOT) ||
+											(JimageUtil.MODULES_ON_DEMAND != null &&
+											JimageUtil.MODULES_ON_DEMAND.indexOf(mod.toString()) == -1)) {
+										return FileVisitResult.SKIP_SUBTREE;
+									}
+									return ((notify & JimageUtil.NOTIFY_MODULES) == 0) ? 
+											FileVisitResult.CONTINUE : visitor.visitModule(mod);
+								}
+								if (dir == subdir || count < 3 || (notify & JimageUtil.NOTIFY_PACKAGES) == 0) {
+									// We are dealing with a module or not client is not interested in packages
+									return FileVisitResult.CONTINUE;
+								}
+								return visitor.visitPackage(dir.subpath(2, count), dir.getName(1), attrs);
+							}
+
+							@Override
+							public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) throws IOException {
+								if ((notify & JimageUtil.NOTIFY_FILES) == 0)
+									return FileVisitResult.CONTINUE;
+								int count = file.getNameCount();
+								// This happens when a file in a default package is present. E.g. /modules/some.module/file.name
+								if (count == 3) {
+									cachePackage(JimageUtil.DEFAULT_PACKAGE, file.getName(1).toString());
+								}
+								return visitor.visitFile(file.subpath(2, file.getNameCount()), file.getName(1), attrs);
+							}
+						});
+					} else if (visitPackageMapping) {
+						Files.walkFileTree(subdir, new JimageUtil.AbstractFileVisitor<java.nio.file.Path>() {
+							@Override
+							public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) throws IOException {
+								// e.g. /modules/java.base
+								java.nio.file.Path mod = file.getName(file.getNameCount() - 1);
+								if (!mod.toString().startsWith(JimageUtil.JAVA_DOT)) {
+									return FileVisitResult.CONTINUE;
+								}
+								java.nio.file.Path relative = subdir.relativize(file);
+								cachePackage(relative.getParent().toString(), relative.getFileName().toString());
+								return FileVisitResult.CONTINUE;
+							}
+						});
+					}
+			    }
+			} catch (Exception e) {
+				throw new IOException(e.getMessage());
+			}
+		}
+	}
+
+	void cachePackage(String packageName, String module) {
+		packageName = packageName.intern();
+		module = module.intern();
+		packageName = packageName.replace('.', '/');
+		Object current = this.packageToModule.get(packageName);
+		if (current == null) {
+			this.packageToModule.put(packageName, module);
+		} else if(current == module || current.equals(module)) {
+			return;
+		} else if (current == JimageUtil.MULTIPLE) {
+			List<String> list = this.packageToModules.get(packageName);
+			if (!list.contains(module)) {
+				if (JimageUtil.JAVA_BASE == module || JimageUtil.JAVA_BASE.equals(module)) {
+					list.add(0, JimageUtil.JAVA_BASE);
+				} else {
+					list.add(module);
+				}
+			}
+		} else {
+			String first = (String) current;
+			this.packageToModule.put(packageName, JimageUtil.MULTIPLE);
+			List<String> list = new ArrayList<String>();
+			// Just do this as comparator might be overkill
+			if (JimageUtil.JAVA_BASE == current || JimageUtil.JAVA_BASE.equals(current)) {
+				list.add(first);
+				list.add(module);
+			} else {
+				list.add(module);
+				list.add(first);
+			}
+			this.packageToModules.put(packageName, list);
+		}
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/SuffixConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/SuffixConstants.java
index 61b919b..c21d1e1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/SuffixConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/SuffixConstants.java
@@ -1,10 +1,14 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -15,6 +19,8 @@
 	public final static String EXTENSION_CLASS = "CLASS"; //$NON-NLS-1$
 	public final static String EXTENSION_java = "java"; //$NON-NLS-1$
 	public final static String EXTENSION_JAVA = "JAVA"; //$NON-NLS-1$
+	public final static String EXTENSION_jimage = "jimage"; //$NON-NLS-1$
+	public final static String EXTENSION_JIMAGE = "JIMAGE"; //$NON-NLS-1$
 
 	public final static String SUFFIX_STRING_class = "." + EXTENSION_class; //$NON-NLS-1$
 	public final static String SUFFIX_STRING_CLASS = "." + EXTENSION_CLASS; //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java
index 9911a4d..c083afa 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java
@@ -4,6 +4,10 @@
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
@@ -742,6 +746,54 @@
 		}
 		return true; // it is neither a ".java" file nor a ".class" file, so this is a potential archive name
 	}
+	
+	public static final int ZIP_FILE = 0;
+	
+	public static final int JIMAGE_FILE = 1;
+	
+	/**
+	 * Returns whether the given name is potentially a zip archive file name
+	 * (it has a file extension and it is not ".java" nor ".class")
+	 */
+	public final static int archiveFormat(String name) {
+		int lastDot = name.lastIndexOf('.');
+		if (lastDot == -1)
+			return -1; // no file extension, it cannot be a zip archive name
+		if (name.lastIndexOf(File.separatorChar) > lastDot)
+			return -1; // dot was before the last file separator, it cannot be a zip archive name
+		int length = name.length();
+		int extensionLength = length - lastDot - 1;
+		
+		if (extensionLength == EXTENSION_jimage.length()) {
+			for (int i = extensionLength-1; i >=0; i--) {
+				if (Character.toLowerCase(name.charAt(length - extensionLength + i)) != EXTENSION_jimage.charAt(i)) {
+					break;
+				}
+				if (i == 0) {
+					return JIMAGE_FILE;
+				}
+			}
+		}
+		if (extensionLength == EXTENSION_java.length()) {
+			for (int i = extensionLength-1; i >=0; i--) {
+				if (Character.toLowerCase(name.charAt(length - extensionLength + i)) != EXTENSION_java.charAt(i)) {
+					break; // not a ".java" file, check ".class" file case below
+				}
+				if (i == 0) {
+					return -1; // it is a ".java" file, it cannot be a zip archive name
+				}
+			}
+		}
+		if (extensionLength == EXTENSION_class.length()) {
+			for (int i = extensionLength-1; i >=0; i--) {
+				if (Character.toLowerCase(name.charAt(length - extensionLength + i)) != EXTENSION_class.charAt(i)) {
+					return ZIP_FILE; // not a ".class" file, so this is a potential archive name
+				}
+			}
+			return -1; // it is a ".class" file, it cannot be a zip archive name
+		}
+		return ZIP_FILE; // it is neither a ".java" file nor a ".class" file, so this is a potential archive name
+	}
 
 	/**
 	 * Returns true iff str.toLowerCase().endsWith(".class")
@@ -1629,5 +1681,4 @@
 				}
 		}
 	}
-
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java
index 8c882fd..2946d65 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java
@@ -1,10 +1,14 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java
index c1ed588..c9daac2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java
@@ -361,6 +361,15 @@
 	public boolean isArchive();
 
 	/**
+	 * Returns whether this package fragment root represents a Java module
+	 * or not. The module could either be a source or a binary coming from
+	 * the jimage. Note: This needs more work.
+	 *
+	 * @since 3.12 BETA_JAVA9
+	 */
+	public boolean isModule();
+
+	/**
 	 * Returns whether this package fragment root is external
 	 * to the workbench (that is, a local file), and has no
 	 * underlying resource.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
index fa4d46b..c172c9d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     IBM Corporation - added the following constants:
@@ -1813,7 +1817,7 @@
 	 *    should match the compliance setting.</p>
 	 * <dl>
 	 * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.compliance"</code></dd>
-	 * <dt>Possible values:</dt><dd><code>{ "1.3", "1.4", "1.5", "1.6", "1.7", "1.8" }</code></dd>
+	 * <dt>Possible values:</dt><dd><code>{ "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9" }</code></dd>
 	 * <dt>Default:</dt><dd><code>"1.4"</code></dd>
 	 * </dl>
 	 * @since 2.0
@@ -2701,6 +2705,12 @@
 	public static final String VERSION_1_8 = "1.8"; //$NON-NLS-1$
 	/**
 	 * Configurable option value: {@value}.
+	 * @since 3.12 BETA_JAVA9
+	 * @category OptionValue
+	 */
+	public static final String VERSION_1_9 = "1.9"; //$NON-NLS-1$
+	/**
+	 * Configurable option value: {@value}.
 	 * @since 3.4
 	 * @category OptionValue
 	 */
@@ -5652,6 +5662,14 @@
 				options.put(JavaCore.COMPILER_PB_ENUM_IDENTIFIER, JavaCore.ERROR);
 				options.put(JavaCore.COMPILER_CODEGEN_INLINE_JSR_BYTECODE, JavaCore.ENABLED);
 				break;
+			case ClassFileConstants.MAJOR_VERSION_1_9:
+				options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_9);
+				options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_8); //TODO(BETA_JAVA9) at the moment, there's no new Java language feature
+				options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_8); //TODO(BETA_JAVA9) at the moment, runtime doesn't support a new class file version
+				options.put(JavaCore.COMPILER_PB_ASSERT_IDENTIFIER, JavaCore.ERROR);
+				options.put(JavaCore.COMPILER_PB_ENUM_IDENTIFIER, JavaCore.ERROR);
+				options.put(JavaCore.COMPILER_CODEGEN_INLINE_JSR_BYTECODE, JavaCore.ENABLED);
+				break;
 		}
 	}
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
index 78cf856..16ce305 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -14,6 +18,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
@@ -322,15 +327,11 @@
 	JavaElement pkg = (JavaElement) getParent();
 	if (pkg instanceof JarPackageFragment) {
 		JarPackageFragmentRoot root = (JarPackageFragmentRoot) pkg.getParent();
-		ZipFile zip = null;
 		try {
-			zip = root.getJar();
 			String entryName = Util.concatWith(((PackageFragment) pkg).names, getElementName(), '/');
-			ZipEntry ze = zip.getEntry(entryName);
-			if (ze != null) {
-				return org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(ze, zip);
-			}
-			throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
+			return getClassFileContent(root, entryName);
+			// BETA_JAVA9 - The below exception is not thrown in new scheme of things. Could cause issues?
+//			throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
 		} catch (IOException ioe) {
 			throw new JavaModelException(ioe, IJavaModelStatusConstants.IO_EXCEPTION);
 		} catch (CoreException e) {
@@ -339,25 +340,46 @@
 			} else {
 				throw new JavaModelException(e);
 			}
-		} finally {
-			JavaModelManager.getJavaModelManager().closeZipFile(zip);
 		}
 	} else {
 		IFile file = (IFile) resource();
 		return Util.getResourceContentsAsByteArray(file);
 	}
 }
+private byte[] getClassFileContent(JarPackageFragmentRoot root, String className) throws CoreException, IOException {
+	byte[] contents = null;
+	if (root.isModule()) {
+			contents = org.eclipse.jdt.internal.compiler.util.JimageUtil.getClassfileContent(
+					new File(root.getPath().toOSString()),
+					className,
+					root.getElementName());
+	} else {
+		ZipFile zip = root.getJar();
+		try {
+			ZipEntry ze = zip.getEntry(className);
+			if (ze != null) {
+				contents = org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(ze, zip);
+			}
+		} finally {
+			JavaModelManager.getJavaModelManager().closeZipFile(zip);
+		}
+	}
+	return contents;
+}
 private IBinaryType getJarBinaryTypeInfo(PackageFragment pkg, boolean fullyInitialize) throws CoreException, IOException, ClassFormatException {
 	JarPackageFragmentRoot root = (JarPackageFragmentRoot) pkg.getParent();
-	ZipFile zip = null;
 	ZipFile annotationZip = null;
 	try {
-		zip = root.getJar();
 		String entryName = Util.concatWith(pkg.names, getElementName(), '/');
-		ZipEntry ze = zip.getEntry(entryName);
-		if (ze != null) {
-			byte contents[] = org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(ze, zip);
-			String fileName = root.getHandleIdentifier() + IDependent.JAR_FILE_ENTRY_SEPARATOR + entryName;
+		byte[] contents = getClassFileContent(root, entryName);
+		if (contents != null) {
+			String fileName;
+			if (root.isModule()) {
+				fileName = root.getHandleIdentifier() + IDependent.JAR_FILE_ENTRY_SEPARATOR + 
+						root.getElementName() + IDependent.JAR_FILE_ENTRY_SEPARATOR + entryName;
+			} else {
+				fileName = root.getHandleIdentifier() + IDependent.JAR_FILE_ENTRY_SEPARATOR + entryName;
+			}
 			ClassFileReader reader = new ClassFileReader(contents, fileName.toCharArray(), fullyInitialize);
 			if (root.getKind() == IPackageFragmentRoot.K_BINARY) {
 				JavaProject javaProject = (JavaProject) getAncestor(IJavaElement.JAVA_PROJECT);
@@ -373,7 +395,6 @@
 			return reader;
 		}
 	} finally {
-		JavaModelManager.getJavaModelManager().closeZipFile(zip);
 		JavaModelManager.getJavaModelManager().closeZipFile(annotationZip);
 	}
 	return null;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryDirectory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryDirectory.java
index cb04892..de0657c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryDirectory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryDirectory.java
@@ -1,10 +1,14 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java
index 21af1eb..a56a0bf 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java
@@ -1,16 +1,21 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
 import java.io.ByteArrayInputStream;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.zip.ZipEntry;
@@ -18,9 +23,12 @@
 
 import org.eclipse.core.resources.IStorage;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
 import org.eclipse.jdt.core.IJarEntryResource;
 import org.eclipse.jdt.core.IJavaModelStatusConstants;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.compiler.util.JimageUtil;
 import org.eclipse.jdt.internal.compiler.util.Util;
 
 /**
@@ -30,7 +38,6 @@
  */
 public class JarEntryFile  extends JarEntryResource {
 	private static final IJarEntryResource[] NO_CHILDREN = new IJarEntryResource[0];
-
 	public JarEntryFile(String simpleName) {
 		super(simpleName);
 	}
@@ -42,24 +49,38 @@
 	}
 
 	public InputStream getContents() throws CoreException {
-		ZipFile zipFile = null;
-		try {
-			zipFile = getZipFile();
-			if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
-				System.out.println("(" + Thread.currentThread() + ") [JarEntryFile.getContents()] Creating ZipFile on " +zipFile.getName()); //$NON-NLS-1$	//$NON-NLS-2$
+		IPackageFragmentRoot root = getPackageFragmentRoot();
+		if (root.isModule()) {
+			try {
+				IPath rootPath = root.getPath();
+				Object target = JavaModel.getTarget(rootPath, false);
+				if (target != null && target instanceof File) {
+					return JimageUtil.getContentFromJimage((File) target, getEntryName(), root.getElementName());
+				}
+			} catch (IOException e) {
+				throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
 			}
-			String entryName = getEntryName();
-			ZipEntry zipEntry = zipFile.getEntry(entryName);
-			if (zipEntry == null){
-				throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, entryName));
+			return null;
+		} else {
+			ZipFile zipFile = null;
+			try {
+				zipFile = getZipFile();
+				if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
+					System.out.println("(" + Thread.currentThread() + ") [JarEntryFile.getContents()] Creating ZipFile on " +zipFile.getName()); //$NON-NLS-1$	//$NON-NLS-2$
+				}
+				String entryName = getEntryName();
+				ZipEntry zipEntry = zipFile.getEntry(entryName);
+				if (zipEntry == null){
+					throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, entryName));
+				}
+				byte[] contents = Util.getZipEntryByteContent(zipEntry, zipFile);
+				return new ByteArrayInputStream(contents);
+			} catch (IOException e){
+				throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+			} finally {
+				// avoid leaking ZipFiles
+				JavaModelManager.getJavaModelManager().closeZipFile(zipFile);
 			}
-			byte[] contents = Util.getZipEntryByteContent(zipEntry, zipFile);
-			return new ByteArrayInputStream(contents);
-		} catch (IOException e){
-			throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
-		} finally {
-			// avoid leaking ZipFiles
-			JavaModelManager.getJavaModelManager().closeZipFile(zipFile);
 		}
 	}
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryResource.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryResource.java
index 57a2775..50773f6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryResource.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryResource.java
@@ -1,10 +1,14 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java
index 78a66b4..220e968 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java
@@ -1,17 +1,22 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
 import java.net.URL;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipException;
 import java.util.zip.ZipFile;
@@ -39,7 +44,7 @@
 @SuppressWarnings({"rawtypes", "unchecked"})
 public class JarPackageFragmentRoot extends PackageFragmentRoot {
 
-	private final static ArrayList EMPTY_LIST = new ArrayList();
+	protected final static ArrayList EMPTY_LIST = new ArrayList();
 
 	/**
 	 * The path to the jar file
@@ -72,23 +77,22 @@
 	 * by the path of class files contained in the jar of this package fragment root.
 	 */
 	protected boolean computeChildren(OpenableElementInfo info, IResource underlyingResource) throws JavaModelException {
-		HashtableOfArrayToObject rawPackageInfo = new HashtableOfArrayToObject();
+		final HashtableOfArrayToObject rawPackageInfo = new HashtableOfArrayToObject();
 		IJavaElement[] children;
 		ZipFile jar = null;
 		try {
 			Object file = JavaModel.getTarget(getPath(), true);
 			long level = Util.getJdkLevel(file);
-			String compliance = CompilerOptions.versionFromJdkLevel(level);
-			jar = getJar();
+			final String compliance = CompilerOptions.versionFromJdkLevel(level);
 
 			// always create the default package
 			rawPackageInfo.put(CharOperation.NO_STRINGS, new ArrayList[] { EMPTY_LIST, EMPTY_LIST });
 
+			jar = getJar();
 			for (Enumeration e= jar.entries(); e.hasMoreElements();) {
 				ZipEntry member= (ZipEntry) e.nextElement();
 				initRawPackageInfo(rawPackageInfo, member.getName(), member.isDirectory(), compliance);
 			}
-
 			// loop through all of referenced packages, creating package fragments if necessary
 			// and cache the entry names in the rawPackageInfo table
 			children = new IJavaElement[rawPackageInfo.size()];
@@ -116,6 +120,19 @@
 		((JarPackageFragmentRootInfo) info).rawPackageInfo = rawPackageInfo;
 		return true;
 	}
+	protected IJavaElement[] createChildren(final HashtableOfArrayToObject rawPackageInfo) {
+		IJavaElement[] children;
+		// loop through all of referenced packages, creating package fragments if necessary
+		// and cache the entry names in the rawPackageInfo table
+		children = new IJavaElement[rawPackageInfo.size()];
+		int index = 0;
+		for (int i = 0, length = rawPackageInfo.keyTable.length; i < length; i++) {
+			String[] pkgName = (String[]) rawPackageInfo.keyTable[i];
+			if (pkgName == null) continue;
+			children[index++] = getPackageFragment(pkgName);
+		}
+		return children;
+	}
 	/**
 	 * Returns a new element info for this element.
 	 */
@@ -183,6 +200,9 @@
 	public PackageFragment getPackageFragment(String[] pkgName) {
 		return new JarPackageFragment(this, pkgName);
 	}
+	public PackageFragment getPackageFragment(String[] pkgName, String mod) {
+		return new JarPackageFragment(this, pkgName); // Overridden in JImageModuleFragmentBridge
+	}
 	public IPath internalPath() {
 		if (isExternal()) {
 			return this.jarPath;
@@ -213,8 +233,10 @@
 	public int hashCode() {
 		return this.jarPath.hashCode();
 	}
-	private void initRawPackageInfo(HashtableOfArrayToObject rawPackageInfo, String entryName, boolean isDirectory, String compliance) {
-		int lastSeparator = isDirectory ? entryName.length()-1 : entryName.lastIndexOf('/');
+	protected void initRawPackageInfo(HashtableOfArrayToObject rawPackageInfo, String entryName, boolean isDirectory, String compliance) {
+		if (entryName.length() == 0) return;
+		int lastSeparator = isDirectory ? (entryName.charAt(entryName.length() - 1) == '/' ? 
+						entryName.length()-1 : entryName.length() ) : entryName.lastIndexOf('/');
 		String[] pkgName = Util.splitOn('/', entryName, 0, lastSeparator);
 		String[] existing = null;
 		int length = pkgName.length;
@@ -274,7 +296,6 @@
 	public boolean isReadOnly() {
 		return true;
 	}
-
 	/**
 	 * Returns whether the corresponding resource or associated file exists
 	 */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java
index 8e8a746..8f50572 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -361,6 +361,10 @@
 	return false;
 }
 
+public static boolean isJimage(File file) {
+	return JavaModelManager.isJimage(file.getPath());
+}
+
 /**
  * Returns whether the provided path is an external file, checking and updating the
  * JavaModelManager's external file cache.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
index e03896a..5f430bf 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Theodora Yeung (tyeung@bea.com) - ensure that JarPackageFragmentRoot make it into cache
@@ -55,6 +59,7 @@
 import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
+import org.eclipse.jdt.internal.compiler.util.ObjectVector;
 import org.eclipse.jdt.internal.core.JavaProjectElementInfo.ProjectCache;
 import org.eclipse.jdt.internal.core.builder.JavaBuilder;
 import org.eclipse.jdt.internal.core.dom.SourceRangeVerifier;
@@ -240,6 +245,8 @@
 	 */
 	public static final String MAX_COMPILED_UNITS_AT_ONCE = "maxCompiledUnitsAtOnce"; //$NON-NLS-1$
 
+	public static final String JIMAGE_EXT = "jimage"; //$NON-NLS-1$
+
 	/**
 	 * Special value used for recognizing ongoing initialization and breaking initialization cycles
 	 */
@@ -1147,6 +1154,7 @@
 		public Map rootPathToRawEntries; // reverse map from a package fragment root's path to the raw entry
 		public Map rootPathToResolvedEntries; // map from a package fragment root's path to the resolved entry
 		public IPath outputLocation;
+		public Map<IPath, ObjectVector> jimageRoots; // A map between a Jimage classpath entry (as a string) and the package fragment roots found in it.
 
 		public IEclipsePreferences preferences;
 		public Hashtable options;
@@ -1256,6 +1264,11 @@
 			return setClasspath(this.rawClasspath, referencedEntries, this.outputLocation, this.rawClasspathStatus, newResolvedClasspath, newRootPathToRawEntries, newRootPathToResolvedEntries, newUnresolvedEntryStatus, addClasspathChange);
 		}
 
+		public synchronized void setJimagePackageRoots(IPath jimagePath, ObjectVector roots) {
+			if (this.jimageRoots == null) this.jimageRoots = new HashMap<>();
+			this.jimageRoots.put(jimagePath, roots);
+		}
+
 		/**
 		 * Reads the classpath and caches the entries. Returns a two-dimensional array, where the number of elements in the row is fixed to 2.
 		 * The first element is an array of raw classpath entries and the second element is an array of referenced entries that may have been stored
@@ -1438,6 +1451,7 @@
 	public static boolean CP_RESOLVE_VERBOSE_ADVANCED = false;
 	public static boolean CP_RESOLVE_VERBOSE_FAILURE = false;
 	public static boolean ZIP_ACCESS_VERBOSE = false;
+	public static boolean JIMAGE_ACCESS_VERBOSE = false;
 	
 	/**
 	 * A cache of opened zip files per thread.
@@ -2621,7 +2635,22 @@
 		return this.workspaceScope;
 	}
 
+	public static boolean isJimage(IPath path) {
+		if (path.getFileExtension() != null && path.getFileExtension().equalsIgnoreCase(JIMAGE_EXT)) {
+			return true;
+		}
+		return false;
+	}
+
+	public static boolean isJimage(String path) {
+		return isJimage(new Path(path));
+	}
+
 	public void verifyArchiveContent(IPath path) throws CoreException {
+		// TODO: We don't yet know how to open a jimage file given its path. So, simply don't attempt.
+		if (isJimage(path)) {
+			return;
+		}
 		if (isInvalidArchive(path)) {
 			throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.status_IOException, new ZipException()));			
 		}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
index 13cfffb..41e868f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for
@@ -15,6 +19,8 @@
 
 import java.io.*;
 import java.net.URI;
+import java.nio.file.FileVisitResult;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -69,6 +75,7 @@
 import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.eval.IEvaluationContext;
+import org.eclipse.jdt.internal.compiler.util.JimageUtil;
 import org.eclipse.jdt.internal.compiler.util.ObjectVector;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.JavaModelManager.PerProjectInfo;
@@ -616,7 +623,20 @@
 				} else if (target instanceof File) {
 					// external target
 					if (JavaModel.isFile(target)) {
-						root = new JarPackageFragmentRoot(entryPath, this);
+						if (JavaModel.isJimage((File) target)) {
+							PerProjectInfo info = getPerProjectInfo();
+							if (info.jimageRoots == null || !info.jimageRoots.containsKey(entryPath)) {
+								ObjectVector imageRoots = new ObjectVector();
+								loadModulesInJimage(entryPath, imageRoots, rootToResolvedEntries, resolvedEntry, referringEntry);
+								info.setJimagePackageRoots(entryPath, imageRoots);
+								accumulatedRoots.addAll(imageRoots);
+								rootIDs.add(rootID);
+							} else {
+								accumulatedRoots.addAll(info.jimageRoots.get(entryPath));
+							}
+						} else {
+							root = new JarPackageFragmentRoot(entryPath, this);
+						}
 					} else if (((File) target).isDirectory()) {
 						root = new ExternalPackageFragmentRoot(entryPath, this);
 					}
@@ -654,6 +674,63 @@
 	}
 
 	/**
+	 * This bogus package fragment root acts as placeholder plus bridge for the
+	 * real one until the module name becomes available. It is useful in certain
+	 * scenarios like creating package roots from delta processors, search etc.
+	 */
+	class JImageModuleFragmentBridge extends JarPackageFragmentRoot {
+
+		protected JImageModuleFragmentBridge(IPath externalJarPath) {
+			super(externalJarPath, JavaProject.this);
+		}
+		public PackageFragment getPackageFragment(String[] pkgName) {
+			return getPackageFragment(pkgName, null);
+		}
+		public PackageFragment getPackageFragment(String[] pkgName, String mod) {
+			PackageFragmentRoot realRoot = new ModulePackageFragmentRoot(this.jarPath,
+												mod == null ?  JimageUtil.JAVA_BASE : mod,
+														JavaProject.this);
+			return new JarPackageFragment(realRoot, pkgName);
+		}
+		protected boolean computeChildren(OpenableElementInfo info, IResource underlyingResource) throws JavaModelException {
+			// Do nothing, idea is to avoid this being read in JarPackageFragmentRoot as a Jar.
+			return true;
+		}
+		public boolean isModule() {
+			return true;
+		}
+	}
+
+	private void loadModulesInJimage(final IPath imagePath, final ObjectVector roots, final Map rootToResolvedEntries, 
+				final IClasspathEntry resolvedEntry, final IClasspathEntry referringEntry) {
+		try {
+			org.eclipse.jdt.internal.compiler.util.JimageUtil.walkModuleImage(imagePath.toFile(),
+					new org.eclipse.jdt.internal.compiler.util.JimageUtil.JimageVisitor<java.nio.file.Path>() {
+				@Override
+				public FileVisitResult visitPackage(java.nio.file.Path dir, java.nio.file.Path mod, BasicFileAttributes attrs) throws IOException {
+					return FileVisitResult.SKIP_SIBLINGS;
+				}
+
+				@Override
+				public FileVisitResult visitFile(java.nio.file.Path path, java.nio.file.Path mod, BasicFileAttributes attrs) throws IOException {
+					return FileVisitResult.SKIP_SIBLINGS;
+				}
+
+				@Override
+				public FileVisitResult visitModule(java.nio.file.Path mod) throws IOException {
+					ModulePackageFragmentRoot root = new ModulePackageFragmentRoot(imagePath, mod.toString(), JavaProject.this);
+					roots.add(root);
+					if (rootToResolvedEntries != null) 
+						rootToResolvedEntries.put(root, ((ClasspathEntry)resolvedEntry).combineWith((ClasspathEntry) referringEntry));
+					return FileVisitResult.SKIP_SUBTREE;
+				}
+			}, JimageUtil.NOTIFY_MODULES);
+		} catch (IOException e) {
+			Util.log(IStatus.ERROR, "Error reading modules from " + imagePath.toOSString()); //$NON-NLS-1$
+		}
+	}
+
+	/**
 	 * Returns (local/all) the package fragment roots identified by the given project's classpath.
 	 * Note: this follows project classpath references to find required project contributions,
 	 * eliminating duplicates silently.
@@ -1231,7 +1308,7 @@
 		}
 		for (int i= 0; i < allRoots.length; i++) {
 			IPackageFragmentRoot classpathRoot= allRoots[i];
-			if (classpathRoot.getPath().equals(path)) {
+			if (classpathRoot.getPath() != null && classpathRoot.getPath().equals(path)) {
 				return classpathRoot;
 			}
 		}
@@ -1588,6 +1665,7 @@
 	 * @see JavaElement
 	 */
 	public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) {
+		String mod = null;
 		switch (token.charAt(0)) {
 			case JEM_PACKAGEFRAGMENTROOT:
 				String rootPath = IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH;
@@ -1597,11 +1675,22 @@
 					// https://bugs.eclipse.org/bugs/show_bug.cgi?id=331821
 					if (token == MementoTokenizer.PACKAGEFRAGMENT || token == MementoTokenizer.COUNT) {
 						break;
+					} else if (token == MementoTokenizer.PACKAGEFRAGMENTROOT) {
+						if (memento.hasMoreTokens()) {
+							token = memento.nextToken();
+							if (token != null) {
+								mod = token;
+							
+							}
+						}
+						continue;
 					}
 					rootPath += token;
 				}
-				JavaElement root = (JavaElement)getPackageFragmentRoot(new Path(rootPath));
-				if (token != null && token.charAt(0) == JEM_PACKAGEFRAGMENT) {
+				JavaElement root = (mod == null) ?
+						(JavaElement)getPackageFragmentRoot(new Path(rootPath)) :
+							new ModulePackageFragmentRoot(new Path(rootPath), mod, this);
+				if (token != null && (token.charAt(0) == JEM_PACKAGEFRAGMENT)) {
 					return root.getHandleFromMemento(token, memento, owner);
 				} else {
 					return root.getHandleFromMemento(memento, owner);
@@ -1833,6 +1922,9 @@
 		IFolder linkedFolder = JavaModelManager.getExternalManager().getFolder(externalLibraryPath);
 		if (linkedFolder != null)
 			return new ExternalPackageFragmentRoot(linkedFolder, externalLibraryPath, this);
+		if (JavaModelManager.isJimage(externalLibraryPath)) {
+			return this.new JImageModuleFragmentBridge(externalLibraryPath);
+		}
 		return new JarPackageFragmentRoot(externalLibraryPath, this);
 	}
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModulePackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModulePackageFragmentRoot.java
new file mode 100644
index 0000000..6c8d23a
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModulePackageFragmentRoot.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2015 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.util.JimageUtil;
+import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject;
+import org.eclipse.jdt.internal.core.util.Util;
+
+/**
+ * A package fragment root that corresponds to a .jimage
+ *
+ * @see org.eclipse.jdt.core.IPackageFragmentRoot
+ * @see org.eclipse.jdt.internal.core.JarPackageFragmentRootInfo
+ */
+public class ModulePackageFragmentRoot extends JarPackageFragmentRoot {
+
+	String moduleName;
+	
+	/**
+	 * Constructs a package fragment root which represents a module
+	 * contained in a Jimage.
+	 */
+	protected ModulePackageFragmentRoot(IPath jimagePath, String moduleName, JavaProject project) {
+		super(jimagePath, project);
+		this.moduleName = moduleName;
+	}
+
+	protected boolean computeChildren(OpenableElementInfo info, IResource underlyingResource) throws JavaModelException {
+		final HashtableOfArrayToObject rawPackageInfo = new HashtableOfArrayToObject();
+		final String compliance = CompilerOptions.VERSION_1_8; // TODO: Revisit
+
+		// always create the default package
+		rawPackageInfo.put(CharOperation.NO_STRINGS, new ArrayList[] { EMPTY_LIST, EMPTY_LIST });
+
+		try {
+			org.eclipse.jdt.internal.compiler.util.JimageUtil.walkModuleImage(this.jarPath.toFile(),
+					new org.eclipse.jdt.internal.compiler.util.JimageUtil.JimageVisitor<Path>() {
+				@Override
+				public FileVisitResult visitPackage(Path dir, Path mod, BasicFileAttributes attrs) throws IOException {
+					initRawPackageInfo(rawPackageInfo, dir.toString(), true, compliance);
+					return FileVisitResult.CONTINUE;
+				}
+
+				@Override
+				public FileVisitResult visitFile(Path path, Path mod, BasicFileAttributes attrs) throws IOException {
+					initRawPackageInfo(rawPackageInfo, path.toString(), false, compliance);
+					return FileVisitResult.CONTINUE;
+				}
+
+				@Override
+				public FileVisitResult visitModule(Path mod) throws IOException {
+					if (!ModulePackageFragmentRoot.this.moduleName.equals(mod.toString())) {
+						return FileVisitResult.SKIP_SUBTREE;
+					}
+					return FileVisitResult.CONTINUE;
+				}
+			}, JimageUtil.NOTIFY_ALL);
+		} catch (IOException e) {
+			Util.log(IStatus.ERROR, "Error reading modules" + toStringWithAncestors()); //$NON-NLS-1$
+		}
+
+		info.setChildren(createChildren(rawPackageInfo));
+		((JarPackageFragmentRootInfo) info).rawPackageInfo = rawPackageInfo;
+		return true;
+	}
+	public boolean equals(Object o) {
+		if (this == o)
+			return true;
+		if (o instanceof ModulePackageFragmentRoot) {
+			ModulePackageFragmentRoot other= (ModulePackageFragmentRoot) o;
+			return this.moduleName.equals(other.moduleName);
+		}
+		return false;
+	}
+	public String getElementName() {
+		return this.moduleName;
+	}
+	public PackageFragment getPackageFragment(String[] pkgName) {
+		// NOTE: Do we need a different kind of package fragment?
+		return new JarPackageFragment(this, pkgName);
+	}
+	public int hashCode() {
+		return this.parent.hashCode() + this.moduleName.hashCode();
+	}
+	protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
+		buffer.append(tabString(tab));
+		buffer.append("<module:").append(this.moduleName).append(">"); //$NON-NLS-1$ //$NON-NLS-2$
+		if (info == null) {
+			buffer.append(" (not open)"); //$NON-NLS-1$
+		}
+	}
+	@Override
+	public boolean isModule() {
+		return true;
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
index beba74d..1fbbc84 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
@@ -1,10 +1,14 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -209,7 +213,7 @@
 }
 
 /**
- * Starting at this folder, create package fragments and add the fragments that are not exclused
+ * Starting at this folder, create package fragments and add the fragments that are not excluded
  * to the collection of children.
  *
  * @exception JavaModelException  The resource associated with this package fragment does not exist
@@ -478,6 +482,10 @@
 	((JavaElement)getParent()).getHandleMemento(buff);
 	buff.append(getHandleMementoDelimiter());
 	escapeMementoName(buff, path.toString());
+	if (isModule()) {
+		buff.append(getHandleMementoDelimiter());
+		escapeMementoName(buff, getElementName());
+	}
 }
 /**
  * @see IPackageFragmentRoot
@@ -517,6 +525,9 @@
 public PackageFragment getPackageFragment(String[] pkgName) {
 	return new PackageFragment(this, pkgName);
 }
+public PackageFragment getPackageFragment(String[] pkgName, String mod) {
+	return new PackageFragment(this, pkgName); // Overridden in JImageModuleFragmentBridge
+}
 /**
  * Returns the package name for the given folder
  * (which is a decendent of this root).
@@ -824,4 +835,8 @@
 	}
 }
 
+@Override
+public boolean isModule() {
+	return false;
+}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
index 6be7c79..85e8139 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Kelly Campbell <kellyc@google.com> - Hangs in SourceMapper during java proposals - https://bugs.eclipse.org/bugs/show_bug.cgi?id=281575
@@ -13,6 +17,8 @@
 package org.eclipse.jdt.internal.core;
 
 import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -60,6 +66,7 @@
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
+import org.eclipse.jdt.internal.compiler.util.JimageUtil;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.compiler.util.Util;
 import org.eclipse.jdt.internal.core.util.ReferenceInfoAdapter;
@@ -453,6 +460,62 @@
 		return -1;
 	}
 
+	class JimagePackageNamesAdderVisitor implements JimageUtil.JimageVisitor<java.nio.file.Path> {
+
+		public final HashSet firstLevelPackageNames;
+		final IPackageFragmentRoot root;
+		public String sourceLevel = null;
+		public String complianceLevel = null;
+		public boolean containsADefaultPackage;
+		public boolean containsJavaSource;
+
+		JimagePackageNamesAdderVisitor(HashSet firstLevelPackageNames, String sourceLevel, String complianceLevel,
+				boolean containsADefaultPackage, boolean containsJavaSource, IPackageFragmentRoot root) {
+			this.firstLevelPackageNames = firstLevelPackageNames;
+			this.root = root;
+			this.sourceLevel = sourceLevel;
+			this.complianceLevel = complianceLevel;
+			this.containsADefaultPackage = containsADefaultPackage;
+			this.containsJavaSource = containsJavaSource;
+		}
+		
+		@Override
+		public FileVisitResult visitPackage(java.nio.file.Path dir, java.nio.file.Path mod, BasicFileAttributes attrs) throws IOException {
+			return FileVisitResult.CONTINUE;
+		}
+		
+		@Override
+		public FileVisitResult visitFile(java.nio.file.Path file, java.nio.file.Path mod, BasicFileAttributes attrs) throws IOException {
+			String entryName = file.toString();
+			if (Util.isClassFileName(entryName)) {
+				int index = entryName.indexOf('/');
+				if (index != -1) {
+					String firstLevelPackageName = entryName.substring(0, index);
+					if (!this.firstLevelPackageNames.contains(firstLevelPackageName)) {
+						if (this.sourceLevel == null) {
+							IJavaProject project = this.root.getJavaProject();
+							this.sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true);
+							this.complianceLevel = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
+						}
+						IStatus status = JavaConventions.validatePackageName(firstLevelPackageName, this.sourceLevel, this.complianceLevel);
+						if (status.isOK() || status.getSeverity() == IStatus.WARNING) {
+							this.firstLevelPackageNames.add(firstLevelPackageName);
+						}
+					}
+				} else {
+					this.containsADefaultPackage = true;
+				}
+			} else if (!this.containsJavaSource && org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(entryName)) {
+				this.containsJavaSource = true;
+			}
+			return FileVisitResult.CONTINUE;
+		}
+
+		@Override
+		public FileVisitResult visitModule(java.nio.file.Path mod) throws IOException {
+			return FileVisitResult.CONTINUE;
+		}
+	}
 	private synchronized void computeAllRootPaths(IType type) {
 		if (this.areRootPathsComputed) {
 			return;
@@ -471,7 +534,19 @@
 
 		String sourceLevel = null;
 		String complianceLevel = null;
-		if (root.isArchive()) {
+		if (root.isModule()) {
+			try {
+				JimagePackageNamesAdderVisitor jimagePackageNamesAdderVisitor = new JimagePackageNamesAdderVisitor(firstLevelPackageNames, 
+						sourceLevel, complianceLevel, containsADefaultPackage, containsJavaSource, root);
+				org.eclipse.jdt.internal.compiler.util.JimageUtil.walkModuleImage(root.getPath().toFile(), jimagePackageNamesAdderVisitor, JimageUtil.NOTIFY_FILES);
+				sourceLevel = jimagePackageNamesAdderVisitor.sourceLevel;
+				complianceLevel = jimagePackageNamesAdderVisitor.complianceLevel;
+				containsADefaultPackage = jimagePackageNamesAdderVisitor.containsADefaultPackage;
+				containsJavaSource = jimagePackageNamesAdderVisitor.containsJavaSource;
+			} catch (IOException e) {
+				// We are not reading any specific Jimage file, so, move on for now
+			}
+		} else if (root.isArchive()) {
 			JavaModelManager manager = JavaModelManager.getJavaModelManager();
 			ZipFile zip = null;
 			try {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
index 1bda5fb..8208f53 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Tal Lev-Ami - added package cache for zip files
@@ -15,17 +19,21 @@
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.*;
-
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
 import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
+import org.eclipse.jdt.internal.compiler.util.JimageUtil;
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
 import org.eclipse.jdt.internal.compiler.util.SimpleSet;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
+import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.eclipse.jdt.internal.core.util.Util;
 
 import java.io.*;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.*;
 import java.util.zip.*;
 
@@ -46,6 +54,18 @@
 
 static SimpleLookupTable PackageCache = new SimpleLookupTable();
 
+
+protected static void addToPackageSet(SimpleSet packageSet, String fileName, boolean endsWithSep) {
+	int last = endsWithSep ? fileName.length() : fileName.lastIndexOf('/');
+	while (last > 0) {
+		// extract the package name
+		String packageName = fileName.substring(0, last);
+		if (packageSet.addIfNotIncluded(packageName) == null)
+			return; // already existed
+		last = packageName.lastIndexOf('/');
+	}
+}
+
 /**
  * Calculate and cache the package list available in the zipFile.
  * @param jar The ClasspathJar to use
@@ -53,29 +73,46 @@
  */
 static SimpleSet findPackageSet(ClasspathJar jar) {
 	String zipFileName = jar.zipFilename;
+	PackageCacheEntry cacheEntry = (PackageCacheEntry) PackageCache.get(zipFileName);
 	long lastModified = jar.lastModified();
 	long fileSize = new File(zipFileName).length();
-	PackageCacheEntry cacheEntry = (PackageCacheEntry) PackageCache.get(zipFileName);
 	if (cacheEntry != null && cacheEntry.lastModified == lastModified && cacheEntry.fileSize == fileSize)
 		return cacheEntry.packageSet;
-
-	SimpleSet packageSet = new SimpleSet(41);
+	final SimpleSet packageSet = new SimpleSet(41);
 	packageSet.add(""); //$NON-NLS-1$
-	nextEntry : for (Enumeration e = jar.zipFile.entries(); e.hasMoreElements(); ) {
-		String fileName = ((ZipEntry) e.nextElement()).getName();
+	if (jar.isJimage) {
+		try {
+			org.eclipse.jdt.internal.compiler.util.JimageUtil.walkModuleImage(new File(zipFileName), 
+					new org.eclipse.jdt.internal.compiler.util.JimageUtil.JimageVisitor<Path>() {
 
-		// add the package name & all of its parent packages
-		int last = fileName.lastIndexOf('/');
-		while (last > 0) {
-			// extract the package name
-			String packageName = fileName.substring(0, last);
-			if (packageSet.addIfNotIncluded(packageName) == null)
-				continue nextEntry; // already existed
-			last = packageName.lastIndexOf('/');
+				@Override
+				public FileVisitResult visitPackage(Path dir, Path mod, BasicFileAttributes attrs) throws IOException {
+					ClasspathJar.addToPackageSet(packageSet, dir.toString(), true);
+					return FileVisitResult.CONTINUE;
+				}
+
+				@Override
+				public FileVisitResult visitFile(Path file, Path mod, BasicFileAttributes attrs) throws IOException {
+					return FileVisitResult.CONTINUE;
+				}
+
+				@Override
+				public FileVisitResult visitModule(Path mod) throws IOException {
+					return FileVisitResult.CONTINUE;
+				}
+			}, JimageUtil.NOTIFY_PACKAGES);
+		} catch (IOException e) {
+			// TODO: Should report better
 		}
+		PackageCache.put(zipFileName, new PackageCacheEntry(0, 0, packageSet));
+	} else {
+		packageSet.add(""); //$NON-NLS-1$
+		for (Enumeration e = jar.zipFile.entries(); e.hasMoreElements(); ) {
+			String fileName = ((ZipEntry) e.nextElement()).getName();
+			addToPackageSet(packageSet, fileName, false);
+		}
+		PackageCache.put(zipFileName, new PackageCacheEntry(lastModified, fileSize, packageSet));
 	}
-
-	PackageCache.put(zipFileName, new PackageCacheEntry(lastModified, fileSize, packageSet));
 	return packageSet;
 }
 
@@ -89,6 +126,7 @@
 SimpleSet knownPackageNames;
 AccessRuleSet accessRuleSet;
 String externalAnnotationPath;
+boolean isJimage;
 
 ClasspathJar(IFile resource, AccessRuleSet accessRuleSet, IPath externalAnnotationPath) {
 	this.resource = resource;
@@ -116,18 +154,22 @@
 	this.zipFile = null;
 	this.knownPackageNames = null;
 	this.accessRuleSet = accessRuleSet;
+	this.isJimage = JavaModelManager.isJimage(zipFilename);
 	if (externalAnnotationPath != null)
 		this.externalAnnotationPath = externalAnnotationPath.toString();
 }
 
 public ClasspathJar(ZipFile zipFile, AccessRuleSet accessRuleSet, IPath externalAnnotationPath) {
-	this.zipFilename = zipFile.getName();
+	this(zipFile.getName(), accessRuleSet, externalAnnotationPath);
 	this.zipFile = zipFile;
-	this.closeZipFileAtEnd = false;
-	this.knownPackageNames = null;
-	this.accessRuleSet = accessRuleSet;
+}
+
+public ClasspathJar(String fileName, AccessRuleSet accessRuleSet, IPath externalAnnotationPath) {
+	this(fileName, 0, accessRuleSet, externalAnnotationPath);
 	if (externalAnnotationPath != null)
 		this.externalAnnotationPath = externalAnnotationPath.toString();
+	this.isJimage = JavaModelManager.isJimage(fileName);
+
 }
 
 public void cleanup() {
@@ -147,14 +189,15 @@
 			this.annotationZipFile = null;
 		}
 	}
-	this.knownPackageNames = null;
+	if (!this.isJimage)
+		this.knownPackageNames = null;
 }
 
 public boolean equals(Object o) {
 	if (this == o) return true;
 	if (!(o instanceof ClasspathJar)) return false;
-
 	ClasspathJar jar = (ClasspathJar) o;
+	if (this.isJimage && jar.isJimage) return this.zipFilename.endsWith(jar.zipFilename);
 	if (this.accessRuleSet != jar.accessRuleSet)
 		if (this.accessRuleSet == null || !this.accessRuleSet.equals(jar.accessRuleSet))
 			return false;
@@ -165,7 +208,12 @@
 	if (!isPackage(qualifiedPackageName)) return null; // most common case
 
 	try {
-		ClassFileReader reader = ClassFileReader.read(this.zipFile, qualifiedBinaryFileName);
+		ClassFileReader reader = null;
+		if (this.isJimage) {
+			reader = ClassFileReader.readFromJimage(new File(this.zipFilename), qualifiedBinaryFileName);
+		} else {
+			reader = ClassFileReader.read(this.zipFile, qualifiedBinaryFileName);
+		}
 		if (reader != null) {
 			String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length);
 			if (this.externalAnnotationPath != null) {
@@ -199,14 +247,22 @@
 		return this.knownPackageNames.includes(qualifiedPackageName);
 
 	try {
-		if (this.zipFile == null) {
+		if (this.isJimage) {
+			synchronized (this) {
+				if (this.knownPackageNames == null) {
+					this.knownPackageNames = findPackageSet(this);
+				}
+			}
+		} else if (this.zipFile == null) {
 			if (org.eclipse.jdt.internal.core.JavaModelManager.ZIP_ACCESS_VERBOSE) {
 				System.out.println("(" + Thread.currentThread() + ") [ClasspathJar.isPackage(String)] Creating ZipFile on " + this.zipFilename); //$NON-NLS-1$	//$NON-NLS-2$
 			}
 			this.zipFile = new ZipFile(this.zipFilename);
 			this.closeZipFileAtEnd = true;
+			this.knownPackageNames = findPackageSet(this);
+		} else {
+			this.knownPackageNames = findPackageSet(this);
 		}
-		this.knownPackageNames = findPackageSet(this);
 	} catch(Exception e) {
 		this.knownPackageNames = new SimpleSet(); // assume for this build the zipFile is empty
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java
index 0cfc4b9..66ee5b1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java
@@ -1,10 +1,14 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -94,6 +98,11 @@
 				this.packageHandles= new HashtableOfArrayToObject(5);
 			}
 			// create handle
+			String module = null;
+			if (this.lastPkgFragmentRoot.isModule()) {
+				module = resourcePath.substring(separatorIndex + 1, 
+						(separatorIndex = resourcePath.lastIndexOf(IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR)));
+			}
 			String classFilePath= resourcePath.substring(separatorIndex + 1);
 			String[] simpleNames = new Path(classFilePath).segments();
 			String[] pkgName;
@@ -106,7 +115,7 @@
 			}
 			IPackageFragment pkgFragment= (IPackageFragment) this.packageHandles.get(pkgName);
 			if (pkgFragment == null) {
-				pkgFragment= this.lastPkgFragmentRoot.getPackageFragment(pkgName);
+				pkgFragment= this.lastPkgFragmentRoot.getPackageFragment(pkgName, module);
 				this.packageHandles.put(pkgName, pkgFragment);
 			}
 			IClassFile classFile= pkgFragment.getClassFile(simpleNames[length]);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java
index e08855c..76978ef 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -46,6 +50,7 @@
 import org.eclipse.jdt.internal.compiler.ast.UnionTypeReference;
 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
 import org.eclipse.jdt.internal.compiler.env.ClassSignature;
@@ -845,13 +850,18 @@
 						}
 					}
 					if (path != null) {
-						jar = JavaModelManager.getJavaModelManager().getZipFile(path);
-						for (Enumeration e= jar.entries(); e.hasMoreElements();) {
-							ZipEntry member= (ZipEntry) e.nextElement();
-							String entryName= member.getName();
-							if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(entryName)) {
-								reader = ClassFileReader.read(jar, entryName);
-								break;
+						if (JavaModelManager.isJimage(path)) {
+							// TODO(BETA_JAVA9): At the moment, there's no new class file version for Java 9.
+							return ClassFileConstants.JDK1_8;
+						} else {
+							jar = JavaModelManager.getJavaModelManager().getZipFile(path);
+							for (Enumeration e= jar.entries(); e.hasMoreElements();) {
+								ZipEntry member= (ZipEntry) e.nextElement();
+								String entryName= member.getName();
+								if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(entryName)) {
+									reader = ClassFileReader.read(jar, entryName);
+									break;
+								}
 							}
 						}
 					}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchDocument.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchDocument.java
index f5f3311..5e7fd06 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchDocument.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchDocument.java
@@ -1,10 +1,14 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -32,7 +36,11 @@
 		super(documentPath, participant);
 	}
 	public JavaSearchDocument(java.util.zip.ZipEntry zipEntry, IPath zipFilePath, byte[] contents, SearchParticipant participant) {
-		super(zipFilePath + IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR + zipEntry.getName(), participant);
+		this(zipFilePath + IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR + zipEntry.getName(), contents, participant);
+	}
+
+	public JavaSearchDocument(String documentPath, byte[] contents, SearchParticipant participant) {
+		super(documentPath, participant);
 		this.byteContents = contents;
 	}
 
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/TypeNameMatchRequestorWrapper.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/TypeNameMatchRequestorWrapper.java
index 81a74da..8f052ab 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/TypeNameMatchRequestorWrapper.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/TypeNameMatchRequestorWrapper.java
@@ -1,10 +1,18 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for bug 215139
@@ -152,7 +160,7 @@
 	if (this.lastPkgFragmentRootPath == null
 			|| this.lastPkgFragmentRootPath.length() > resourcePath.length()
 			|| !resourcePath.startsWith(this.lastPkgFragmentRootPath)) {
-		String jarPath= resourcePath.substring(0, separatorIndex);
+		String jarPath= resourcePath.substring(0, separatorIndex); 
 		IPackageFragmentRoot root= ((AbstractJavaSearchScope)this.scope).packageFragmentRoot(resourcePath, separatorIndex, jarPath);
 		if (root == null) return null;
 		this.lastPkgFragmentRootPath= jarPath;
@@ -161,6 +169,9 @@
 	}
 	// create handle
 	String classFilePath= resourcePath.substring(separatorIndex + 1);
+	int actualClassIndexSeparator = classFilePath.indexOf(IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR);
+	String moduleName = actualClassIndexSeparator == -1 ? null : classFilePath.substring(0, actualClassIndexSeparator);
+	classFilePath = moduleName != null ? classFilePath.substring(actualClassIndexSeparator + 1, classFilePath.length()) : classFilePath;
 	String[] simpleNames = new Path(classFilePath).segments();
 	String[] pkgName;
 	int length = simpleNames.length-1;
@@ -172,7 +183,7 @@
 	}
 	IPackageFragment pkgFragment= (IPackageFragment) this.packageHandles.get(pkgName);
 	if (pkgFragment == null) {
-		pkgFragment= ((PackageFragmentRoot) this.lastPkgFragmentRoot).getPackageFragment(pkgName);
+		pkgFragment= ((PackageFragmentRoot) this.lastPkgFragmentRoot).getPackageFragment(pkgName, moduleName); //BUG 478143
 		// filter org.apache.commons.lang.enum package for projects above 1.5 
 		// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=317264
 		if (length == 5 && pkgName[4].equals("enum")) { //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJimageFileToIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJimageFileToIndex.java
new file mode 100644
index 0000000..17e1e2b
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJimageFileToIndex.java
@@ -0,0 +1,362 @@
+/*******************************************************************************
+ * Copyright (c) 2015 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.search.indexing;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileVisitResult;
+import java.nio.file.attribute.BasicFileAttributes;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.compiler.InvalidInputException;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+import org.eclipse.jdt.core.search.SearchEngine;
+import org.eclipse.jdt.core.search.SearchParticipant;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.parser.Scanner;
+import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
+import org.eclipse.jdt.internal.compiler.util.JimageUtil;
+import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
+import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
+import org.eclipse.jdt.internal.compiler.util.Util;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.index.Index;
+import org.eclipse.jdt.internal.core.index.IndexLocation;
+import org.eclipse.jdt.internal.core.search.JavaSearchDocument;
+import org.eclipse.jdt.internal.core.search.processing.JobManager;
+
+public class AddJimageFileToIndex extends IndexRequest {
+
+	IFile resource;
+	Scanner scanner;
+	private IndexLocation indexFileURL;
+	private final boolean forceIndexUpdate;
+	static final char JAR_SEPARATOR = IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR.charAt(0);
+	
+	enum FILE_INDEX_STATE {
+		EXISTS,
+		DELETED
+	}
+
+
+	public AddJimageFileToIndex(IFile resource, IndexLocation indexFile, IndexManager manager) {
+		this(resource, indexFile, manager, false);
+	}
+	public AddJimageFileToIndex(IFile resource, IndexLocation indexFile, IndexManager manager, final boolean updateIndex) {
+		super(resource.getFullPath(), manager);
+		this.resource = resource;
+		this.indexFileURL = indexFile;
+		this.forceIndexUpdate = updateIndex;
+	}
+	public AddJimageFileToIndex(IPath jimagePath, IndexLocation indexFile, IndexManager manager) {
+		this(jimagePath, indexFile, manager, false);
+	}
+	public AddJimageFileToIndex(IPath jimagePath, IndexLocation indexFile, IndexManager manager, final boolean updateIndex) {
+		// external JAR scenario - no resource
+		super(jimagePath, manager);
+		this.indexFileURL = indexFile;
+		this.forceIndexUpdate = updateIndex;
+	}
+	public boolean equals(Object o) {
+		if (o instanceof AddJimageFileToIndex) {
+			if (this.resource != null)
+				return this.resource.equals(((AddJimageFileToIndex) o).resource);
+			if (this.containerPath != null)
+				return this.containerPath.equals(((AddJimageFileToIndex) o).containerPath);
+		}
+		return false;
+	}
+	public int hashCode() {
+		if (this.resource != null)
+			return this.resource.hashCode();
+		if (this.containerPath != null)
+			return this.containerPath.hashCode();
+		return -1;
+	}
+	
+	private class JimageTraverser implements org.eclipse.jdt.internal.compiler.util.JimageUtil.JimageVisitor<java.nio.file.Path> {
+		
+		SimpleLookupTable indexedFileNames;
+		public JimageTraverser() {
+		}
+		public JimageTraverser(SimpleLookupTable indexedFileNames) {
+			this.indexedFileNames = indexedFileNames;
+		}
+
+		@Override
+		public FileVisitResult visitPackage(java.nio.file.Path dir, java.nio.file.Path mod, BasicFileAttributes attrs)
+				throws IOException {
+			return FileVisitResult.CONTINUE;
+		}
+
+		@Override
+		public FileVisitResult visitFile(java.nio.file.Path path, java.nio.file.Path mod, BasicFileAttributes attrs)
+				throws IOException {
+			String name = path.getFileName().toString();
+			if (Util.isClassFileName(name) && 
+					isValidPackageNameForClass(name)) {
+				this.indexedFileNames.put(name, FILE_INDEX_STATE.EXISTS);
+			}
+			return FileVisitResult.CONTINUE;
+		}
+		@Override
+		public FileVisitResult visitModule(java.nio.file.Path mod) throws IOException {
+			return FileVisitResult.CONTINUE;
+		}
+	}
+	
+	private class JimageIndexer extends JimageTraverser {
+		final SearchParticipant participant;
+		final IPath indexPath;
+		final IndexManager indexManager;
+		final IPath container;
+		final Index index;
+		final File jimage;
+
+		public JimageIndexer(File jimage, SearchParticipant participant, Index index, IPath container, IndexManager indexManager) {
+			this.jimage = jimage;
+			this.participant = (participant != null) ? participant : SearchEngine.getDefaultSearchParticipant();
+			this.index = index;
+			IndexLocation indexLocation = index.getIndexLocation();
+			this.indexPath = indexLocation != null ? new Path(indexLocation.getCanonicalFilePath()) : null;
+			this.container = container;
+			this.indexManager = indexManager;
+		}
+
+		public FileVisitResult visitFile(java.nio.file.Path path, java.nio.file.Path mod, BasicFileAttributes attrs)
+				throws IOException {
+			String name = path.getFileName().toString();
+			if (Util.isClassFileName(name) && 
+					isValidPackageNameForClass(name)) {
+				try {
+					String fullPath = path.toString();
+					final byte[] classFileBytes = JimageUtil.getClassfileContent(this.jimage, fullPath, mod.toString());
+					String docFullPath =  this.container.toString() + JAR_SEPARATOR + mod.toString() + JAR_SEPARATOR + fullPath;
+					JavaSearchDocument entryDocument = new JavaSearchDocument(docFullPath, classFileBytes, this.participant);
+					this.indexManager.indexDocument(entryDocument, this.participant, this.index, this.indexPath);
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+			return FileVisitResult.CONTINUE;
+		}
+	}
+
+	public boolean execute(IProgressMonitor progressMonitor) {
+
+		if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true;
+
+		if (hasPreBuiltIndex()) {
+			boolean added = this.manager.addIndex(this.containerPath, this.indexFileURL);
+			if (added) return true;	
+			this.indexFileURL = null;
+		}
+
+		try {
+			// if index is already cached, then do not perform any check
+			// MUST reset the IndexManager if a jar file is changed
+			if (this.manager.getIndexForUpdate(this.containerPath, false, /*do not reuse index file*/ false /*do not create if none*/) != null) {
+				if (JobManager.VERBOSE)
+					org.eclipse.jdt.internal.core.util.Util.verbose("-> no indexing required (index already exists) for " + this.containerPath); //$NON-NLS-1$
+				return true;
+			}
+
+			final Index index = this.manager.getIndexForUpdate(this.containerPath, true, /*reuse index file*/ true /*create if none*/);
+			if (index == null) {
+				if (JobManager.VERBOSE)
+					org.eclipse.jdt.internal.core.util.Util.verbose("-> index could not be created for " + this.containerPath); //$NON-NLS-1$
+				return true;
+			}
+			index.separator = JAR_SEPARATOR;
+			ReadWriteMonitor monitor = index.monitor;
+			if (monitor == null) {
+				if (JobManager.VERBOSE)
+					org.eclipse.jdt.internal.core.util.Util.verbose("-> index for " + this.containerPath + " just got deleted"); //$NON-NLS-1$//$NON-NLS-2$
+				return true; // index got deleted since acquired
+			}
+			try {
+				final String fileName;
+				final IPath container;
+				monitor.enterWrite(); // ask permission to write
+
+				if (this.resource != null) {
+					URI location = this.resource.getLocationURI();
+					if (location == null) return false;
+					if (JavaModelManager.JIMAGE_ACCESS_VERBOSE)
+						System.out.println("(" + Thread.currentThread() + ") [AddJimageFileToIndex.execute()] Creating ZipFile on " + location.getPath()); //$NON-NLS-1$	//$NON-NLS-2$
+					File file = null;
+					try {
+						file = org.eclipse.jdt.internal.core.util.Util.toLocalFile(location, progressMonitor);
+					} catch (CoreException e) {
+						if (JobManager.VERBOSE) {
+							org.eclipse.jdt.internal.core.util.Util.verbose("-> failed to index " + location.getPath() + " because of the following exception:"); //$NON-NLS-1$ //$NON-NLS-2$
+							e.printStackTrace();
+						}
+					}
+					if (file == null) {
+						if (JobManager.VERBOSE)
+							org.eclipse.jdt.internal.core.util.Util.verbose("-> failed to index " + location.getPath() + " because the file could not be fetched"); //$NON-NLS-1$ //$NON-NLS-2$
+						return false;
+					}
+					fileName = file.getAbsolutePath();
+					container =  this.resource.getFullPath().makeRelative();
+					// absolute path relative to the workspace
+				} else {
+					
+					fileName = this.containerPath.toOSString();
+					container = this.containerPath;
+				}
+
+
+				if (JobManager.VERBOSE)
+					org.eclipse.jdt.internal.core.util.Util.verbose("-> indexing " + fileName); //$NON-NLS-1$
+				long initialTime = System.currentTimeMillis();
+				String[] paths = index.queryDocumentNames(""); // all file names //$NON-NLS-1$
+				if (paths != null) {
+					int max = paths.length;
+					/* check integrity of the existing index file
+					 * if the length is equal to 0, we want to index the whole jimage again
+					 * If not, then we want to check that there is no missing entry, if
+					 * one entry is missing then we recreate the index
+					 */
+					
+					final SimpleLookupTable indexedFileNames = new SimpleLookupTable(max == 0 ? 33 : max + 11);
+					for (int i = 0; i < max; i++)
+						indexedFileNames.put(paths[i], FILE_INDEX_STATE.DELETED);
+					
+					org.eclipse.jdt.internal.compiler.util.JimageUtil.walkModuleImage(new File(fileName), 
+							new JimageTraverser(indexedFileNames), JimageUtil.NOTIFY_FILES);
+
+					boolean needToReindex = indexedFileNames.elementSize != max; // a new file was added
+					if (!needToReindex) {
+						Object[] valueTable = indexedFileNames.valueTable;
+						for (int i = 0, l = valueTable.length; i < l; i++) {
+							if (valueTable[i] == FILE_INDEX_STATE.DELETED) {
+								needToReindex = true; // a file was deleted so re-index
+								break;
+							}
+						}
+						if (!needToReindex) {
+							if (JobManager.VERBOSE)
+								org.eclipse.jdt.internal.core.util.Util.verbose("-> no indexing required (index is consistent with library) for " //$NON-NLS-1$
+								+ fileName + " (" //$NON-NLS-1$
+								+ (System.currentTimeMillis() - initialTime) + "ms)"); //$NON-NLS-1$
+							this.manager.saveIndex(index); // to ensure its placed into the saved state
+							return true;
+						}
+					}
+				}
+
+				// Index the jimage for the first time or reindex the jimage in case the previous index file has been corrupted
+				// index already existed: recreate it so that we forget about previous entries
+				if (!this.manager.resetIndex(this.containerPath)) {
+					// failed to recreate index, see 73330
+					this.manager.removeIndex(this.containerPath);
+					return false;
+				}
+				
+				File jimage = new File(fileName);
+				org.eclipse.jdt.internal.compiler.util.JimageUtil.walkModuleImage(jimage, 
+						new JimageIndexer(jimage, SearchEngine.getDefaultSearchParticipant(), index, container, this.manager), JimageUtil.NOTIFY_FILES);
+
+				if(this.forceIndexUpdate) {
+					this.manager.savePreBuiltIndex(index);
+				}
+				else {
+					this.manager.saveIndex(index);
+				}
+				if (JobManager.VERBOSE)
+					org.eclipse.jdt.internal.core.util.Util.verbose("-> done indexing of " //$NON-NLS-1$
+						+ fileName + " (" //$NON-NLS-1$
+						+ (System.currentTimeMillis() - initialTime) + "ms)"); //$NON-NLS-1$
+			} finally {
+				monitor.exitWrite();
+			}
+		} catch (IOException e ) {
+			if (JobManager.VERBOSE) {
+				org.eclipse.jdt.internal.core.util.Util.verbose("-> failed to index " + this.containerPath + " because of the following exception:"); //$NON-NLS-1$ //$NON-NLS-2$
+				e.printStackTrace();
+			}
+			this.manager.removeIndex(this.containerPath);
+			return false;
+		}
+		return true;
+	}
+	public String getJobFamily() {
+		if (this.resource != null)
+			return super.getJobFamily();
+		return this.containerPath.toOSString(); // external jar
+	}	
+	private boolean isIdentifier() throws InvalidInputException {
+		switch(this.scanner.scanIdentifier()) {
+			// assert and enum will not be recognized as java identifiers 
+			// in 1.7 mode, which are in 1.3.
+			case TerminalTokens.TokenNameIdentifier:
+			case TerminalTokens.TokenNameassert:
+			case TerminalTokens.TokenNameenum:
+				return true;
+			default:
+				return false;
+		}
+	}
+	boolean isValidPackageNameForClass(String className) {
+		char[] classNameArray = className.toCharArray();
+		// use 1.7 as the source level as there are more valid identifiers in 1.7 mode
+		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=376673
+		if (this.scanner == null)
+			this.scanner = new Scanner(false /* comment */, true /* whitespace */, false /* nls */,
+					ClassFileConstants.JDK1_7/* sourceLevel */, null/* taskTag */, null/* taskPriorities */, true /* taskCaseSensitive */);
+		
+		this.scanner.setSource(classNameArray); 
+		this.scanner.eofPosition = classNameArray.length - SuffixConstants.SUFFIX_CLASS.length;
+		try {
+			if (isIdentifier()) {
+				while (this.scanner.eofPosition > this.scanner.currentPosition) {
+					if (this.scanner.getNextChar() != '/' || this.scanner.eofPosition <= this.scanner.currentPosition) {
+						return false;
+					}
+					if (!isIdentifier()) return false;
+				}
+				return true;
+			}
+		} catch (InvalidInputException e) {
+			// invalid class name
+		}
+		return false;
+	}
+	protected Integer updatedIndexState() {
+
+		Integer updateState = null;
+		if(hasPreBuiltIndex()) {
+			updateState = IndexManager.REUSE_STATE;
+		}
+		else {
+			updateState = IndexManager.REBUILDING_STATE;
+		}
+		return updateState;
+	}
+	public String toString() {
+		return "indexing " + this.containerPath.toString(); //$NON-NLS-1$
+	}
+
+	protected boolean hasPreBuiltIndex() {
+		return !this.forceIndexUpdate && (this.indexFileURL != null && this.indexFileURL.exists());
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
index 543549d..5773d8b 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
@@ -1,10 +1,14 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -29,6 +33,7 @@
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
 import org.eclipse.jdt.internal.compiler.util.SimpleSet;
+import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.*;
 import org.eclipse.jdt.internal.core.index.*;
 import org.eclipse.jdt.internal.core.search.BasicSearchEngine;
@@ -553,6 +558,15 @@
 	this.indexLibrary(path, requestingProject, indexURL, false);
 }
 
+private IndexRequest getRequest(Object target, IPath jPath, IndexLocation indexFile, IndexManager manager, boolean updateIndex) {
+	return isJimage(((File) target).getName()) ? new AddJimageFileToIndex(jPath, indexFile, this, updateIndex) :
+		new AddJarFileToIndex(jPath, indexFile, this, updateIndex);
+}
+
+private boolean isJimage(String fileName) {
+	return fileName != null && 
+			fileName.substring(fileName.lastIndexOf('.') + 1, fileName.length()).equals(SuffixConstants.EXTENSION_jimage);
+}
 /**
  * Trigger addition of a library to an index
  * Note: the actual operation is performed in background
@@ -579,9 +593,11 @@
 	IndexRequest request = null;
 	Object target = JavaModel.getTarget(path, true);
 	if (target instanceof IFile) {
-		request = new AddJarFileToIndex((IFile) target, indexFile, this, forceIndexUpdate);
+		request = isJimage(((IFile) target).getFullPath().toOSString()) ? 
+				new AddJimageFileToIndex((IFile) target, indexFile, this, forceIndexUpdate) :
+					new AddJarFileToIndex((IFile) target, indexFile, this, forceIndexUpdate);
 	} else if (target instanceof File) {
-		request = new AddJarFileToIndex(path, indexFile, this, forceIndexUpdate);
+		request = getRequest(target, path, indexFile, this, forceIndexUpdate);
 	} else if (target instanceof IContainer) {
 		request = new IndexBinaryFolder((IContainer) target, this);
 	} else {
@@ -685,9 +701,11 @@
 	} else if (target instanceof IFolder) {
 		request = new IndexBinaryFolder((IFolder) target, this);
 	} else if (target instanceof IFile) {
-		request = new AddJarFileToIndex((IFile) target, null, this, updateIndex);
+		request = isJimage(((IFile) target).getFullPath().toOSString()) ? 
+				new AddJimageFileToIndex((IFile) target, null, this, updateIndex) :
+					new AddJarFileToIndex((IFile) target, null, this, updateIndex);
 	} else if (target instanceof File) {
-		request = new AddJarFileToIndex(containerPath, null, this, updateIndex);
+		request = getRequest(target, containerPath, null, this, updateIndex);
 	}
 	if (request != null)
 		request(request);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java
index 2126a1c..fe5a05e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -101,7 +105,9 @@
 	try {
 		if (root.isArchive()) {
 			ClasspathEntry rawClasspathEntry = (ClasspathEntry) root.getRawClasspathEntry();
-			cp = new ClasspathJar(manager.getZipFile(path), rawClasspathEntry.getAccessRuleSet(), ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, ((IJavaProject)root.getParent()).getProject(), true));
+			cp = JavaModelManager.isJimage(path) ? 
+					new ClasspathJar(path.toOSString(), rawClasspathEntry.getAccessRuleSet(), ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, ((IJavaProject)root.getParent()).getProject(), true)) :
+			new ClasspathJar(manager.getZipFile(path), rawClasspathEntry.getAccessRuleSet(), ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, ((IJavaProject)root.getParent()).getProject(), true));
 		} else {
 			Object target = JavaModel.getTarget(path, true);
 			if (target != null) 
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
index 41a3b48..5b5634c 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
@@ -5,6 +5,10 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -12,6 +16,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -249,24 +254,27 @@
 		if (!root.isArchive())
 			return Util.newClassFileReader(((JavaElement) type).resource());
 
-		ZipFile zipFile = null;
-		try {
-			IPath zipPath = root.getPath();
-			if (JavaModelManager.ZIP_ACCESS_VERBOSE)
-				System.out.println("(" + Thread.currentThread() + ") [MatchLocator.classFileReader()] Creating ZipFile on " + zipPath); //$NON-NLS-1$	//$NON-NLS-2$
-			zipFile = manager.getZipFile(zipPath);
+		String rootPath = root.getPath().toOSString();
+		if (root.isModule()) {
 			String classFileName = classFile.getElementName();
 			String path = Util.concatWith(pkg.names, classFileName, '/');
-			return ClassFileReader.read(zipFile, path);
-		} finally {
-			manager.closeZipFile(zipFile);
+			return ClassFileReader.readFromJimage(new File(rootPath), path, root.getElementName());
+		} else {
+			ZipFile zipFile = null;
+			try {
+				IPath zipPath = root.getPath();
+				if (JavaModelManager.ZIP_ACCESS_VERBOSE)
+					System.out.println("(" + Thread.currentThread() + ") [MatchLocator.classFileReader()] Creating ZipFile on " + zipPath); //$NON-NLS-1$	//$NON-NLS-2$
+				zipFile = manager.getZipFile(zipPath);
+				String classFileName = classFile.getElementName();
+				String path = Util.concatWith(pkg.names, classFileName, '/');
+				return ClassFileReader.read(zipFile, path);
+			} finally {
+				manager.closeZipFile(zipFile);
+			}
 		}
-	} catch (ClassFormatException e) {
+	} catch (ClassFormatException | CoreException | IOException e) {
 		// invalid class file: return null
-	} catch (CoreException e) {
-		// cannot read class file: return null
-	} catch (IOException e) {
-		// cannot read class file: return null
 	}
 	return null;
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatchSet.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatchSet.java
index df8ef79..ad5b939 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatchSet.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PossibleMatchSet.java
@@ -10,6 +10,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
 
+import java.util.HashSet;
+
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.internal.compiler.util.ObjectVector;
@@ -45,11 +47,14 @@
 public PossibleMatch[] getPossibleMatches(IPackageFragmentRoot[] roots) {
 	PossibleMatch[] result = new PossibleMatch[this.elementCount];
 	int index = 0;
+	HashSet<IPath> processedHash = new HashSet<>();
 	for (int i = 0, length = roots.length; i < length; i++) {
-		ObjectVector possibleMatches = (ObjectVector) this.rootsToPossibleMatches.get(roots[i].getPath());
-		if (possibleMatches != null) {
+		IPath path = roots[i].getPath();
+		ObjectVector possibleMatches = (ObjectVector) this.rootsToPossibleMatches.get(path);
+		if (possibleMatches != null && !processedHash.contains(path)) {
 			possibleMatches.copyInto(result, index);
 			index += possibleMatches.size();
+			processedHash.add(path);
 		}
 	}
 	if (index < this.elementCount)