mx_jvmci.py revision 11694:20d1eb098cd0
16059Samurai#
26059Samurai# ----------------------------------------------------------------------------------------------------
36059Samurai#
46059Samurai# Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
56059Samurai# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
66059Samurai#
76059Samurai# This code is free software; you can redistribute it and/or modify it
86059Samurai# under the terms of the GNU General Public License version 2 only, as
96059Samurai# published by the Free Software Foundation.
106059Samurai#
116059Samurai# This code is distributed in the hope that it will be useful, but WITHOUT
126059Samurai# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
136059Samurai# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
146059Samurai# version 2 for more details (a copy is included in the LICENSE file that
156059Samurai# accompanied this code).
166059Samurai#
176059Samurai# You should have received a copy of the GNU General Public License version
186059Samurai# 2 along with this work; if not, write to the Free Software Foundation,
196059Samurai# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2047695Sbrian#
218857Srgrimes# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
226059Samurai# or visit www.oracle.com if you need additional information or have any
236059Samurai# questions.
2443313Sbrian#
2530715Sbrian# ----------------------------------------------------------------------------------------------------
2630715Sbrian
2730715Sbrianimport os, shutil, zipfile, re, time, sys, datetime, platform
2836285Sbrianfrom os.path import join, exists, dirname, isdir
2930715Sbrianfrom argparse import ArgumentParser, REMAINDER
3031061Sbrianimport StringIO
3145193Sbrianimport xml.dom.minidom
3246686Sbrianimport subprocess
3330715Sbrian
3446686Sbrianimport mx
3530715Sbrianimport mx_gate
3630715Sbrianimport mx_unittest
3730715Sbrian
386059Samuraifrom mx_gate import Task
3946686Sbrianfrom mx_unittest import unittest
406059Samurai
4136285Sbrian_suite = mx.suite('jvmci')
426059Samurai
4336285SbrianJVMCI_VERSION = 9
4436285Sbrian
4536285Sbrian"""
466059SamuraiTop level directory of the JDK source workspace.
4736285Sbrian"""
4836285Sbrian_jdkSourceRoot = dirname(_suite.dir)
4936285Sbrian
5036285Sbrian_JVMCI_JDK_TAG = 'jvmci'
5136285Sbrian
5236285Sbrian_minVersion = mx.VersionSpec('1.9')
5343313Sbrian
5443313Sbrian# max version (first _unsupported_ version)
5543313Sbrian_untilVersion = None
5636285Sbrian
5730715Sbrian_jvmciModes = {
586059Samurai    'hosted' : ['-XX:+UnlockExperimentalVMOptions', '-XX:+EnableJVMCI'],
5928679Sbrian    'jit' : ['-XX:+UnlockExperimentalVMOptions', '-XX:+EnableJVMCI', '-XX:+UseJVMCICompiler'],
606059Samurai    'disabled' : []
6146686Sbrian}
6246686Sbrian
6346686Sbrian# TODO: can optimized be built without overriding release build?
646059Samurai_jdkDebugLevels = ['release', 'fastdebug', 'slowdebug']
656059Samurai
6645103Sbrian# TODO: add client once/if it can be built on 64-bit platforms
6736285Sbrian_jdkJvmVariants = ['server', 'client']
686059Samurai
6945103Sbrian"""
7045103SbrianTranslation table from mx_jvmci:8 --vmbuild values to mx_jvmci:9 --jdk-debug-level values.
7146686Sbrian"""
7246686Sbrian_legacyVmbuilds = {
7345103Sbrian    'product' : 'release',
7436285Sbrian    'debug' : 'slowdebug'
7536285Sbrian}
7646686Sbrian
776059Samurai"""
786059SamuraiTranslates a mx_jvmci:8 --vmbuild value to a mx_jvmci:9 --jdk-debug-level value.
796059Samurai"""
8046686Sbriandef _translateLegacyDebugLevel(debugLevel):
816059Samurai    return _legacyVmbuilds.get(debugLevel, debugLevel)
8246686Sbrian
8347061Sbrian"""
8447695SbrianTranslation table from mx_jvmci:8 --vm values to mx_jvmci:9 (--jdk-jvm-variant, --jvmci-mode) tuples.
856059Samurai"""
8646686Sbrian_legacyVms = {
876059Samurai    'jvmci' : ('server', 'jit')
8846686Sbrian}
8947061Sbrian
9047695Sbrian"""
916059SamuraiA VM configuration composed of a JDK debug level, JVM variant and a JVMCI mode.
9246686SbrianThis is also a context manager that can be used with the 'with' statement to set/change
936059Samuraia VM configuration within a dynamic scope. For example:
9447061Sbrian
9536285Sbrian    with ConfiguredJDK(debugLevel='fastdebug'):
9646686Sbrian        dacapo(['pmd'])
976059Samurai"""
9846686Sbrianclass VM:
9936285Sbrian    def __init__(self, jvmVariant=None, debugLevel=None, jvmciMode=None):
10046686Sbrian        self.update(jvmVariant, debugLevel, jvmciMode)
1016059Samurai
1026059Samurai    def update(self, jvmVariant=None, debugLevel=None, jvmciMode=None):
1036059Samurai        if jvmVariant in _legacyVms:
10446828Sbrian            # Backwards compatibility for mx_jvmci:8 API
1056059Samurai            jvmVariant, newJvmciMode = _legacyVms[jvmVariant]
1066059Samurai            if jvmciMode is not None and jvmciMode != newJvmciMode:
1076059Samurai                mx.abort('JVM variant "' + jvmVariant + '" implies JVMCI mode "' + newJvmciMode +
1086059Samurai                         '" which conflicts with explicitly specified JVMCI mode of "' + jvmciMode + '"')
10928679Sbrian            jvmciMode = newJvmciMode
1106059Samurai        debugLevel = _translateLegacyDebugLevel(debugLevel)
11145103Sbrian        assert jvmVariant is None or jvmVariant in _jdkJvmVariants, jvmVariant
11236285Sbrian        assert debugLevel is None or debugLevel in _jdkDebugLevels, debugLevel
1136059Samurai        assert jvmciMode is None or jvmciMode in _jvmciModes, jvmciMode
1146059Samurai        self.jvmVariant = jvmVariant or _vm.jvmVariant
11528679Sbrian        self.debugLevel = debugLevel or _vm.debugLevel
11628679Sbrian        self.jvmciMode = jvmciMode or _vm.jvmciMode
1176059Samurai
1186059Samurai    def __enter__(self):
11936960Sbrian        global _vm
12036960Sbrian        self.previousVm = _vm
1216735Samurai        _vm = self
12236285Sbrian
12332663Sbrian    def __exit__(self, exc_type, exc_value, traceback):
12447695Sbrian        global _vm
12547695Sbrian        _vm = self.previousVm
12646686Sbrian
1276059Samurai_vm = VM(jvmVariant=_jdkJvmVariants[0], debugLevel=_jdkDebugLevels[0], jvmciMode='hosted')
12828679Sbrian
1296059Samuraidef get_vm():
13028679Sbrian    """
13128679Sbrian    Gets the configured VM.
13228679Sbrian    """
1336059Samurai    return _vm
13428679Sbrian
13528679Sbriandef relativeVmLibDirInJdk():
1366059Samurai    mxos = mx.get_os()
1376059Samurai    if mxos == 'darwin':
13836285Sbrian        return join('lib')
13936960Sbrian    if mxos == 'windows' or mxos == 'cygwin':
14036960Sbrian        return join('bin')
1416735Samurai    return join('lib', mx.get_arch())
14236285Sbrian
14332663Sbriandef isJVMCIEnabled(vm):
1446735Samurai    assert vm in _jdkJvmVariants
1456059Samurai    return True
1466059Samurai
14747695Sbriandef _makehelp():
14830715Sbrian    return subprocess.check_output([mx.gmake_cmd(), 'help'], cwd=_jdkSourceRoot)
14947695Sbrian
1506059Samuraidef _runmake(args):
15146686Sbrian    """run the JDK make process
1526059Samurai
1536059SamuraiTo build hotspot and import it into the JDK: "mx make hotspot import-hotspot"
15446686Sbrian{0}"""
15546686Sbrian
15646686Sbrian    jdkBuildDir = _get_jdk_build_dir()
1576059Samurai    if not exists(jdkBuildDir):
1586059Samurai        # JDK9 must be bootstrapped with a JDK8
1596059Samurai        compliance = mx.JavaCompliance('8')
16046686Sbrian        jdk8 = mx.get_jdk(compliance.exactMatch, versionDescription=compliance.value)
1616059Samurai        cmd = ['sh', 'configure', '--with-debug-level=' + _vm.debugLevel, '--with-native-debug-symbols=external', '--disable-precompiled-headers',
1626059Samurai               '--with-jvm-variants=' + _vm.jvmVariant, '--disable-warnings-as-errors', '--with-boot-jdk=' + jdk8.home]
16347061Sbrian        mx.run(cmd, cwd=_jdkSourceRoot)
1646059Samurai    cmd = [mx.gmake_cmd(), 'CONF=' + _vm.debugLevel]
1656059Samurai    if mx.get_opts().verbose:
1666059Samurai        cmd.append('LOG=debug')
16747061Sbrian    cmd.extend(args)
1686059Samurai    if mx.get_opts().use_jdk_image and 'images' not in args:
1696059Samurai        cmd.append('images')
17046686Sbrian
1716059Samurai    if not mx.get_opts().verbose:
17246686Sbrian        mx.log('--------------- make execution ----------------------')
17346686Sbrian        mx.log('Working directory: ' + _jdkSourceRoot)
17446686Sbrian        mx.log('Command line: ' + ' '.join(cmd))
1756059Samurai        mx.log('-----------------------------------------------------')
17631514Sbrian
17731514Sbrian    mx.run(cmd, cwd=_jdkSourceRoot)
17832439Sbrian
17931514Sbrian    if 'images' in cmd:
18037010Sbrian        jdkImageDir = join(jdkBuildDir, 'images', 'jdk')
18131514Sbrian
18236285Sbrian        # The OpenJDK build creates an empty cacerts file so copy one from
18346686Sbrian        # the default JDK (which is assumed to be an OracleJDK)
18446686Sbrian        srcCerts = join(mx.get_jdk(tag='default').home, 'lib', 'security', 'cacerts')
18536285Sbrian        if not exists(srcCerts):
18636285Sbrian            # Might be building with JDK8 which has cacerts under jre/
18731514Sbrian            srcCerts = join(mx.get_jdk(tag='default').home, 'jre', 'lib', 'security', 'cacerts')
18831514Sbrian        dstCerts = join(jdkImageDir, 'lib', 'security', 'cacerts')
18946686Sbrian        if srcCerts != dstCerts:
19046686Sbrian            shutil.copyfile(srcCerts, dstCerts)
191
192        _create_jdk_bundle(jdkBuildDir, _vm.debugLevel, jdkImageDir)
193
194def _get_jdk_bundle_arches():
195    """
196    Gets a list of names that will be the part of a JDK bundle's file name denoting the architecture.
197    The first element in the list is the canonical name. Symlinks should be created for the
198    remaining names.
199    """
200    cpu = mx.get_arch()
201    if cpu == 'amd64':
202        return ['x64', 'x86_64', 'amd64']
203    elif cpu == 'sparcv9':
204        return ['sparcv9']
205    mx.abort('Unsupported JDK bundle arch: ' + cpu)
206
207def _create_jdk_bundle(jdkBuildDir, debugLevel, jdkImageDir):
208    """
209    Creates a tar.gz JDK archive, an accompanying tar.gz.sha1 file with its
210    SHA1 signature plus symlinks to the archive for non-canonical architecture names.
211    """
212
213    arches = _get_jdk_bundle_arches()
214    jdkTgzPath = join(_suite.get_output_root(), 'jdk-bundles', 'jdk9-{}-{}-{}.tar.gz'.format(debugLevel, _get_openjdk_os(), arches[0]))
215    with mx.Archiver(jdkTgzPath, kind='tgz') as arc:
216        mx.log('Creating ' + jdkTgzPath)
217        for root, _, filenames in os.walk(jdkImageDir):
218            for name in filenames:
219                f = join(root, name)
220                arcname = 'jdk1.9.0/' + os.path.relpath(f, jdkImageDir)
221                arc.zf.add(name=f, arcname=arcname, recursive=False)
222
223    with open(jdkTgzPath + '.sha1', 'w') as fp:
224        mx.log('Creating ' + jdkTgzPath + '.sha1')
225        fp.write(mx.sha1OfFile(jdkTgzPath))
226
227    def _create_link(source, link_name):
228        if exists(link_name):
229            os.remove(link_name)
230        mx.log('Creating ' + link_name + ' -> ' + source)
231        os.symlink(source, link_name)
232
233    for arch in arches[1:]:
234        link_name = join(_suite.get_output_root(), 'jdk-bundles', 'jdk9-{}-{}-{}.tar.gz'.format(debugLevel, _get_openjdk_os(), arch))
235        jdkTgzName = os.path.basename(jdkTgzPath)
236        _create_link(jdkTgzName, link_name)
237        _create_link(jdkTgzName + '.sha1', link_name + '.sha1')
238
239def _runmultimake(args):
240    """run the JDK make process for one or more configurations"""
241
242    jvmVariantsDefault = ','.join(_jdkJvmVariants)
243    debugLevelsDefault = ','.join(_jdkDebugLevels)
244
245    parser = ArgumentParser(prog='mx multimake')
246    parser.add_argument('--jdk-jvm-variants', '--vms', help='a comma separated list of VMs to build (default: ' + jvmVariantsDefault + ')', metavar='<args>', default=jvmVariantsDefault)
247    parser.add_argument('--jdk-debug-levels', '--builds', help='a comma separated list of JDK debug levels (default: ' + debugLevelsDefault + ')', metavar='<args>', default=debugLevelsDefault)
248    parser.add_argument('-n', '--no-check', action='store_true', help='omit running "java -version" after each build')
249    select = parser.add_mutually_exclusive_group()
250    select.add_argument('-c', '--console', action='store_true', help='send build output to console instead of log files')
251    select.add_argument('-d', '--output-dir', help='directory for log files instead of current working directory', default=os.getcwd(), metavar='<dir>')
252
253    args = parser.parse_args(args)
254    jvmVariants = args.jdk_jvm_variants.split(',')
255    debugLevels = [_translateLegacyDebugLevel(dl) for dl in args.jdk_debug_levels.split(',')]
256
257    allStart = time.time()
258    for jvmVariant in jvmVariants:
259        for debugLevel in debugLevels:
260            if not args.console:
261                logFile = join(mx.ensure_dir_exists(args.output_dir), jvmVariant + '-' + debugLevel + '.log')
262                log = open(logFile, 'wb')
263                start = time.time()
264                mx.log('BEGIN: ' + jvmVariant + '-' + debugLevel + '\t(see: ' + logFile + ')')
265                verbose = ['-v'] if mx.get_opts().verbose else []
266                # Run as subprocess so that output can be directed to a file
267                cmd = [sys.executable, '-u', mx.__file__] + verbose + ['--jdk-jvm-variant=' + jvmVariant, '--jdk-debug-level=' + debugLevel, 'make']
268                mx.logv("executing command: " + str(cmd))
269                subprocess.check_call(cmd, cwd=_suite.dir, stdout=log, stderr=subprocess.STDOUT)
270                duration = datetime.timedelta(seconds=time.time() - start)
271                mx.log('END:   ' + jvmVariant + '-' + debugLevel + '\t[' + str(duration) + ']')
272            else:
273                with VM(jvmVariant=jvmVariant, debugLevel=debugLevel):
274                    _runmake([])
275            if not args.no_check:
276                with VM(jvmciMode='jit'):
277                    run_vm(['-XX:-BootstrapJVMCI', '-version'])
278    allDuration = datetime.timedelta(seconds=time.time() - allStart)
279    mx.log('TOTAL TIME:   ' + '[' + str(allDuration) + ']')
280
281class HotSpotProject(mx.NativeProject):
282    """
283    Defines a NativeProject representing the HotSpot binaries built via make.
284    """
285    def __init__(self, suite, name, deps, workingSets, **args):
286        assert name == 'hotspot'
287        mx.NativeProject.__init__(self, suite, name, "", [], deps, workingSets, None, None, join(suite.mxDir, name))
288
289    def eclipse_config_up_to_date(self, configZip):
290        # Assume that any change to this module might imply changes to the generated IDE files
291        if configZip.isOlderThan(__file__):
292            return False
293        for _, source in self._get_eclipse_settings_sources().iteritems():
294            if configZip.isOlderThan(source):
295                return False
296        return True
297
298    def _get_eclipse_settings_sources(self):
299        """
300        Gets a dictionary from the name of an Eclipse settings file to
301        the file providing its generated content.
302        """
303        if not hasattr(self, '_eclipse_settings'):
304            esdict = {}
305            templateSettingsDir = join(self.dir, 'templates', 'eclipse', 'settings')
306            if exists(templateSettingsDir):
307                for name in os.listdir(templateSettingsDir):
308                    source = join(templateSettingsDir, name)
309                    esdict[name] = source
310            self._eclipse_settings = esdict
311        return self._eclipse_settings
312
313    def _eclipseinit(self, files=None, libFiles=None):
314        """
315        Generates an Eclipse project for each HotSpot build configuration.
316        """
317
318        roots = [
319            'ASSEMBLY_EXCEPTION',
320            'LICENSE',
321            'README',
322            'THIRD_PARTY_README',
323            'agent',
324            'make',
325            'src',
326            'test'
327        ]
328
329        for jvmVariant in _jdkJvmVariants:
330            for debugLevel in _jdkDebugLevels:
331                name = jvmVariant + '-' + debugLevel
332                eclProjectDir = join(self.dir, 'eclipse', name)
333                mx.ensure_dir_exists(eclProjectDir)
334
335                out = mx.XMLDoc()
336                out.open('projectDescription')
337                out.element('name', data='hotspot:' + name)
338                out.element('comment', data='')
339                out.element('projects', data='')
340                out.open('buildSpec')
341                out.open('buildCommand')
342                out.element('name', data='org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder')
343                out.element('triggers', data='full,incremental')
344                out.element('arguments', data='')
345                out.close('buildCommand')
346
347                out.close('buildSpec')
348                out.open('natures')
349                out.element('nature', data='org.eclipse.cdt.core.cnature')
350                out.element('nature', data='org.eclipse.cdt.core.ccnature')
351                out.element('nature', data='org.eclipse.cdt.managedbuilder.core.managedBuildNature')
352                out.element('nature', data='org.eclipse.cdt.managedbuilder.core.ScannerConfigNature')
353                out.close('natures')
354
355                if roots:
356                    out.open('linkedResources')
357                    for r in roots:
358                        f = join(_suite.dir, r)
359                        out.open('link')
360                        out.element('name', data=r)
361                        out.element('type', data='2' if isdir(f) else '1')
362                        out.element('locationURI', data=mx.get_eclipse_project_rel_locationURI(f, eclProjectDir))
363                        out.close('link')
364
365                    out.open('link')
366                    out.element('name', data='generated')
367                    out.element('type', data='2')
368                    generated = join(_get_hotspot_build_dir(jvmVariant, debugLevel), 'generated')
369                    out.element('locationURI', data=mx.get_eclipse_project_rel_locationURI(generated, eclProjectDir))
370                    out.close('link')
371
372                    out.close('linkedResources')
373                out.close('projectDescription')
374                projectFile = join(eclProjectDir, '.project')
375                mx.update_file(projectFile, out.xml(indent='\t', newl='\n'))
376                if files:
377                    files.append(projectFile)
378
379                cprojectTemplate = join(self.dir, 'templates', 'eclipse', 'cproject')
380                cprojectFile = join(eclProjectDir, '.cproject')
381                with open(cprojectTemplate) as f:
382                    content = f.read()
383                mx.update_file(cprojectFile, content)
384                if files:
385                    files.append(cprojectFile)
386
387                settingsDir = join(eclProjectDir, ".settings")
388                mx.ensure_dir_exists(settingsDir)
389                for name, source in self._get_eclipse_settings_sources().iteritems():
390                    out = StringIO.StringIO()
391                    print >> out, '# GENERATED -- DO NOT EDIT'
392                    print >> out, '# Source:', source
393                    with open(source) as f:
394                        print >> out, f.read()
395                    content = out.getvalue()
396                    mx.update_file(join(settingsDir, name), content)
397                    if files:
398                        files.append(join(settingsDir, name))
399
400    def getBuildTask(self, args):
401        return JDKBuildTask(self, args, _vm.debugLevel, _vm.jvmVariant)
402
403
404class JDKBuildTask(mx.NativeBuildTask):
405    def __init__(self, project, args, debugLevel, jvmVariant):
406        mx.NativeBuildTask.__init__(self, args, project)
407        self.jvmVariant = jvmVariant
408        self.debugLevel = debugLevel
409
410    def __str__(self):
411        return 'Building JDK[{}, {}]'.format(self.debugLevel, self.jvmVariant)
412
413    def build(self):
414        if mx.get_opts().use_jdk_image:
415            _runmake(['images'])
416        else:
417            _runmake([])
418        self._newestOutput = None
419
420    def clean(self, forBuild=False):
421        if forBuild:  # Let make handle incremental builds
422            return
423        if exists(_get_jdk_build_dir(self.debugLevel)):
424            _runmake(['clean'])
425        self._newestOutput = None
426
427# Backwards compatibility for mx_jvmci:8 API
428def buildvms(args):
429    _runmultimake(args)
430
431def run_vm(args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, debugLevel=None, vmbuild=None):
432    """run a Java program by executing the java executable in a JVMCI JDK"""
433    jdkTag = mx.get_jdk_option().tag
434    if jdkTag and jdkTag != _JVMCI_JDK_TAG:
435        mx.abort('The "--jdk" option must have the tag "' + _JVMCI_JDK_TAG + '" when running a command requiring a JVMCI VM')
436    jdk = get_jvmci_jdk(debugLevel=debugLevel or _translateLegacyDebugLevel(vmbuild))
437    return jdk.run_java(args, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout)
438
439def _unittest_vm_launcher(vmArgs, mainClass, mainClassArgs):
440    run_vm(vmArgs + [mainClass] + mainClassArgs)
441
442mx_unittest.set_vm_launcher('JVMCI VM launcher', _unittest_vm_launcher)
443
444def _jvmci_gate_runner(args, tasks):
445    # Build release server VM now so we can run the unit tests
446    with Task('BuildHotSpotJVMCIHosted: release', tasks) as t:
447        if t: _runmultimake(['--jdk-jvm-variants', 'server', '--jdk-debug-levels', 'release'])
448
449    # Run unit tests in hosted mode
450    with VM(jvmVariant='server', debugLevel='release', jvmciMode='hosted'):
451        with Task('JVMCI UnitTests: hosted-release', tasks) as t:
452            if t: unittest(['--suite', 'jvmci', '--enable-timing', '--verbose', '--fail-fast'])
453
454    # Build the other VM flavors
455    with Task('BuildHotSpotJVMCIOthers: fastdebug', tasks) as t:
456        if t: _runmultimake(['--jdk-jvm-variants', 'server', '--jdk-debug-levels', 'fastdebug'])
457
458    with Task('CleanAndBuildIdealGraphVisualizer', tasks, disableJacoco=True) as t:
459        if t and platform.processor() != 'sparc':
460            buildxml = mx._cygpathU2W(join(_suite.dir, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml'))
461            mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'], env=_igvBuildEnv())
462
463mx_gate.add_gate_runner(_suite, _jvmci_gate_runner)
464mx_gate.add_gate_argument('-g', '--only-build-jvmci', action='store_false', dest='buildNonJVMCI', help='only build the JVMCI VM')
465
466def _igvJdk():
467    v8u20 = mx.VersionSpec("1.8.0_20")
468    v8u40 = mx.VersionSpec("1.8.0_40")
469    v8 = mx.VersionSpec("1.8")
470    def _igvJdkVersionCheck(version):
471        return version >= v8 and (version < v8u20 or version >= v8u40)
472    return mx.get_jdk(_igvJdkVersionCheck, versionDescription='>= 1.8 and < 1.8.0u20 or >= 1.8.0u40', purpose="building & running IGV").home
473
474def _igvBuildEnv():
475        # When the http_proxy environment variable is set, convert it to the proxy settings that ant needs
476    env = dict(os.environ)
477    proxy = os.environ.get('http_proxy')
478    if not (proxy is None) and len(proxy) > 0:
479        if '://' in proxy:
480            # Remove the http:// prefix (or any other protocol prefix)
481            proxy = proxy.split('://', 1)[1]
482        # Separate proxy server name and port number
483        proxyName, proxyPort = proxy.split(':', 1)
484        proxyEnv = '-DproxyHost="' + proxyName + '" -DproxyPort=' + proxyPort
485        env['ANT_OPTS'] = proxyEnv
486
487    env['JAVA_HOME'] = _igvJdk()
488    return env
489
490def igv(args):
491    """run the Ideal Graph Visualizer"""
492    logFile = '.ideal_graph_visualizer.log'
493    with open(join(_suite.dir, logFile), 'w') as fp:
494        mx.logv('[Ideal Graph Visualizer log is in ' + fp.name + ']')
495        nbplatform = join(_suite.dir, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'nbplatform')
496
497        # Remove NetBeans platform if it is earlier than the current supported version
498        if exists(nbplatform):
499            updateTrackingFile = join(nbplatform, 'platform', 'update_tracking', 'org-netbeans-core.xml')
500            if not exists(updateTrackingFile):
501                mx.log('Could not find \'' + updateTrackingFile + '\', removing NetBeans platform')
502                shutil.rmtree(nbplatform)
503            else:
504                dom = xml.dom.minidom.parse(updateTrackingFile)
505                currentVersion = mx.VersionSpec(dom.getElementsByTagName('module_version')[0].getAttribute('specification_version'))
506                supportedVersion = mx.VersionSpec('3.43.1')
507                if currentVersion < supportedVersion:
508                    mx.log('Replacing NetBeans platform version ' + str(currentVersion) + ' with version ' + str(supportedVersion))
509                    shutil.rmtree(nbplatform)
510                elif supportedVersion < currentVersion:
511                    mx.log('Supported NetBeans version in igv command should be updated to ' + str(currentVersion))
512
513        if not exists(nbplatform):
514            mx.logv('[This execution may take a while as the NetBeans platform needs to be downloaded]')
515
516        env = _igvBuildEnv()
517        # make the jar for Batik 1.7 available.
518        env['IGV_BATIK_JAR'] = mx.library('BATIK').get_path(True)
519        if mx.run(['ant', '-f', mx._cygpathU2W(join(_suite.dir, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml')), '-l', mx._cygpathU2W(fp.name), 'run'], env=env, nonZeroIsFatal=False):
520            mx.abort("IGV ant build & launch failed. Check '" + logFile + "'. You can also try to delete 'src/share/tools/IdealGraphVisualizer/nbplatform'.")
521
522def c1visualizer(args):
523    """run the Cl Compiler Visualizer"""
524    libpath = join(_suite.dir, 'lib')
525    if mx.get_os() == 'windows':
526        executable = join(libpath, 'c1visualizer', 'bin', 'c1visualizer.exe')
527    else:
528        executable = join(libpath, 'c1visualizer', 'bin', 'c1visualizer')
529
530    # Check whether the current C1Visualizer installation is the up-to-date
531    if exists(executable) and not exists(mx.library('C1VISUALIZER_DIST').get_path(resolve=False)):
532        mx.log('Updating C1Visualizer')
533        shutil.rmtree(join(libpath, 'c1visualizer'))
534
535    archive = mx.library('C1VISUALIZER_DIST').get_path(resolve=True)
536
537    if not exists(executable):
538        zf = zipfile.ZipFile(archive, 'r')
539        zf.extractall(libpath)
540
541    if not exists(executable):
542        mx.abort('C1Visualizer binary does not exist: ' + executable)
543
544    if mx.get_os() != 'windows':
545        # Make sure that execution is allowed. The zip file does not always specfiy that correctly
546        os.chmod(executable, 0777)
547
548    mx.run([executable])
549
550def hsdis(args, copyToDir=None):
551    """download the hsdis library
552
553    This is needed to support HotSpot's assembly dumping features.
554    By default it downloads the Intel syntax version, use the 'att' argument to install AT&T syntax."""
555    flavor = 'intel'
556    if 'att' in args:
557        flavor = 'att'
558    if mx.get_arch() == "sparcv9":
559        flavor = "sparcv9"
560    lib = mx.add_lib_suffix('hsdis-' + mx.get_arch())
561    path = join(_suite.dir, 'lib', lib)
562
563    sha1s = {
564        'att/hsdis-amd64.dll' : 'bcbd535a9568b5075ab41e96205e26a2bac64f72',
565        'att/hsdis-amd64.so' : '58919ba085d4ef7a513f25bae75e7e54ee73c049',
566        'intel/hsdis-amd64.dll' : '6a388372cdd5fe905c1a26ced614334e405d1f30',
567        'intel/hsdis-amd64.so' : '844ed9ffed64fe9599638f29a8450c50140e3192',
568        'intel/hsdis-amd64.dylib' : 'fdb13ef0d7d23d93dacaae9c98837bea0d4fc5a2',
569        'sparcv9/hsdis-sparcv9.so': '970640a9af0bd63641f9063c11275b371a59ee60',
570    }
571
572    flavoredLib = flavor + "/" + lib
573    if flavoredLib not in sha1s:
574        mx.logv("hsdis not supported on this plattform or architecture")
575        return
576
577    if not exists(path):
578        sha1 = sha1s[flavoredLib]
579        sha1path = path + '.sha1'
580        mx.download_file_with_sha1('hsdis', path, ['https://lafo.ssw.uni-linz.ac.at/pub/hsdis/' + flavoredLib], sha1, sha1path, True, True, sources=False)
581    if copyToDir is not None and exists(copyToDir):
582        shutil.copy(path, copyToDir)
583
584def hcfdis(args):
585    """disassemble HexCodeFiles embedded in text files
586
587    Run a tool over the input files to convert all embedded HexCodeFiles
588    to a disassembled format."""
589
590    parser = ArgumentParser(prog='mx hcfdis')
591    parser.add_argument('-m', '--map', help='address to symbol map applied to disassembler output')
592    parser.add_argument('files', nargs=REMAINDER, metavar='files...')
593
594    args = parser.parse_args(args)
595
596    path = mx.library('HCFDIS').get_path(resolve=True)
597    mx.run_java(['-cp', path, 'com.oracle.max.hcfdis.HexCodeFileDis'] + args.files)
598
599    if args.map is not None:
600        addressRE = re.compile(r'0[xX]([A-Fa-f0-9]+)')
601        with open(args.map) as fp:
602            lines = fp.read().splitlines()
603        symbols = dict()
604        for l in lines:
605            addressAndSymbol = l.split(' ', 1)
606            if len(addressAndSymbol) == 2:
607                address, symbol = addressAndSymbol
608                if address.startswith('0x'):
609                    address = long(address, 16)
610                    symbols[address] = symbol
611        for f in args.files:
612            with open(f) as fp:
613                lines = fp.read().splitlines()
614            updated = False
615            for i in range(0, len(lines)):
616                l = lines[i]
617                for m in addressRE.finditer(l):
618                    sval = m.group(0)
619                    val = long(sval, 16)
620                    sym = symbols.get(val)
621                    if sym:
622                        l = l.replace(sval, sym)
623                        updated = True
624                        lines[i] = l
625            if updated:
626                mx.log('updating ' + f)
627                with open('new_' + f, "w") as fp:
628                    for l in lines:
629                        print >> fp, l
630
631def jol(args):
632    """Java Object Layout"""
633    joljar = mx.library('JOL_INTERNALS').get_path(resolve=True)
634    candidates = mx.findclass(args, logToConsole=False, matcher=lambda s, classname: s == classname or classname.endswith('.' + s) or classname.endswith('$' + s))
635
636    if len(candidates) > 0:
637        candidates = mx.select_items(sorted(candidates))
638    else:
639        # mx.findclass can be mistaken, don't give up yet
640        candidates = args
641
642    run_vm(['-javaagent:' + joljar, '-cp', os.pathsep.join([mx.classpath(), joljar]), "org.openjdk.jol.MainObjectInternals"] + candidates)
643
644def _get_openjdk_os():
645    # See: common/autoconf/platform.m4
646    os = mx.get_os()
647    if 'darwin' in os:
648        os = 'macosx'
649    elif 'linux' in os:
650        os = 'linux'
651    elif 'solaris' in os:
652        os = 'solaris'
653    elif 'cygwin' in os or 'mingw' in os:
654        os = 'windows'
655    return os
656
657def _get_openjdk_cpu():
658    cpu = mx.get_arch()
659    if cpu == 'amd64':
660        cpu = 'x86_64'
661    elif cpu == 'sparcv9':
662        cpu = 'sparcv9'
663    return cpu
664
665def _get_openjdk_os_cpu():
666    return _get_openjdk_os() + '-' + _get_openjdk_cpu()
667
668def _get_jdk_build_dir(debugLevel=None):
669    """
670    Gets the directory into which the JDK is built. This directory contains
671    the exploded JDK under jdk/ and the JDK image under images/jdk/.
672    """
673    if debugLevel is None:
674        debugLevel = _vm.debugLevel
675    name = '{}-{}-{}-{}'.format(_get_openjdk_os_cpu(), 'normal', _vm.jvmVariant, debugLevel)
676    return join(dirname(_suite.dir), 'build', name)
677
678_jvmci_bootclasspath_prepends = []
679
680def _get_hotspot_build_dir(jvmVariant=None, debugLevel=None):
681    """
682    Gets the directory in which a particular HotSpot configuration is built
683    (e.g., <JDK_REPO_ROOT>/build/macosx-x86_64-normal-server-release/hotspot/bsd_amd64_compiler2)
684    """
685    if jvmVariant is None:
686        jvmVariant = _vm.jvmVariant
687
688    os = mx.get_os()
689    if os == 'darwin':
690        os = 'bsd'
691    arch = mx.get_arch()
692    buildname = {'client': 'compiler1', 'server': 'compiler2'}.get(jvmVariant, jvmVariant)
693
694    name = '{}_{}_{}'.format(os, arch, buildname)
695    return join(_get_jdk_build_dir(debugLevel=debugLevel), 'hotspot', name)
696
697class JVMCI9JDKConfig(mx.JDKConfig):
698    def __init__(self, debugLevel):
699        self.debugLevel = debugLevel
700        jdkBuildDir = _get_jdk_build_dir(debugLevel)
701        jdkDir = join(jdkBuildDir, 'images', 'jdk') if mx.get_opts().use_jdk_image else join(jdkBuildDir, 'jdk')
702        mx.JDKConfig.__init__(self, jdkDir, tag=_JVMCI_JDK_TAG)
703
704    def parseVmArgs(self, args, addDefaultArgs=True):
705        args = mx.expand_project_in_args(args, insitu=False)
706        jacocoArgs = mx_gate.get_jacoco_agent_args()
707        if jacocoArgs:
708            args = jacocoArgs + args
709
710        args = ['-Xbootclasspath/p:' + dep.classpath_repr() for dep in _jvmci_bootclasspath_prepends] + args
711
712        # Remove JVMCI jars from class path. They are only necessary when
713        # compiling with a javac from JDK8 or earlier.
714        cpIndex, cp = mx.find_classpath_arg(args)
715        if cp:
716            excluded = frozenset([dist.path for dist in _suite.dists])
717            cp = os.pathsep.join([e for e in cp.split(os.pathsep) if e not in excluded])
718            args[cpIndex] = cp
719
720        if '-version' in args:
721            ignoredArgs = args[args.index('-version') + 1:]
722            if  len(ignoredArgs) > 0:
723                mx.log("Warning: The following options will be ignored by the vm because they come after the '-version' argument: " + ' '.join(ignoredArgs))
724        return self.processArgs(args, addDefaultArgs=addDefaultArgs)
725
726    # Overrides JDKConfig
727    def run_java(self, args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, env=None, addDefaultArgs=True):
728        if vm is None:
729            vm = 'server'
730
731        args = self.parseVmArgs(args, addDefaultArgs=addDefaultArgs)
732
733        jvmciModeArgs = _jvmciModes[_vm.jvmciMode]
734        cmd = [self.java] + ['-' + vm] + jvmciModeArgs + args
735        return mx.run(cmd, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd)
736
737"""
738The dict of JVMCI JDKs indexed by debug-level names.
739"""
740_jvmci_jdks = {}
741
742def get_jvmci_jdk(debugLevel=None):
743    """
744    Gets the JVMCI JDK corresponding to 'debugLevel'.
745    """
746    if not debugLevel:
747        debugLevel = _vm.debugLevel
748    jdk = _jvmci_jdks.get(debugLevel)
749    if jdk is None:
750        try:
751            jdk = JVMCI9JDKConfig(debugLevel)
752        except mx.JDKConfigException as e:
753            jdkBuildDir = _get_jdk_build_dir(debugLevel)
754            msg = 'Error with the JDK built into {}:\n{}\nTry (re)building it with: mx --jdk-debug-level={} make'
755            if mx.get_opts().use_jdk_image:
756                msg += ' images'
757            mx.abort(msg.format(jdkBuildDir, e.message, debugLevel))
758        _jvmci_jdks[debugLevel] = jdk
759    return jdk
760
761class JVMCI9JDKFactory(mx.JDKFactory):
762    def getJDKConfig(self):
763        jdk = get_jvmci_jdk(_vm.debugLevel)
764        return jdk
765
766    def description(self):
767        return "JVMCI JDK"
768
769mx.update_commands(_suite, {
770    'make': [_runmake, '[args...]', _makehelp],
771    'multimake': [_runmultimake, '[options]'],
772    'c1visualizer' : [c1visualizer, ''],
773    'hsdis': [hsdis, '[att]'],
774    'hcfdis': [hcfdis, ''],
775    'igv' : [igv, ''],
776    'jol' : [jol, ''],
777    'vm': [run_vm, '[-options] class [args...]'],
778})
779
780mx.add_argument('-M', '--jvmci-mode', action='store', choices=sorted(_jvmciModes.viewkeys()), help='the JVM variant type to build/run (default: ' + _vm.jvmciMode + ')')
781mx.add_argument('--jdk-jvm-variant', '--vm', action='store', choices=_jdkJvmVariants + sorted(_legacyVms.viewkeys()), help='the JVM variant type to build/run (default: ' + _vm.jvmVariant + ')')
782mx.add_argument('--jdk-debug-level', '--vmbuild', action='store', choices=_jdkDebugLevels + sorted(_legacyVmbuilds.viewkeys()), help='the JDK debug level to build/run (default: ' + _vm.debugLevel + ')')
783mx.add_argument('-I', '--use-jdk-image', action='store_true', help='build/run JDK image instead of exploded JDK')
784
785mx.addJDKFactory(_JVMCI_JDK_TAG, mx.JavaCompliance('9'), JVMCI9JDKFactory())
786
787def mx_post_parse_cmd_line(opts):
788    mx.set_java_command_default_jdk_tag(_JVMCI_JDK_TAG)
789
790    jdkTag = mx.get_jdk_option().tag
791
792    jvmVariant = None
793    debugLevel = None
794    jvmciMode = None
795
796    if opts.jdk_jvm_variant is not None:
797        jvmVariant = opts.jdk_jvm_variant
798        if jdkTag and jdkTag != _JVMCI_JDK_TAG:
799            mx.warn('Ignoring "--jdk-jvm-variant" option as "--jdk" tag is not "' + _JVMCI_JDK_TAG + '"')
800
801    if opts.jdk_debug_level is not None:
802        debugLevel = _translateLegacyDebugLevel(opts.jdk_debug_level)
803        if jdkTag and jdkTag != _JVMCI_JDK_TAG:
804            mx.warn('Ignoring "--jdk-debug-level" option as "--jdk" tag is not "' + _JVMCI_JDK_TAG + '"')
805
806    if opts.jvmci_mode is not None:
807        jvmciMode = opts.jvmci_mode
808        if jdkTag and jdkTag != _JVMCI_JDK_TAG:
809            mx.warn('Ignoring "--jvmci-mode" option as "--jdk" tag is not "' + _JVMCI_JDK_TAG + '"')
810
811    _vm.update(jvmVariant, debugLevel, jvmciMode)
812