changeset 21613:60154926b513

replaced use of javap with a small Java utility for refining service class list to only those implementing com.oracle.jvmci.service.Service
author Doug Simon <doug.simon@oracle.com>
date Sun, 31 May 2015 12:32:15 +0200
parents f2a6088ddebc
children 2f92172fa320
files mx/FilterTypes.java mx/mx_graal.py mxtool/mx.py
diffstat 3 files changed, 84 insertions(+), 77 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mx/FilterTypes.java	Sun May 31 12:32:15 2015 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public class FilterTypes {
+
+    /**
+     * Prints to {@link System#out} the values in {@code args[1 .. N]} that denote classes that are
+     * {@link Class#isAssignableFrom(Class) assignable} to the type denoted in {@code args[0]}. The
+     * values are separated by {@code "|"}.
+     */
+    public static void main(String... args) throws Exception {
+        Class<?> jvmciServiceInterface = Class.forName(args[0]);
+        boolean needSep = false;
+        StringBuilder buf = new StringBuilder();
+        for (int i = 1; i < args.length; ++i) {
+            String serviceName = args[i];
+            Class<?> service = Class.forName(serviceName, false, FilterTypes.class.getClassLoader());
+            if (jvmciServiceInterface.isAssignableFrom(service)) {
+                if (buf.length() != 0) {
+                    buf.append('|');
+                }
+                buf.append(serviceName);
+                needSep = true;
+            }
+        }
+        System.out.print(buf);
+    }
+}
--- a/mx/mx_graal.py	Sat May 30 14:31:16 2015 +0200
+++ b/mx/mx_graal.py	Sun May 31 12:32:15 2015 +0200
@@ -547,78 +547,17 @@
         shutil.move(tmp, dstLib)
         os.chmod(dstLib, permissions)
 
-def _eraseGenerics(className):
-    if '<' in className:
-        return className[:className.index('<')]
-    return className
-
-def _classifyJVMCIServices(classNames, jvmciJars):
-    classification = {}
-    if not classNames:
-        return classification
-    for className in classNames:
-        classification[className] = None
-    javap = mx.java().javap
-    output = subprocess.check_output([javap, '-cp', os.pathsep.join(jvmciJars)] + classNames, stderr=subprocess.STDOUT)
-    lines = output.split(os.linesep)
-    for line in lines:
-        if line.startswith('public interface '):
-            declLine = line[len('public interface '):].strip()
-            for className in classNames:
-                if declLine.startswith(className):
-                    assert classification[className] is None
-                    afterName = declLine[len(className):]
-                    if not afterName.startswith(' extends '):
-                        classification[className] = False
-                        break
-                    superInterfaces = afterName[len(' extends '):-len(' {')].split(',')
-                    if 'com.oracle.jvmci.service.Service' in superInterfaces:
-                        classification[className] = True
-                        break
-                    maybe = [_eraseGenerics(superInterface) for superInterface in superInterfaces]
-                    classification[className] = maybe
-                    break
-    for className, v in classification.items():
-        if v is None:
-            mx.abort('Could not find interface for service ' + className + ':\n' + output)
-    return classification
-
-def _extractMaybes(classification):
-    maybes = set()
-    for v in classification.values():
-        if isinstance(v, list):
-            maybes.update(v)
-    return list(maybes)
-
-def _mergeClassification(classification, newClassification):
-    for className, value in classification.items():
-        if isinstance(value, list):
-            classification[className] = None
-            for superInterface in value:
-                if newClassification[superInterface] is True:
-                    classification[className] = True
-                    break
-                elif newClassification[superInterface] is False:
-                    if classification[className] is None:
-                        classification[className] = False
-                else:
-                    if not classification[className]:
-                        classification[className] = []
-                    classification[className].extend(newClassification[superInterface])
-
-def _filterJVMCIService(classNames, jvmciJars):
-    classification = _classifyJVMCIServices(classNames, jvmciJars)
-    needClassification = _extractMaybes(classification)
-    while needClassification:
-        _mergeClassification(classification, _classifyJVMCIServices(needClassification, jvmciJars))
-        needClassification = _extractMaybes(classification)
-    filtered = []
-    for className in classNames:
-        if classification[className] is True:
-            filtered.append(className)
-    return filtered
-
-def _extractJVMCIFiles(jvmciJars, servicesDir, optionsDir, cleanDestination=True):
+def _filterJVMCIServices(serviceImplNames, classpath):
+    """
+    Filters and returns the names in 'serviceImplNames' that denote
+    types available in 'classpath' implementing or extending
+    com.oracle.jvmci.service.Service.
+    """
+    _, binDir = mx._compile_mx_class('FilterTypes', os.pathsep.join(classpath), myDir=dirname(__file__))
+    cmd = [mx.java().java, '-cp', mx._cygpathU2W(os.pathsep.join([binDir] + classpath)), 'FilterTypes', 'com.oracle.jvmci.service.Service'] + serviceImplNames
+    return subprocess.check_output(cmd, stderr=subprocess.PIPE).split('|')
+
+def _extractJVMCIFiles(jdkJars, jvmciJars, servicesDir, optionsDir, cleanDestination=True):
     if cleanDestination:
         if exists(servicesDir):
             shutil.rmtree(servicesDir)
