mx_jvmci.py revision 12799:c2314cb67e28
1#
2# ----------------------------------------------------------------------------------------------------
3#
4# Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
5# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6#
7# This code is free software; you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 2 only, as
9# published by the Free Software Foundation.
10#
11# This code is distributed in the hope that it will be useful, but WITHOUT
12# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14# version 2 for more details (a copy is included in the LICENSE file that
15# accompanied this code).
16#
17# You should have received a copy of the GNU General Public License version
18# 2 along with this work; if not, write to the Free Software Foundation,
19# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20#
21# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22# or visit www.oracle.com if you need additional information or have any
23# questions.
24#
25# ----------------------------------------------------------------------------------------------------
26
27import os, shutil, zipfile, re, time, sys, datetime, platform
28from os.path import join, exists, dirname, isdir
29from argparse import ArgumentParser, REMAINDER
30import StringIO
31import xml.dom.minidom
32import subprocess
33
34import mx
35import mx_gate
36import mx_unittest
37
38from mx_gate import Task
39from mx_unittest import unittest
40
41_suite = mx.suite('jvmci')
42
43JVMCI_VERSION = 9
44
45"""
46Top level directory of the JDK source workspace.
47"""
48_jdkSourceRoot = dirname(_suite.dir)
49
50_JVMCI_JDK_TAG = 'jvmci'
51
52_minVersion = mx.VersionSpec('1.9')
53
54# max version (first _unsupported_ version)
55_untilVersion = None
56
57_jvmciModes = {
58    'hosted' : ['-XX:+UnlockExperimentalVMOptions', '-XX:+EnableJVMCI'],
59    'jit' : ['-XX:+UnlockExperimentalVMOptions', '-XX:+EnableJVMCI', '-XX:+UseJVMCICompiler'],
60    'disabled' : []
61}
62
63# TODO: can optimized be built without overriding release build?
64_jdkDebugLevels = ['release', 'fastdebug', 'slowdebug']
65
66# TODO: add client once/if it can be built on 64-bit platforms
67_jdkJvmVariants = ['server', 'client']
68
69"""
70Translation table from mx_jvmci:8 --vmbuild values to mx_jvmci:9 --jdk-debug-level values.
71"""
72_legacyVmbuilds = {
73    'product' : 'release',
74    'debug' : 'slowdebug'
75}
76
77"""
78Translates a mx_jvmci:8 --vmbuild value to a mx_jvmci:9 --jdk-debug-level value.
79"""
80def _translateLegacyDebugLevel(debugLevel):
81    return _legacyVmbuilds.get(debugLevel, debugLevel)
82
83"""
84Translation table from mx_jvmci:8 --vm values to mx_jvmci:9 (--jdk-jvm-variant, --jvmci-mode) tuples.
85"""
86_legacyVms = {
87    'jvmci' : ('server', 'jit')
88}
89
90"""
91A VM configuration composed of a JDK debug level, JVM variant and a JVMCI mode.
92This is also a context manager that can be used with the 'with' statement to set/change
93a VM configuration within a dynamic scope. For example:
94
95    with ConfiguredJDK(debugLevel='fastdebug'):
96        dacapo(['pmd'])
97"""
98class VM:
99    def __init__(self, jvmVariant=None, debugLevel=None, jvmciMode=None):
100        self.update(jvmVariant, debugLevel, jvmciMode)
101
102    def update(self, jvmVariant=None, debugLevel=None, jvmciMode=None):
103        if jvmVariant in _legacyVms:
104            # Backwards compatibility for mx_jvmci:8 API
105            jvmVariant, newJvmciMode = _legacyVms[jvmVariant]
106            if jvmciMode is not None and jvmciMode != newJvmciMode:
107                mx.abort('JVM variant "' + jvmVariant + '" implies JVMCI mode "' + newJvmciMode +
108                         '" which conflicts with explicitly specified JVMCI mode of "' + jvmciMode + '"')
109            jvmciMode = newJvmciMode
110        debugLevel = _translateLegacyDebugLevel(debugLevel)
111        assert jvmVariant is None or jvmVariant in _jdkJvmVariants, jvmVariant
112        assert debugLevel is None or debugLevel in _jdkDebugLevels, debugLevel
113        assert jvmciMode is None or jvmciMode in _jvmciModes, jvmciMode
114        self.jvmVariant = jvmVariant or _vm.jvmVariant
115        self.debugLevel = debugLevel or _vm.debugLevel
116        self.jvmciMode = jvmciMode or _vm.jvmciMode
117
118    def __enter__(self):
119        global _vm
120        self.previousVm = _vm
121        _vm = self
122
123    def __exit__(self, exc_type, exc_value, traceback):
124        global _vm
125        _vm = self.previousVm
126
127_vm = VM(jvmVariant=_jdkJvmVariants[0], debugLevel=_jdkDebugLevels[0], jvmciMode='hosted')
128
129def get_vm():
130    """
131    Gets the configured VM.
132    """
133    return _vm
134
135def relativeVmLibDirInJdk():
136    mxos = mx.get_os()
137    if mxos == 'darwin':
138        return join('lib')
139    if mxos == 'windows' or mxos == 'cygwin':
140        return join('bin')
141    return join('lib', mx.get_arch())
142
143def isJVMCIEnabled(vm):
144    assert vm in _jdkJvmVariants
145    return True
146
147def _makehelp():
148    return subprocess.check_output([mx.gmake_cmd(), 'help'], cwd=_jdkSourceRoot)
149
150def _runmake(args):
151    """run the JDK make process
152
153To build hotspot and import it into the JDK: "mx make hotspot import-hotspot"
154{0}"""
155
156    jdkBuildDir = _get_jdk_build_dir()
157    if not exists(jdkBuildDir):
158        # JDK9 must be bootstrapped with a JDK8
159        compliance = mx.JavaCompliance('8')
160        jdk8 = mx.get_jdk(compliance.exactMatch, versionDescription=compliance.value)
161        cmd = ['sh', 'configure', '--with-debug-level=' + _vm.debugLevel, '--with-native-debug-symbols=external', '--disable-precompiled-headers', '--with-jvm-features=graal',
162               '--with-jvm-variants=' + _vm.jvmVariant, '--disable-warnings-as-errors', '--with-boot-jdk=' + jdk8.home, '--with-jvm-features=graal']
163        mx.run(cmd, cwd=_jdkSourceRoot)
164    cmd = [mx.gmake_cmd(), 'CONF=' + _vm.debugLevel]
165    if mx.get_opts().verbose:
166        cmd.append('LOG=debug')
167    cmd.extend(args)
168    if mx.get_opts().use_jdk_image and 'images' not in args:
169        cmd.append('images')
170
171    if not mx.get_opts().verbose:
172        mx.log('--------------- make execution ----------------------')
173        mx.log('Working directory: ' + _jdkSourceRoot)
174        mx.log('Command line: ' + ' '.join(cmd))
175        mx.log('-----------------------------------------------------')
176
177    mx.run(cmd, cwd=_jdkSourceRoot)
178
179def _runmultimake(args):
180    """run the JDK make process for one or more configurations"""
181
182    jvmVariantsDefault = ','.join(_jdkJvmVariants)
183    debugLevelsDefault = ','.join(_jdkDebugLevels)
184
185    parser = ArgumentParser(prog='mx multimake')
186    parser.add_argument('--jdk-jvm-variants', '--vms', help='a comma separated list of VMs to build (default: ' + jvmVariantsDefault + ')', metavar='<args>', default=jvmVariantsDefault)
187    parser.add_argument('--jdk-debug-levels', '--builds', help='a comma separated list of JDK debug levels (default: ' + debugLevelsDefault + ')', metavar='<args>', default=debugLevelsDefault)
188    parser.add_argument('-n', '--no-check', action='store_true', help='omit running "java -version" after each build')
189    select = parser.add_mutually_exclusive_group()
190    select.add_argument('-c', '--console', action='store_true', help='send build output to console instead of log files')
191    select.add_argument('-d', '--output-dir', help='directory for log files instead of current working directory', default=os.getcwd(), metavar='<dir>')
192
193    args = parser.parse_args(args)
194    jvmVariants = args.jdk_jvm_variants.split(',')
195    debugLevels = [_translateLegacyDebugLevel(dl) for dl in args.jdk_debug_levels.split(',')]
196
197    allStart = time.time()
198    for jvmVariant in jvmVariants:
199        for debugLevel in debugLevels:
200            if not args.console:
201                logFile = join(mx.ensure_dir_exists(args.output_dir), jvmVariant + '-' + debugLevel + '.log')
202                log = open(logFile, 'wb')
203                start = time.time()
204                mx.log('BEGIN: ' + jvmVariant + '-' + debugLevel + '\t(see: ' + logFile + ')')
205                verbose = ['-v'] if mx.get_opts().verbose else []
206                # Run as subprocess so that output can be directed to a file
207                cmd = [sys.executable, '-u', mx.__file__] + verbose + ['--jdk-jvm-variant=' + jvmVariant, '--jdk-debug-level=' + debugLevel, 'make']
208                mx.logv("executing command: " + str(cmd))
209                subprocess.check_call(cmd, cwd=_suite.dir, stdout=log, stderr=subprocess.STDOUT)
210                duration = datetime.timedelta(seconds=time.time() - start)
211                mx.log('END:   ' + jvmVariant + '-' + debugLevel + '\t[' + str(duration) + ']')
212            else:
213                with VM(jvmVariant=jvmVariant, debugLevel=debugLevel):
214                    _runmake([])
215            if not args.no_check:
216                with VM(jvmciMode='jit'):
217                    run_vm(['-XX:-BootstrapJVMCI', '-version'])
218    allDuration = datetime.timedelta(seconds=time.time() - allStart)
219    mx.log('TOTAL TIME:   ' + '[' + str(allDuration) + ']')
220
221class HotSpotProject(mx.NativeProject):
222    """
223    Defines a NativeProject representing the HotSpot binaries built via make.
224    """
225    def __init__(self, suite, name, deps, workingSets, **args):
226        assert name == 'hotspot'
227        mx.NativeProject.__init__(self, suite, name, "", [], deps, workingSets, None, None, join(suite.mxDir, name))
228
229    def eclipse_config_up_to_date(self, configZip):
230        # Assume that any change to this module might imply changes to the generated IDE files
231        if configZip.isOlderThan(__file__):
232            return False
233        for _, source in self._get_eclipse_settings_sources().iteritems():
234            if configZip.isOlderThan(source):
235                return False
236        return True
237
238    def _get_eclipse_settings_sources(self):
239        """
240        Gets a dictionary from the name of an Eclipse settings file to
241        the file providing its generated content.
242        """
243        if not hasattr(self, '_eclipse_settings'):
244            esdict = {}
245            templateSettingsDir = join(self.dir, 'templates', 'eclipse', 'settings')
246            if exists(templateSettingsDir):
247                for name in os.listdir(templateSettingsDir):
248                    source = join(templateSettingsDir, name)
249                    esdict[name] = source
250            self._eclipse_settings = esdict
251        return self._eclipse_settings
252
253    def _eclipseinit(self, files=None, libFiles=None):
254        """
255        Generates an Eclipse project for each HotSpot build configuration.
256        """
257
258        roots = [
259            'ASSEMBLY_EXCEPTION',
260            'LICENSE',
261            'README',
262            'THIRD_PARTY_README',
263            'agent',
264            'make',
265            'src',
266            'test'
267        ]
268
269        for jvmVariant in _jdkJvmVariants:
270            for debugLevel in _jdkDebugLevels:
271                name = jvmVariant + '-' + debugLevel
272                eclProjectDir = join(self.dir, 'eclipse', name)
273                mx.ensure_dir_exists(eclProjectDir)
274
275                out = mx.XMLDoc()
276                out.open('projectDescription')
277                out.element('name', data='hotspot:' + name)
278                out.element('comment', data='')
279                out.element('projects', data='')
280                out.open('buildSpec')
281                out.open('buildCommand')
282                out.element('name', data='org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder')
283                out.element('triggers', data='full,incremental')
284                out.element('arguments', data='')
285                out.close('buildCommand')
286
287                out.close('buildSpec')
288                out.open('natures')
289                out.element('nature', data='org.eclipse.cdt.core.cnature')
290                out.element('nature', data='org.eclipse.cdt.core.ccnature')
291                out.element('nature', data='org.eclipse.cdt.managedbuilder.core.managedBuildNature')
292                out.element('nature', data='org.eclipse.cdt.managedbuilder.core.ScannerConfigNature')
293                out.close('natures')
294
295                if roots:
296                    out.open('linkedResources')
297                    for r in roots:
298                        f = join(_suite.dir, r)
299                        out.open('link')
300                        out.element('name', data=r)
301                        out.element('type', data='2' if isdir(f) else '1')
302                        out.element('locationURI', data=mx.get_eclipse_project_rel_locationURI(f, eclProjectDir))
303                        out.close('link')
304
305                    out.open('link')
306                    out.element('name', data='gensrc')
307                    out.element('type', data='2')
308                    generated = join(_get_hotspot_build_dir(jvmVariant, debugLevel), 'gensrc')
309                    out.element('locationURI', data=mx.get_eclipse_project_rel_locationURI(generated, eclProjectDir))
310                    out.close('link')
311
312                    out.close('linkedResources')
313                out.close('projectDescription')
314                projectFile = join(eclProjectDir, '.project')
315                mx.update_file(projectFile, out.xml(indent='\t', newl='\n'))
316                if files:
317                    files.append(projectFile)
318
319                cprojectTemplate = join(self.dir, 'templates', 'eclipse', 'cproject')
320                cprojectFile = join(eclProjectDir, '.cproject')
321                with open(cprojectTemplate) as f:
322                    content = f.read()
323                mx.update_file(cprojectFile, content)
324                if files:
325                    files.append(cprojectFile)
326
327                settingsDir = join(eclProjectDir, ".settings")
328                mx.ensure_dir_exists(settingsDir)
329                for name, source in self._get_eclipse_settings_sources().iteritems():
330                    out = StringIO.StringIO()
331                    print >> out, '# GENERATED -- DO NOT EDIT'
332                    print >> out, '# Source:', source
333                    with open(source) as f:
334                        print >> out, f.read()
335                    content = out.getvalue()
336                    mx.update_file(join(settingsDir, name), content)
337                    if files:
338                        files.append(join(settingsDir, name))
339
340    def getBuildTask(self, args):
341        return JDKBuildTask(self, args, _vm.debugLevel, _vm.jvmVariant)
342
343
344class JDKBuildTask(mx.NativeBuildTask):
345    def __init__(self, project, args, debugLevel, jvmVariant):
346        mx.NativeBuildTask.__init__(self, args, project)
347        self.jvmVariant = jvmVariant
348        self.debugLevel = debugLevel
349
350    def __str__(self):
351        return 'Building JDK[{}, {}]'.format(self.debugLevel, self.jvmVariant)
352
353    def build(self):
354        if mx.get_opts().use_jdk_image:
355            _runmake(['images'])
356        else:
357            _runmake([])
358        self._newestOutput = None
359
360    def clean(self, forBuild=False):
361        if forBuild:  # Let make handle incremental builds
362            return
363        if exists(_get_jdk_build_dir(self.debugLevel)):
364            _runmake(['clean'])
365        self._newestOutput = None
366
367# Backwards compatibility for mx_jvmci:8 API
368def buildvms(args):
369    _runmultimake(args)
370
371def run_vm(args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, debugLevel=None, vmbuild=None):
372    """run a Java program by executing the java executable in a JVMCI JDK"""
373    jdkTag = mx.get_jdk_option().tag
374    if jdkTag and jdkTag != _JVMCI_JDK_TAG:
375        mx.abort('The "--jdk" option must have the tag "' + _JVMCI_JDK_TAG + '" when running a command requiring a JVMCI VM')
376    jdk = get_jvmci_jdk(debugLevel=debugLevel or _translateLegacyDebugLevel(vmbuild))
377    return jdk.run_java(args, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout)
378
379def _unittest_vm_launcher(vmArgs, mainClass, mainClassArgs):
380    run_vm(vmArgs + [mainClass] + mainClassArgs)
381
382mx_unittest.set_vm_launcher('JVMCI VM launcher', _unittest_vm_launcher)
383
384def _jvmci_gate_runner(args, tasks):
385    # Build release server VM now so we can run the unit tests
386    with Task('BuildHotSpotJVMCIHosted: release', tasks) as t:
387        if t: _runmultimake(['--jdk-jvm-variants', 'server', '--jdk-debug-levels', 'release'])
388
389    # Run unit tests in hosted mode
390    with VM(jvmVariant='server', debugLevel='release', jvmciMode='hosted'):
391        with Task('JVMCI UnitTests: hosted-release', tasks) as t:
392            if t: unittest(['--suite', 'jvmci', '--enable-timing', '--verbose', '--fail-fast'])
393
394    # Build the other VM flavors
395    with Task('BuildHotSpotJVMCIOthers: fastdebug', tasks) as t:
396        if t: _runmultimake(['--jdk-jvm-variants', 'server', '--jdk-debug-levels', 'fastdebug'])
397
398    with Task('CleanAndBuildIdealGraphVisualizer', tasks, disableJacoco=True) as t:
399        if t and platform.processor() != 'sparc':
400            buildxml = mx._cygpathU2W(join(_suite.dir, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml'))
401            mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'], env=_igvBuildEnv())
402
403mx_gate.add_gate_runner(_suite, _jvmci_gate_runner)
404mx_gate.add_gate_argument('-g', '--only-build-jvmci', action='store_false', dest='buildNonJVMCI', help='only build the JVMCI VM')
405
406def _igvJdk():
407    v8u20 = mx.VersionSpec("1.8.0_20")
408    v8u40 = mx.VersionSpec("1.8.0_40")
409    v8 = mx.VersionSpec("1.8")
410    def _igvJdkVersionCheck(version):
411        return version >= v8 and (version < v8u20 or version >= v8u40)
412    return mx.get_jdk(_igvJdkVersionCheck, versionDescription='>= 1.8 and < 1.8.0u20 or >= 1.8.0u40', purpose="building & running IGV").home
413
414def _igvBuildEnv():
415        # When the http_proxy environment variable is set, convert it to the proxy settings that ant needs
416    env = dict(os.environ)
417    proxy = os.environ.get('http_proxy')
418    if not (proxy is None) and len(proxy) > 0:
419        if '://' in proxy:
420            # Remove the http:// prefix (or any other protocol prefix)
421            proxy = proxy.split('://', 1)[1]
422        # Separate proxy server name and port number
423        proxyName, proxyPort = proxy.split(':', 1)
424        proxyEnv = '-DproxyHost="' + proxyName + '" -DproxyPort=' + proxyPort
425        env['ANT_OPTS'] = proxyEnv
426
427    env['JAVA_HOME'] = _igvJdk()
428    return env
429
430def igv(args):
431    """run the Ideal Graph Visualizer"""
432    logFile = '.ideal_graph_visualizer.log'
433    with open(join(_suite.dir, logFile), 'w') as fp:
434        mx.logv('[Ideal Graph Visualizer log is in ' + fp.name + ']')
435        nbplatform = join(_suite.dir, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'nbplatform')
436
437        # Remove NetBeans platform if it is earlier than the current supported version
438        if exists(nbplatform):
439            updateTrackingFile = join(nbplatform, 'platform', 'update_tracking', 'org-netbeans-core.xml')
440            if not exists(updateTrackingFile):
441                mx.log('Could not find \'' + updateTrackingFile + '\', removing NetBeans platform')
442                shutil.rmtree(nbplatform)
443            else:
444                dom = xml.dom.minidom.parse(updateTrackingFile)
445                currentVersion = mx.VersionSpec(dom.getElementsByTagName('module_version')[0].getAttribute('specification_version'))
446                supportedVersion = mx.VersionSpec('3.43.1')
447                if currentVersion < supportedVersion:
448                    mx.log('Replacing NetBeans platform version ' + str(currentVersion) + ' with version ' + str(supportedVersion))
449                    shutil.rmtree(nbplatform)
450                elif supportedVersion < currentVersion:
451                    mx.log('Supported NetBeans version in igv command should be updated to ' + str(currentVersion))
452
453        if not exists(nbplatform):
454            mx.logv('[This execution may take a while as the NetBeans platform needs to be downloaded]')
455
456        env = _igvBuildEnv()
457        # make the jar for Batik 1.7 available.
458        env['IGV_BATIK_JAR'] = mx.library('BATIK').get_path(True)
459        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):
460            mx.abort("IGV ant build & launch failed. Check '" + logFile + "'. You can also try to delete 'src/share/tools/IdealGraphVisualizer/nbplatform'.")
461
462def c1visualizer(args):
463    """run the Cl Compiler Visualizer"""
464    libpath = join(_suite.dir, 'lib')
465    if mx.get_os() == 'windows':
466        executable = join(libpath, 'c1visualizer', 'bin', 'c1visualizer.exe')
467    else:
468        executable = join(libpath, 'c1visualizer', 'bin', 'c1visualizer')
469
470    # Check whether the current C1Visualizer installation is the up-to-date
471    if exists(executable) and not exists(mx.library('C1VISUALIZER_DIST').get_path(resolve=False)):
472        mx.log('Updating C1Visualizer')
473        shutil.rmtree(join(libpath, 'c1visualizer'))
474
475    archive = mx.library('C1VISUALIZER_DIST').get_path(resolve=True)
476
477    if not exists(executable):
478        zf = zipfile.ZipFile(archive, 'r')
479        zf.extractall(libpath)
480
481    if not exists(executable):
482        mx.abort('C1Visualizer binary does not exist: ' + executable)
483
484    if mx.get_os() != 'windows':
485        # Make sure that execution is allowed. The zip file does not always specfiy that correctly
486        os.chmod(executable, 0777)
487
488    mx.run([executable])
489
490def hsdis(args, copyToDir=None):
491    """download the hsdis library
492
493    This is needed to support HotSpot's assembly dumping features.
494    By default it downloads the Intel syntax version, use the 'att' argument to install AT&T syntax."""
495    flavor = 'intel'
496    if 'att' in args:
497        flavor = 'att'
498    if mx.get_arch() == "sparcv9":
499        flavor = "sparcv9"
500    lib = mx.add_lib_suffix('hsdis-' + mx.get_arch())
501    path = join(_suite.dir, 'lib', lib)
502
503    sha1s = {
504        'att/hsdis-amd64.dll' : 'bcbd535a9568b5075ab41e96205e26a2bac64f72',
505        'att/hsdis-amd64.so' : '58919ba085d4ef7a513f25bae75e7e54ee73c049',
506        'intel/hsdis-amd64.dll' : '6a388372cdd5fe905c1a26ced614334e405d1f30',
507        'intel/hsdis-amd64.so' : '844ed9ffed64fe9599638f29a8450c50140e3192',
508        'intel/hsdis-amd64.dylib' : 'fdb13ef0d7d23d93dacaae9c98837bea0d4fc5a2',
509        'sparcv9/hsdis-sparcv9.so': '970640a9af0bd63641f9063c11275b371a59ee60',
510    }
511
512    flavoredLib = flavor + "/" + lib
513    if flavoredLib not in sha1s:
514        mx.logv("hsdis not supported on this plattform or architecture")
515        return
516
517    if not exists(path):
518        sha1 = sha1s[flavoredLib]
519        sha1path = path + '.sha1'
520        mx.download_file_with_sha1('hsdis', path, ['https://lafo.ssw.uni-linz.ac.at/pub/hsdis/' + flavoredLib], sha1, sha1path, True, True, sources=False)
521    if copyToDir is not None and exists(copyToDir):
522        shutil.copy(path, copyToDir)
523
524def hcfdis(args):
525    """disassemble HexCodeFiles embedded in text files
526
527    Run a tool over the input files to convert all embedded HexCodeFiles
528    to a disassembled format."""
529
530    parser = ArgumentParser(prog='mx hcfdis')
531    parser.add_argument('-m', '--map', help='address to symbol map applied to disassembler output')
532    parser.add_argument('files', nargs=REMAINDER, metavar='files...')
533
534    args = parser.parse_args(args)
535
536    path = mx.library('HCFDIS').get_path(resolve=True)
537    mx.run_java(['-cp', path, 'com.oracle.max.hcfdis.HexCodeFileDis'] + args.files)
538
539    if args.map is not None:
540        addressRE = re.compile(r'0[xX]([A-Fa-f0-9]+)')
541        with open(args.map) as fp:
542            lines = fp.read().splitlines()
543        symbols = dict()
544        for l in lines:
545            addressAndSymbol = l.split(' ', 1)
546            if len(addressAndSymbol) == 2:
547                address, symbol = addressAndSymbol
548                if address.startswith('0x'):
549                    address = long(address, 16)
550                    symbols[address] = symbol
551        for f in args.files:
552            with open(f) as fp:
553                lines = fp.read().splitlines()
554            updated = False
555            for i in range(0, len(lines)):
556                l = lines[i]
557                for m in addressRE.finditer(l):
558                    sval = m.group(0)
559                    val = long(sval, 16)
560                    sym = symbols.get(val)
561                    if sym:
562                        l = l.replace(sval, sym)
563                        updated = True
564                        lines[i] = l
565            if updated:
566                mx.log('updating ' + f)
567                with open('new_' + f, "w") as fp:
568                    for l in lines:
569                        print >> fp, l
570
571def jol(args):
572    """Java Object Layout"""
573    joljar = mx.library('JOL_INTERNALS').get_path(resolve=True)
574    candidates = mx.findclass(args, logToConsole=False, matcher=lambda s, classname: s == classname or classname.endswith('.' + s) or classname.endswith('$' + s))
575
576    if len(candidates) > 0:
577        candidates = mx.select_items(sorted(candidates))
578    else:
579        # mx.findclass can be mistaken, don't give up yet
580        candidates = args
581
582    run_vm(['-javaagent:' + joljar, '-cp', os.pathsep.join([mx.classpath(), joljar]), "org.openjdk.jol.MainObjectInternals"] + candidates)
583
584def _get_openjdk_os():
585    # See: common/autoconf/platform.m4
586    os = mx.get_os()
587    if 'darwin' in os:
588        os = 'macosx'
589    elif 'linux' in os:
590        os = 'linux'
591    elif 'solaris' in os:
592        os = 'solaris'
593    elif 'cygwin' in os or 'mingw' in os:
594        os = 'windows'
595    return os
596
597def _get_openjdk_cpu():
598    cpu = mx.get_arch()
599    if cpu == 'amd64':
600        cpu = 'x86_64'
601    elif cpu == 'sparcv9':
602        cpu = 'sparcv9'
603    return cpu
604
605def _get_openjdk_os_cpu():
606    return _get_openjdk_os() + '-' + _get_openjdk_cpu()
607
608def _get_jdk_build_dir(debugLevel=None):
609    """
610    Gets the directory into which the JDK is built. This directory contains
611    the exploded JDK under jdk/ and the JDK image under images/jdk/.
612    """
613    if debugLevel is None:
614        debugLevel = _vm.debugLevel
615    name = '{}-{}-{}-{}'.format(_get_openjdk_os_cpu(), 'normal', _vm.jvmVariant, debugLevel)
616    return join(dirname(_suite.dir), 'build', name)
617
618_jvmci_bootclasspath_prepends = []
619
620def _get_hotspot_build_dir(jvmVariant=None, debugLevel=None):
621    """
622    Gets the directory in which a particular HotSpot configuration is built
623    (e.g., <JDK_REPO_ROOT>/build/macosx-x86_64-normal-server-release/hotspot/variant-<variant>)
624    """
625    if jvmVariant is None:
626        jvmVariant = _vm.jvmVariant
627
628    name = 'variant-{}'.format(jvmVariant)
629    return join(_get_jdk_build_dir(debugLevel=debugLevel), 'hotspot', name)
630
631class JVMCI9JDKConfig(mx.JDKConfig):
632    def __init__(self, debugLevel):
633        self.debugLevel = debugLevel
634        jdkBuildDir = _get_jdk_build_dir(debugLevel)
635        jdkDir = join(jdkBuildDir, 'images', 'jdk') if mx.get_opts().use_jdk_image else join(jdkBuildDir, 'jdk')
636        mx.JDKConfig.__init__(self, jdkDir, tag=_JVMCI_JDK_TAG)
637
638    def parseVmArgs(self, args, addDefaultArgs=True):
639        args = mx.expand_project_in_args(args, insitu=False)
640        jacocoArgs = mx_gate.get_jacoco_agent_args()
641        if jacocoArgs:
642            args = jacocoArgs + args
643
644        args = ['-Xbootclasspath/p:' + dep.classpath_repr() for dep in _jvmci_bootclasspath_prepends] + args
645
646        # Remove JVMCI jars from class path. They are only necessary when
647        # compiling with a javac from JDK8 or earlier.
648        cpIndex, cp = mx.find_classpath_arg(args)
649        if cp:
650            excluded = frozenset([dist.path for dist in _suite.dists])
651            cp = os.pathsep.join([e for e in cp.split(os.pathsep) if e not in excluded])
652            args[cpIndex] = cp
653
654        if '-version' in args:
655            ignoredArgs = args[args.index('-version') + 1:]
656            if  len(ignoredArgs) > 0:
657                mx.log("Warning: The following options will be ignored by the vm because they come after the '-version' argument: " + ' '.join(ignoredArgs))
658        return self.processArgs(args, addDefaultArgs=addDefaultArgs)
659
660    # Overrides JDKConfig
661    def run_java(self, args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, env=None, addDefaultArgs=True):
662        if vm is None:
663            vm = 'server'
664
665        args = self.parseVmArgs(args, addDefaultArgs=addDefaultArgs)
666
667        jvmciModeArgs = _jvmciModes[_vm.jvmciMode]
668        cmd = [self.java] + ['-' + vm] + jvmciModeArgs + args
669        return mx.run(cmd, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd)
670
671"""
672The dict of JVMCI JDKs indexed by debug-level names.
673"""
674_jvmci_jdks = {}
675
676def get_jvmci_jdk(debugLevel=None):
677    """
678    Gets the JVMCI JDK corresponding to 'debugLevel'.
679    """
680    if not debugLevel:
681        debugLevel = _vm.debugLevel
682    jdk = _jvmci_jdks.get(debugLevel)
683    if jdk is None:
684        try:
685            jdk = JVMCI9JDKConfig(debugLevel)
686        except mx.JDKConfigException as e:
687            jdkBuildDir = _get_jdk_build_dir(debugLevel)
688            msg = 'Error with the JDK built into {}:\n{}\nTry (re)building it with: mx --jdk-debug-level={} make'
689            if mx.get_opts().use_jdk_image:
690                msg += ' images'
691            mx.abort(msg.format(jdkBuildDir, e.message, debugLevel))
692        _jvmci_jdks[debugLevel] = jdk
693    return jdk
694
695class JVMCI9JDKFactory(mx.JDKFactory):
696    def getJDKConfig(self):
697        jdk = get_jvmci_jdk(_vm.debugLevel)
698        return jdk
699
700    def description(self):
701        return "JVMCI JDK"
702
703mx.update_commands(_suite, {
704    'make': [_runmake, '[args...]', _makehelp],
705    'multimake': [_runmultimake, '[options]'],
706    'c1visualizer' : [c1visualizer, ''],
707    'hsdis': [hsdis, '[att]'],
708    'hcfdis': [hcfdis, ''],
709    'igv' : [igv, ''],
710    'jol' : [jol, ''],
711    'vm': [run_vm, '[-options] class [args...]'],
712})
713
714mx.add_argument('-M', '--jvmci-mode', action='store', choices=sorted(_jvmciModes.viewkeys()), help='the JVM variant type to build/run (default: ' + _vm.jvmciMode + ')')
715mx.add_argument('--jdk-jvm-variant', '--vm', action='store', choices=_jdkJvmVariants + sorted(_legacyVms.viewkeys()), help='the JVM variant type to build/run (default: ' + _vm.jvmVariant + ')')
716mx.add_argument('--jdk-debug-level', '--vmbuild', action='store', choices=_jdkDebugLevels + sorted(_legacyVmbuilds.viewkeys()), help='the JDK debug level to build/run (default: ' + _vm.debugLevel + ')')
717mx.add_argument('-I', '--use-jdk-image', action='store_true', help='build/run JDK image instead of exploded JDK')
718
719mx.addJDKFactory(_JVMCI_JDK_TAG, mx.JavaCompliance('9'), JVMCI9JDKFactory())
720
721def mx_post_parse_cmd_line(opts):
722    mx.set_java_command_default_jdk_tag(_JVMCI_JDK_TAG)
723
724    jdkTag = mx.get_jdk_option().tag
725
726    jvmVariant = None
727    debugLevel = None
728    jvmciMode = None
729
730    if opts.jdk_jvm_variant is not None:
731        jvmVariant = opts.jdk_jvm_variant
732        if jdkTag and jdkTag != _JVMCI_JDK_TAG:
733            mx.warn('Ignoring "--jdk-jvm-variant" option as "--jdk" tag is not "' + _JVMCI_JDK_TAG + '"')
734
735    if opts.jdk_debug_level is not None:
736        debugLevel = _translateLegacyDebugLevel(opts.jdk_debug_level)
737        if jdkTag and jdkTag != _JVMCI_JDK_TAG:
738            mx.warn('Ignoring "--jdk-debug-level" option as "--jdk" tag is not "' + _JVMCI_JDK_TAG + '"')
739
740    if opts.jvmci_mode is not None:
741        jvmciMode = opts.jvmci_mode
742        if jdkTag and jdkTag != _JVMCI_JDK_TAG:
743            mx.warn('Ignoring "--jvmci-mode" option as "--jdk" tag is not "' + _JVMCI_JDK_TAG + '"')
744
745    _vm.update(jvmVariant, debugLevel, jvmciMode)
746