changeset 5457:87dfecd51e71

Merge.
author Doug Simon <doug.simon@oracle.com>
date Wed, 30 May 2012 18:38:11 +0200
parents a5e43a18ac52 (diff) 071f24ba116e (current diff)
children 7accd1838b1b
files
diffstat 5 files changed, 191 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Wed May 30 18:14:20 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Wed May 30 18:38:11 2012 +0200
@@ -221,18 +221,19 @@
         if (srcPos < 0 || destPos < 0 || length < 0 || srcPos + length > src.length || destPos + length > dest.length) {
             throw new IndexOutOfBoundsException();
         }
+        final int scale = arrayIndexScale(CiKind.Object);
         if (src == dest && srcPos < destPos) { // bad aliased case
-            copyObjectsDown(src, srcPos * 8L, dest, destPos * 8L, length);
+            copyObjectsDown(src, srcPos * scale, dest, destPos * scale, length);
         } else {
-            copyObjectsUp(src, srcPos * 8L, dest, destPos * 8L, length);
+            copyObjectsUp(src, srcPos * scale, dest, destPos * scale, length);
         }
         if (length > 0) {
-            int header = arrayHeaderSizeFor(CiKind.Object);
+            int header = arrayBaseOffset(CiKind.Object);
             int cardShift = cardTableShift();
             long cardStart = cardTableStart();
             long dstAddr = GetObjectAddressNode.get(dest);
-            long start = (dstAddr + header + destPos * 8L) >>> cardShift;
-            long end = (dstAddr + header + (destPos + length - 1) * 8L) >>> cardShift;
+            long start = (dstAddr + header + destPos * scale) >>> cardShift;
+            long end = (dstAddr + header + (destPos + length - 1) * scale) >>> cardShift;
             long count = end - start + 1;
             while (count-- > 0) {
                 DirectStoreNode.store((start + cardStart) + count, false);
@@ -242,7 +243,7 @@
 
     @Snippet
     public static void copyBytesDown(Object src, int srcPos, Object dest, int destPos, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Byte);
+        int header = arrayBaseOffset(CiKind.Byte);
         for (long i = length - 1; i >= 0; i--) {
             Byte a = UnsafeLoadNode.load(src, header, i + srcPos, CiKind.Byte);
             UnsafeStoreNode.store(dest, header, i + destPos, a.byteValue(), CiKind.Byte);
@@ -251,7 +252,7 @@
 
     @Snippet
     public static void copyShortsDown(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Short);
+        int header = arrayBaseOffset(CiKind.Short);
         for (long i = (length - 1) * 2; i >= 0; i -= 2) {
             Character a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Short);
             UnsafeStoreNode.store(dest, header, i + destOffset, a.charValue(), CiKind.Short);
@@ -260,7 +261,7 @@
 
     @Snippet
     public static void copyIntsDown(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Int);
+        int header = arrayBaseOffset(CiKind.Int);
         for (long i = (length - 1) * 4; i >= 0; i -= 4) {
             Integer a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Int);
             UnsafeStoreNode.store(dest, header, i + destOffset, a.intValue(), CiKind.Int);
@@ -269,7 +270,7 @@
 
     @Snippet
     public static void copyLongsDown(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Long);
+        int header = arrayBaseOffset(CiKind.Long);
         for (long i = (length - 1) * 8; i >= 0; i -= 8) {
             Long a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Long);
             UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), CiKind.Long);
@@ -279,8 +280,9 @@
     // Does NOT perform store checks
     @Snippet
     public static void copyObjectsDown(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Object);
-        for (long i = (length - 1) * wordSize(); i >= 0; i -= wordSize()) {
+        int header = arrayBaseOffset(CiKind.Object);
+        final int scale = arrayIndexScale(CiKind.Object);
+        for (long i = (length - 1) * scale; i >= 0; i -= scale) {
             Object a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Object);
             DirectObjectStoreNode.store(dest, header, i + destOffset, a);
         }
@@ -295,7 +297,7 @@
      */
     @Snippet
     public static void copyBytesUp(Object src, int srcPos, Object dest, int destPos, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Byte);
+        int header = arrayBaseOffset(CiKind.Byte);
         for (long i = 0; i < length; i++) {
             Byte a = UnsafeLoadNode.load(src, header, i + srcPos, CiKind.Byte);
             UnsafeStoreNode.store(dest, header, i + destPos, a.byteValue(), CiKind.Byte);
@@ -312,7 +314,7 @@
      */
     @Snippet
     public static void copyShortsUp(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Short);
+        int header = arrayBaseOffset(CiKind.Short);
         for (long i = 0; i < length * 2L; i += 2) {
             Character a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Short);
             UnsafeStoreNode.store(dest, header, i + destOffset, a.charValue(), CiKind.Short);
@@ -321,7 +323,7 @@
 
     @Snippet
     public static void copyIntsUp(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Int);
+        int header = arrayBaseOffset(CiKind.Int);
         for (long i = 0; i < length * 4L; i += 4) {
             Integer a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Int);
             UnsafeStoreNode.store(dest, header, i + destOffset, a.intValue(), CiKind.Int);
@@ -330,7 +332,7 @@
 
     @Snippet
     public static void copyLongsUp(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Long);
+        int header = arrayBaseOffset(CiKind.Long);
         for (long i = 0; i < length * 8L; i += 8) {
             Long a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Long);
             UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), CiKind.Long);