@@ -653,7 +592,7 @@
                         with zf.open(member) as optionsFile, \
                              file(targetpath, "wb") as target:
                             shutil.copyfileobj(optionsFile, target)
-    jvmciServices = _filterJVMCIService(servicesMap.keys(), jvmciJars)
+    jvmciServices = _filterJVMCIServices(servicesMap.keys(), jdkJars)
     for serviceName in jvmciServices:
         serviceImpls = servicesMap[serviceName]
         fd, tmp = tempfile.mkstemp(prefix=serviceName)
@@ -672,7 +611,7 @@
     jvmciJars = [join(jreJVMCIDir, e) for e in os.listdir(jreJVMCIDir) if e.endswith('.jar')]
     jreGraalServicesDir = join(jreJVMCIDir, 'services')
     jreGraalOptionsDir = join(jreJVMCIDir, 'options')
-    _extractJVMCIFiles(jvmciJars, jreGraalServicesDir, jreGraalOptionsDir)
+    _extractJVMCIFiles(_getJdkDeployedJars(jdkDir), jvmciJars, jreGraalServicesDir, jreGraalOptionsDir)
 
 def _patchGraalVersionConstant(dist):
     """
@@ -732,6 +671,24 @@
                     # deploy service files
                     _updateJVMCIFiles(jdkDir)
 
+def _getJdkDeployedJars(jdkDir):
+    """
+    Gets jar paths for all deployed distributions in the context of
+    a given JDK directory.
+    """
+    jreLibDir = join(jdkDir, 'jre', 'lib')
+    jars = []
+    for dist in _jdkDeployedDists:
+        jar = basename(mx.distribution(dist.name).path)
+        if dist.isExtension:
+            jars.append(join(jreLibDir, 'ext', jar))
+        elif dist.usesJVMCIClassLoader:
+            jars.append(join(jreLibDir, 'jvmci', jar))
+        else:
+            jars.append(join(jreLibDir, jar))
+    return jars
+
+
 # run a command in the windows SDK Debug Shell
 def _runInDebugShell(cmd, workingDir, logFile=None, findInOutput=None, respondTo=None):
     if respondTo is None:
@@ -892,8 +849,10 @@
         with open(defsPath) as fp:
             defs = fp.read()
         jvmciJars = []
+        jdkJars = []
         for jdkDist in _jdkDeployedDists:
             dist = mx.distribution(jdkDist.name)
+            jdkJars.append(join(_graal_home, dist.path))
             defLine = 'EXPORT_LIST += $(EXPORT_JRE_LIB_DIR)/' + basename(dist.path)
             if jdkDist.isExtension:
                 defLine = 'EXPORT_LIST += $(EXPORT_JRE_LIB_EXT_DIR)/' + basename(dist.path)
@@ -905,7 +864,7 @@
             if defLine not in defs:
                 mx.abort('Missing following line in ' + defsPath + '\n' + defLine)
             shutil.copy(dist.path, opts2.export_dir)
-        services, optionsFiles = _extractJVMCIFiles(jvmciJars, join(opts2.export_dir, 'services'), join(opts2.export_dir, 'options'))
+        services, optionsFiles = _extractJVMCIFiles(jdkJars, jvmciJars, join(opts2.export_dir, 'services'), join(opts2.export_dir, 'options'))
         for service in services:
             defLine = 'EXPORT_LIST += $(EXPORT_JRE_LIB_JVMCI_SERVICES_DIR)/' + service
             if defLine not in defs:
--- a/mxtool/mx.py	Sat May 30 14:31:16 2015 +0200
+++ b/mxtool/mx.py	Sun May 31 12:32:15 2015 +0200
@@ -5434,8 +5434,8 @@
         _show_section('projects', s.projects)
         _show_section('distributions', s.dists)
 
-def _compile_mx_class(javaClassName, classpath=None, jdk=None):
-    myDir = dirname(__file__)
+def _compile_mx_class(javaClassName, classpath=None, jdk=None, myDir=None):
+    myDir = dirname(__file__) if myDir is None else myDir
     binDir = join(myDir, 'bin' if not jdk else '.jdk' + str(jdk.version))
     javaSource = join(myDir, javaClassName + '.java')
     javaClass = join(binDir, javaClassName + '.class')