@@ -340,20 +342,33 @@
     // Does NOT perform store checks
     @Snippet
     public static void copyObjectsUp(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        int header = arrayHeaderSizeFor(CiKind.Object);
-        for (long i = 0; i < length * wordSize(); i += wordSize()) {
+        int header = arrayBaseOffset(CiKind.Object);
+        final int scale = arrayIndexScale(CiKind.Object);
+        for (long i = 0; i < length * scale; i += scale) {
             Object a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Object);
             DirectObjectStoreNode.store(dest, header, i + destOffset, a);
         }
     }
+
     @Fold
-    private static int wordSize() {
-        return CompilerImpl.getInstance().getTarget().wordSize;
+    static int arrayBaseOffset(CiKind elementKind) {
+        return elementKind.arrayBaseOffset();
     }
 
     @Fold
-    static int arrayHeaderSizeFor(CiKind elementKind) {
-        return CompilerImpl.getInstance().getConfig().getArrayOffset(elementKind);
+    static int arrayIndexScale(CiKind elementKind) {
+        return elementKind.arrayIndexScale();
+    }
+
+    static {
+        assert arrayIndexScale(CiKind.Byte) == 1;
+        assert arrayIndexScale(CiKind.Boolean) == 1;
+        assert arrayIndexScale(CiKind.Char) == 2;
+        assert arrayIndexScale(CiKind.Short) == 2;
+        assert arrayIndexScale(CiKind.Int) == 4;
+        assert arrayIndexScale(CiKind.Long) == 8;
+        assert arrayIndexScale(CiKind.Float) == 4;
+        assert arrayIndexScale(CiKind.Double) == 8;
     }
 
     @Fold
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Wed May 30 18:14:20 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Wed May 30 18:38:11 2012 +0200
@@ -24,8 +24,6 @@
 
 import java.lang.reflect.*;
 
-import sun.misc.*;
-
 import com.oracle.graal.cri.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -71,7 +69,7 @@
                 int length = Array.getLength(array);
                 if (index >= 0 && index < length) {
                     return ConstantNode.forCiConstant(elementKind().readUnsafeConstant(array,
-                                    Unsafe.ARRAY_OBJECT_BASE_OFFSET + index * Unsafe.ARRAY_OBJECT_INDEX_SCALE), tool.runtime(), graph());
+                                    elementKind().arrayBaseOffset() + index * elementKind().arrayIndexScale()), tool.runtime(), graph());
                 }
             }
         }
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java	Wed May 30 18:14:20 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java	Wed May 30 18:38:11 2012 +0200
@@ -344,6 +344,58 @@
         return Character.toUpperCase(typeChar);
     }
 
+    public final int arrayBaseOffset() {
+        switch(this) {
+            case Boolean:
+                return Unsafe.ARRAY_BOOLEAN_BASE_OFFSET;
+            case Byte:
+                return Unsafe.ARRAY_BYTE_BASE_OFFSET;
+            case Char:
+                return Unsafe.ARRAY_CHAR_BASE_OFFSET;
+            case Short:
+                return Unsafe.ARRAY_SHORT_BASE_OFFSET;
+            case Int:
+                return Unsafe.ARRAY_INT_BASE_OFFSET;
+            case Long:
+                return Unsafe.ARRAY_LONG_BASE_OFFSET;
+            case Float:
+                return Unsafe.ARRAY_FLOAT_BASE_OFFSET;
+            case Double:
+                return Unsafe.ARRAY_DOUBLE_BASE_OFFSET;
+            case Object:
+                return Unsafe.ARRAY_OBJECT_BASE_OFFSET;
+            default:
+                assert false : "unexpected kind: " + this;
+                return -1;
+        }
+    }
+
+    public final int arrayIndexScale() {
+        switch(this) {
+            case Boolean:
+                return Unsafe.ARRAY_BOOLEAN_INDEX_SCALE;
+            case Byte:
+                return Unsafe.ARRAY_BYTE_INDEX_SCALE;
+            case Char:
+                return Unsafe.ARRAY_CHAR_INDEX_SCALE;
+            case Short:
+                return Unsafe.ARRAY_SHORT_INDEX_SCALE;
+            case Int:
+                return Unsafe.ARRAY_INT_INDEX_SCALE;
+            case Long:
+                return Unsafe.ARRAY_LONG_INDEX_SCALE;
+            case Float:
+                return Unsafe.ARRAY_FLOAT_INDEX_SCALE;
+            case Double:
+                return Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
+            case Object:
+                return Unsafe.ARRAY_OBJECT_INDEX_SCALE;
+            default:
+                assert false : "unexpected kind: " + this;
+                return -1;
+        }
+    }
+
     public CiConstant readUnsafeConstant(Object value, long displacement) {
         assert value != null;
         Unsafe u = Unsafe.getUnsafe();
--- a/hotspot/.cproject	Wed May 30 18:14:20 2012 +0200
+++ b/hotspot/.cproject	Wed May 30 18:38:11 2012 +0200
@@ -20,7 +20,7 @@
 					<folderInfo id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.305678577" name="/" resourcePath="">
 						<toolChain id="cdt.managedbuild.toolchain.gnu.base.1866612258" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.base">
 							<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.base.2075405295" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
-							<builder arguments="${workspace_loc:/hotspot}/../mxtool/mx build" autoBuildTarget="ide-build-target" buildPath="${workspace_loc:/hotspot}/.." cleanBuildTarget="clean" command="bash" enableAutoBuild="true" enableCleanBuild="false" enabledIncrementalBuild="false" id="cdt.managedbuild.target.gnu.builder.base.81453037" incrementalBuildTarget="jvmg1" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" parallelizationNumber="1" superClass="cdt.managedbuild.target.gnu.builder.base">
+							<builder arguments="${workspace_loc:/hotspot}/../mxtool/mx build" autoBuildTarget="ide-build-target" buildPath="${workspace_loc:/hotspot}/.." cleanBuildTarget="clean" command="bash" enableAutoBuild="true" enableCleanBuild="false" enabledIncrementalBuild="false" id="cdt.managedbuild.target.gnu.builder.base.81453037" incrementalBuildTarget="jvmg1" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base">
 								<outputEntries>
 									<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="outputPath" name=""/>
 								</outputEntries>
@@ -80,14 +80,15 @@
 			<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
 			<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
 			<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
-			<storageModule moduleId="scannerConfiguration"/>
 		</cconfiguration>
 	</storageModule>
 	<storageModule moduleId="cdtBuildSystem" version="4.0.0">
 		<project id="hotspot.null.1712822257" name="hotspot"/>
 	</storageModule>
-	<storageModule moduleId="refreshScope" versionNumber="1">
-		<resource resourceType="PROJECT" workspacePath="/hotspot"/>
+	<storageModule moduleId="refreshScope" versionNumber="2">
+		<configuration configurationName="Default">
+			<resource resourceType="PROJECT" workspacePath="/hotspot"/>
+		</configuration>
 	</storageModule>
 	<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
 	<storageModule moduleId="scannerConfiguration">
@@ -111,4 +112,5 @@
 			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
 		</scannerConfigBuildInfo>
 	</storageModule>
+	<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
 </cproject>
--- a/mxtool/mx.py	Wed May 30 18:14:20 2012 +0200
+++ b/mxtool/mx.py	Wed May 30 18:38:11 2012 +0200
@@ -124,7 +124,7 @@
 Property values can use environment variables with Bash syntax (e.g. ${HOME}).
 """
 
-import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal, xml.sax.saxutils
+import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal, xml.sax.saxutils, tempfile
 import shutil, fnmatch, re, xml.dom.minidom
 from collections import Callable
 from threading import Thread
@@ -404,11 +404,11 @@
 class XMLElement(xml.dom.minidom.Element):
     def writexml(self, writer, indent="", addindent="", newl=""):
         writer.write(indent+"<" + self.tagName)
-    
+
         attrs = self._get_attributes()
         a_names = attrs.keys()
         a_names.sort()
-    
+
         for a_name in a_names:
             writer.write(" %s=\"" % a_name)
             xml.dom.minidom._write_data(writer, attrs[a_name].value)
@@ -416,7 +416,7 @@
         if self.childNodes:
             if not self.ownerDocument.padTextNodeWithoutSiblings and len(self.childNodes) == 1 and isinstance(self.childNodes[0], xml.dom.minidom.Text):
                 # if the only child of an Element node is a Text node, then the
-                # text is printed without any indentation or new line padding  
+                # text is printed without any indentation or new line padding
                 writer.write(">")
                 self.childNodes[0].writexml(writer)
                 writer.write("</%s>%s" % (self.tagName,newl))
@@ -440,7 +440,7 @@
         e = XMLElement(tagName)
         e.ownerDocument = self
         return e
-    
+
     def open(self, tag, attributes={}, data=None):
         element = self.createElement(tag)
         for key, value in attributes.items():
@@ -453,13 +453,13 @@
 
     def close(self, tag):
         assert self.current != self
-        assert tag == self.current.tagName, str(tag) + ' != ' + self.current.tagName  
+        assert tag == self.current.tagName, str(tag) + ' != ' + self.current.tagName
         self.current = self.current.parentNode
         return self
-    
+
     def element(self, tag, attributes={}, data=None):
         return self.open(tag, attributes, data).close(tag)
-            
+
     def xml(self, indent='', newl='', escape=False):
         assert self.current == self
         result = self.toprettyxml(indent, newl, encoding="UTF-8")
@@ -534,20 +534,49 @@
         cp += [_opts.cp_suffix]
     return os.pathsep.join(cp)
 
-def classpath(names=None, resolve=True, includeSelf=True):
+def classpath(names=None, resolve=True, includeSelf=True, includeBootClasspath=False):
     """
     Get the class path for a list of given projects, resolving each entry in the
     path (e.g. downloading a missing library) if 'resolve' is true.
     """
     if names is None:
-        return _as_classpath(sorted_deps(includeLibs=True), resolve)
-    deps = []
-    if isinstance(names, types.StringTypes):
-        project(names).all_deps(deps, True, includeSelf)
+        result = _as_classpath(sorted_deps(includeLibs=True), resolve)
     else:
-        for n in names:
-            project(n).all_deps(deps, True, includeSelf)
-    return _as_classpath(deps, resolve)
+        deps = []
+        if isinstance(names, types.StringTypes):
+            project(names).all_deps(deps, True, includeSelf)
+        else:
+            for n in names:
+                project(n).all_deps(deps, True, includeSelf)
+        result = _as_classpath(deps, resolve)
+    if includeBootClasspath:
+        result = os.pathsep.join([java().bootclasspath(), result])
+    return result
+
+def classpath_walk(names=None, resolve=True, includeSelf=True, includeBootClasspath=False):
+    """
+    Walks the resources available in a given classpath, yielding a tuple for each resource
+    where the first member of the tuple is a directory path or ZipFile object for a
+    classpath entry and the second member is the qualified path of the resource relative
+    to the classpath entry.
+    """
+    cp = classpath(names, resolve, includeSelf, includeBootClasspath)
+    for entry in cp.split(os.pathsep):
+        if not exists(entry):
+            continue
+        if isdir(entry):
+            for root, dirs, files in os.walk(entry):
+                for d in dirs:
+                    entryPath = join(root[len(entry) + 1:], d)
+                    yield entry, entryPath
+                for f in files:
+                    entryPath = join(root[len(entry) + 1:], f)
+                    yield entry, entryPath
+        elif entry.endswith('.jar') or entry.endswith('.zip'):
+            with zipfile.ZipFile(entry, 'r') as zf:
+                for zi in zf.infolist():
+                    entryPath = zi.filename
+                    yield zf, entryPath
 
 def sorted_deps(projectNames=None, includeLibs=False):
     """
@@ -830,6 +859,7 @@
         self.javac = exe_suffix(join(self.jdk, 'bin', 'javac'))
         self.javap = exe_suffix(join(self.jdk, 'bin', 'javap'))
         self.javadoc = exe_suffix(join(self.jdk, 'bin', 'javadoc'))
+        self._bootclasspath = None
 
         if not exists(self.java):
             abort('Java launcher derived from JAVA_HOME does not exist: ' + self.java)
@@ -863,6 +893,27 @@
     def format_cmd(self, args):
         return [self.java] + self.java_args_pfx + self.java_args + self.java_args_sfx + args
 
+    def bootclasspath(self):
+        if self._bootclasspath is None:
+            tmpDir = tempfile.mkdtemp()
+            try:
+                src = join(tmpDir, 'bootclasspath.java')
+                with open(src, 'w') as fp:
+                    print >> fp, """
+public class bootclasspath {
+    public static void main(String[] args) {
+        String s = System.getProperty("sun.boot.class.path");
+        if (s != null) {
+            System.out.println(s);
+        }
+    }
+}"""
+                subprocess.check_call([self.javac, '-d', tmpDir, src])
+                self._bootclasspath = subprocess.check_output([self.java, '-cp', tmpDir, 'bootclasspath'])
+            finally:
+                shutil.rmtree(tmpDir)
+        return self._bootclasspath
+
 def check_get_env(key):
     """
     Gets an environment variable, aborting with a useful message if it is not set.
@@ -1039,7 +1090,7 @@
     javaCompliance = java().javaCompliance
 
     defaultEcjPath = join(_mainSuite.dir, 'mx', 'ecj.jar')
-    
+
     parser = parser if parser is not None else ArgumentParser(prog='mx build')
     parser.add_argument('-f', action='store_true', dest='force', help='force build (disables timestamp checking)')
     parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output')
@@ -1440,8 +1491,8 @@
         for dep in p.canonical_deps():
             print '"' + p.name + '"->"' + dep + '"'
     print '}'
-    
-    
+
+
 def _source_locator_memento(deps):
     slm = XMLDoc()
     slm.open('sourceLookupDirector')
@@ -1450,7 +1501,7 @@
     # Every Java program depends on the JRE
     memento = XMLDoc().element('classpathContainer', {'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER'}).xml()
     slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'})
-        
+
     for dep in deps:
         if dep.isLibrary():
             if hasattr(dep, 'eclipse.container'):
@@ -1482,7 +1533,7 @@
     launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.VM_CONNECTOR_ID', 'value' : 'org.eclipse.jdt.launching.socketAttachConnector'})
     launch.close('launchConfiguration')
     launch = launch.xml(newl='\n') % slm.xml(escape=True)
-    
+
     if name is None:
         name = 'attach-' + hostname + '-' + port
     eclipseLaunches = join('mx', 'eclipse-launches')
@@ -1516,11 +1567,11 @@
             mainClass = a
             appArgs = list(reversed(argsCopy))
             break
-    
+
     if mainClass is None:
         log('Cannot create Eclipse launch configuration without main class or jar file: java ' + ' '.join(javaArgs))
         return False
-    
+
     if name is None:
         if mainClass == '-jar':
             name = basename(appArgs[0])
@@ -1535,9 +1586,9 @@
             for s in suites():
                 deps += [p for p in s.projects if e == p.output_dir()]
                 deps += [l for l in s.libs if e == l.get_path(False)]
-    
+
     slm = _source_locator_memento(deps)
-    
+
     launch = XMLDoc()
     launch.open('launchConfiguration', {'type' : 'org.eclipse.jdt.launching.localJavaApplication'})
     launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_id', 'value' : 'org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector'})
@@ -1564,13 +1615,13 @@
     for p in projects():
         if p.native:
             continue
-        
+
         if not exists(p.dir):
             os.makedirs(p.dir)
 
         out = XMLDoc()
         out.open('classpath')
-        
+
         for src in p.srcDirs:
             srcDir = join(p.dir, src)
             if not exists(srcDir):
@@ -1677,7 +1728,7 @@
                     content = content.replace('${javaCompliance}', str(p.javaCompliance))
                     update_file(join(settingsDir, name), content)
 
-    make_eclipse_attach('localhost', '8000', deps=projects())                    
+    make_eclipse_attach('localhost', '8000', deps=projects())
 
 def netbeansinit(args, suite=None):
     """(re)generate NetBeans project configurations"""
@@ -1717,7 +1768,7 @@
         out.element('root', {'id' : 'test.src.dir'})
         out.close('test-roots')
         out.close('data')
-        
+
         firstDep = True
         for dep in p.all_deps([], True):
             if dep == p:
@@ -1894,7 +1945,7 @@
 
 def javadoc(args):
     """generate javadoc for some/all Java projects"""
-    
+
     parser = ArgumentParser(prog='mx javadoc')
     parser.add_argument('--unified', action='store_true', help='put javadoc in a single directory instead of one per project')
     parser.add_argument('--force', action='store_true', help='(re)generate javadoc even if package-list file exists')
@@ -2006,6 +2057,20 @@
         run([java().javadoc, memory, '-classpath', cp, '-quiet', '-d', out, '-sourcepath', sp] + docletArgs + links + extraArgs + list(pkgs))
         log('Generated {2} for {0} in {1}'.format(', '.join(names), out, docDir))
 
+def findclass(args):
+    """find all classes matching a given substring"""
+
+    for entry, filename in classpath_walk(includeBootClasspath=True):
+        if filename.endswith('.class'):
+            if isinstance(entry, zipfile.ZipFile):
+                classname = filename.replace('/', '.')
+            else:
+                classname = filename.replace(os.sep, '.')
+            classname = classname[:-len('.class')]
+            for a in args:
+                if a in classname:
+                    log(classname)
+
 def javap(args):
     """launch javap with a -classpath option denoting all available classes
 
@@ -2047,6 +2112,7 @@
     'canonicalizeprojects': [canonicalizeprojects, ''],
     'clean': [clean, ''],
     'eclipseinit': [eclipseinit, ''],
+    'findclass': [findclass, ''],
     'help': [help_, '[command]'],
     'ideclean': [ideclean, ''],
     'ideinit': [ideinit, ''],