mx_jvmci.py revision 10019:2c4e0146b775
1189251Ssam# 2189251Ssam# ---------------------------------------------------------------------------------------------------- 3281806Srpaulo# 4189251Ssam# Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. 5252726Srpaulo# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6252726Srpaulo# 7189251Ssam# This code is free software; you can redistribute it and/or modify it 8189251Ssam# under the terms of the GNU General Public License version 2 only, as 9189251Ssam# published by the Free Software Foundation. 10189251Ssam# 11189251Ssam# This code is distributed in the hope that it will be useful, but WITHOUT 12189251Ssam# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13281806Srpaulo# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14189251Ssam# version 2 for more details (a copy is included in the LICENSE file that 15189251Ssam# accompanied this code). 16189251Ssam# 17189251Ssam# You should have received a copy of the GNU General Public License version 18189251Ssam# 2 along with this work; if not, write to the Free Software Foundation, 19189251Ssam# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20189251Ssam# 21189251Ssam# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22189251Ssam# or visit www.oracle.com if you need additional information or have any 23189251Ssam# questions. 24189251Ssam# 25189251Ssam# ---------------------------------------------------------------------------------------------------- 26189251Ssam 27189251Ssamimport os, shutil, zipfile, re, time, sys, datetime, platform 28189251Ssamfrom os.path import join, exists, dirname, isdir 29189251Ssamfrom argparse import ArgumentParser, REMAINDER 30189251Ssamimport StringIO 31189251Ssamimport xml.dom.minidom 32189251Ssamimport subprocess 33189251Ssam 34189251Ssamimport mx 35189251Ssamimport mx_gate 36189251Ssamimport mx_unittest 37189251Ssam 38189251Ssamfrom mx_gate import Task 39189251Ssamfrom mx_unittest import unittest 40189251Ssam 41189251Ssam_suite = mx.suite('jvmci') 42189251Ssam 43189251Ssam""" 44189251SsamTop level directory of the JDK source workspace. 45189251Ssam""" 46189251Ssam_jdkSourceRoot = dirname(_suite.dir) 47189251Ssam 48189251Ssam_JVMCI_JDK_TAG = 'jvmci' 49189251Ssam 50189251Ssam_minVersion = mx.VersionSpec('1.9') 51189251Ssam 52189251Ssam# max version (first _unsupported_ version) 53189251Ssam_untilVersion = None 54189251Ssam 55189251Ssam_jvmciModes = { 56189251Ssam 'hosted' : ['-XX:+UnlockExperimentalVMOptions', '-XX:+EnableJVMCI'], 57189251Ssam 'jit' : ['-XX:+UnlockExperimentalVMOptions', '-XX:+EnableJVMCI', '-XX:+UseJVMCICompiler'], 58189251Ssam 'disabled' : [] 59189251Ssam} 60189251Ssam 61189251Ssam# TODO: can optimized be built without overriding release build? 62189251Ssam_jdkDebugLevels = ['release', 'fastdebug', 'slowdebug'] 63189251Ssam 64189251Ssam# TODO: add client once/if it can be built on 64-bit platforms 65189251Ssam_jdkJvmVariants = ['server'] 66189251Ssam 67189251Ssam""" 68189251SsamTranslation table from mx_jvmci:8 --vmbuild values to mx_jvmci:9 --jdk-debug-level values. 69189251Ssam""" 70189251Ssam_legacyVmbuilds = { 71189251Ssam 'product' : 'release', 72189251Ssam 'debug' : 'slowdebug' 73189251Ssam} 74189251Ssam 75189251Ssam""" 76189251SsamTranslates a mx_jvmci:8 --vmbuild value to a mx_jvmci:9 --jdk-debug-level value. 77189251Ssam""" 78189251Ssamdef _translateLegacyDebugLevel(debugLevel): 79189251Ssam return _legacyVmbuilds.get(debugLevel, debugLevel) 80189251Ssam 81189251Ssam""" 82189251SsamTranslation table from mx_jvmci:8 --vm values to mx_jvmci:9 (--jdk-jvm-variant, --jvmci-mode) tuples. 83189251Ssam""" 84189251Ssam_legacyVms = { 85189251Ssam 'jvmci' : ('server', 'jit') 86189251Ssam} 87189251Ssam 88189251Ssam""" 89189251SsamA VM configuration composed of a JDK debug level, JVM variant and a JVMCI mode. 90189251SsamThis is also a context manager that can be used with the 'with' statement to set/change 91189251Ssama VM configuration within a dynamic scope. For example: 92189251Ssam 93189251Ssam with ConfiguredJDK(debugLevel='fastdebug'): 94189251Ssam dacapo(['pmd']) 95189251Ssam""" 96189251Ssamclass VM: 97189251Ssam def __init__(self, jvmVariant=None, debugLevel=None, jvmciMode=None): 98189251Ssam self.update(jvmVariant, debugLevel, jvmciMode) 99189251Ssam 100189251Ssam def update(self, jvmVariant=None, debugLevel=None, jvmciMode=None): 101189251Ssam if jvmVariant in _legacyVms: 102189251Ssam # Backwards compatibility for mx_jvmci:8 API 103189251Ssam jvmVariant, newJvmciMode = _legacyVms[jvmVariant] 104189251Ssam if jvmciMode is not None and jvmciMode != newJvmciMode: 105189251Ssam mx.abort('JVM variant "' + jvmVariant + '" implies JVMCI mode "' + newJvmciMode + 106189251Ssam '" which conflicts with explicitly specified JVMCI mode of "' + jvmciMode + '"') 107189251Ssam jvmciMode = newJvmciMode 108189251Ssam debugLevel = _translateLegacyDebugLevel(debugLevel) 109189251Ssam assert jvmVariant is None or jvmVariant in _jdkJvmVariants, jvmVariant 110189251Ssam assert debugLevel is None or debugLevel in _jdkDebugLevels, debugLevel 111189251Ssam assert jvmciMode is None or jvmciMode in _jvmciModes, jvmciMode 112189251Ssam self.jvmVariant = jvmVariant or _vm.jvmVariant 113189251Ssam self.debugLevel = debugLevel or _vm.debugLevel 114189251Ssam self.jvmciMode = jvmciMode or _vm.jvmciMode 115189251Ssam 116189251Ssam def __enter__(self): 117189251Ssam global _vm 118189251Ssam self.previousVm = _vm 119189251Ssam _vm = self 120189251Ssam 121189251Ssam def __exit__(self, exc_type, exc_value, traceback): 122189251Ssam global _vm 123189251Ssam _vm = self.previousVm 124189251Ssam 125189251Ssam_vm = VM(jvmVariant=_jdkJvmVariants[0], debugLevel=_jdkDebugLevels[0], jvmciMode='hosted') 126189251Ssam 127189251Ssamdef get_vm(): 128189251Ssam """ 129189251Ssam Gets the configured VM. 130189251Ssam """ 131189251Ssam return _vm 132189251Ssam 133189251Ssamdef relativeVmLibDirInJdk(): 134189251Ssam mxos = mx.get_os() 135189251Ssam if mxos == 'darwin': 136189251Ssam return join('lib') 137189251Ssam if mxos == 'windows' or mxos == 'cygwin': 138189251Ssam return join('bin') 139189251Ssam return join('lib', mx.get_arch()) 140189251Ssam 141189251Ssamdef isJVMCIEnabled(vm): 142189251Ssam assert vm in _jdkJvmVariants 143189251Ssam return True 144189251Ssam 145189251Ssamclass JvmciJDKDeployedDist(object): 146189251Ssam def __init__(self, name, compilers=False): 147189251Ssam self._name = name 148189251Ssam self._compilers = compilers 149189251Ssam 150189251Ssam def dist(self): 151189251Ssam return mx.distribution(self._name) 152189251Ssam 153189251Ssam def deploy(self, jdkDir): 154189251Ssam mx.nyi('deploy', self) 155189251Ssam 156189251Ssam def post_parse_cmd_line(self): 157189251Ssam self.set_archiveparticipant() 158189251Ssam 159189251Ssam def set_archiveparticipant(self): 160189251Ssam dist = self.dist() 161189251Ssam dist.set_archiveparticipant(JVMCIArchiveParticipant(dist)) 162189251Ssam 163189251Ssamclass ExtJDKDeployedDist(JvmciJDKDeployedDist): 164189251Ssam def __init__(self, name): 165189251Ssam JvmciJDKDeployedDist.__init__(self, name) 166189251Ssam 167189251Ssam 168189251Ssam""" 169189251SsamThe monolithic JVMCI distribution is deployed through use of -Xbootclasspath/p 170189251Ssamso that it's not necessary to run JDK make after editing JVMCI sources. 171189251SsamThe latter causes all JDK Java sources to be rebuilt since JVMCI is 172189251Ssam(currently) in java.base. 173189251Ssam""" 174189251Ssam_monolithicJvmci = JvmciJDKDeployedDist('JVMCI') 175189251Ssam 176189251Ssam""" 177189251SsamList of distributions that are deployed on the boot class path. 178189251SsamNote: In jvmci-8, they were deployed directly into the JDK directory. 179189251Ssam""" 180189251SsamjdkDeployedDists = [_monolithicJvmci] 181189251Ssam 182189251Ssamdef _makehelp(): 183189251Ssam return subprocess.check_output([mx.gmake_cmd(), 'help'], cwd=_jdkSourceRoot) 184189251Ssam 185189251Ssamdef _runmake(args): 186189251Ssam """run the JDK make process 187189251Ssam 188189251SsamTo build hotspot and import it into the JDK: "mx make hotspot import-hotspot" 189189251Ssam{0}""" 190189251Ssam 191189251Ssam jdkBuildDir = _get_jdk_build_dir() 192189251Ssam if not exists(jdkBuildDir): 193189251Ssam # JDK9 must be bootstrapped with a JDK8 194189251Ssam compliance = mx.JavaCompliance('8') 195189251Ssam jdk8 = mx.get_jdk(compliance.exactMatch, versionDescription=compliance.value) 196189251Ssam cmd = ['sh', 'configure', '--with-debug-level=' + _vm.debugLevel, '--disable-debug-symbols', '--disable-precompiled-headers', 197189251Ssam '--with-jvm-variants=' + _vm.jvmVariant, '--disable-warnings-as-errors', '--with-boot-jdk=' + jdk8.home] 198189251Ssam mx.run(cmd, cwd=_jdkSourceRoot) 199189251Ssam cmd = [mx.gmake_cmd(), 'CONF=' + _vm.debugLevel] 200189251Ssam if mx.get_opts().verbose: 201189251Ssam cmd.append('LOG=debug') 202189251Ssam cmd.extend(args) 203189251Ssam if mx.get_opts().use_jdk_image and 'images' not in args: 204189251Ssam cmd.append('images') 205189251Ssam 206189251Ssam if not mx.get_opts().verbose: 207189251Ssam mx.log('--------------- make execution ----------------------') 208189251Ssam mx.log('Working directory: ' + _jdkSourceRoot) 209189251Ssam mx.log('Command line: ' + ' '.join(cmd)) 210189251Ssam mx.log('-----------------------------------------------------') 211189251Ssam 212189251Ssam mx.run(cmd, cwd=_jdkSourceRoot) 213189251Ssam 214189251Ssam if 'images' in cmd: 215189251Ssam _create_jdk_bundle(jdkBuildDir) 216189251Ssam 217189251Ssamdef _get_jdk_bundle_arches(): 218189251Ssam """ 219189251Ssam Gets a list of names that will be the part of a JDK bundle's file name denoting the architecture. 220189251Ssam The first element in the list is the canonical name. Symlinks should be created for the 221189251Ssam remaining names. 222189251Ssam """ 223189251Ssam cpu = mx.get_arch() 224189251Ssam if cpu == 'amd64': 225189251Ssam return ['x64', 'x86_64', 'amd64'] 226189251Ssam elif cpu == 'sparcv9': 227189251Ssam return ['sparcv9'] 228189251Ssam mx.abort('Unsupported JDK bundle arch: ' + cpu) 229189251Ssam 230189251Ssamdef _create_jdk_bundle(jdkBuildDir): 231189251Ssam """ 232189251Ssam Creates a tar.gz JDK archive, an accompanying tar.gz.sha1 file with its 233189251Ssam SHA1 signature plus symlinks to the archive for non-canonical architecture names. 234189251Ssam """ 235189251Ssam jdkImageDir = join(jdkBuildDir, 'images', 'jdk') 236189251Ssam 237189251Ssam arches = _get_jdk_bundle_arches() 238189251Ssam jdkTgzPath = join(_suite.get_output_root(), 'jdk-bundles', 'jdk9-{}-{}.tar.gz'.format(_get_openjdk_os(), arches[0])) 239189251Ssam with mx.Archiver(jdkTgzPath, kind='tgz') as arc: 240189251Ssam mx.log('Creating ' + jdkTgzPath) 241189251Ssam for root, _, filenames in os.walk(jdkImageDir): 242189251Ssam for name in filenames: 243189251Ssam f = join(root, name) 244189251Ssam arcname = 'jdk1.9.0/' + os.path.relpath(f, jdkImageDir) 245189251Ssam arc.zf.add(name=f, arcname=arcname, recursive=False) 246189251Ssam # The OpenJDK build creates an empty cacerts file so grab one from 247189251Ssam # the default JDK which is assumed to be an OracleJDK 248189251Ssam cacerts = join(mx.get_jdk(tag='default').home, 'jre', 'lib', 'security', 'cacerts') 249189251Ssam arc.zf.add(name=cacerts, arcname='jdk1.9.0/lib/security/cacerts') 250189251Ssam 251189251Ssam with open(jdkTgzPath + '.sha1', 'w') as fp: 252189251Ssam mx.log('Creating ' + jdkTgzPath + '.sha1') 253189251Ssam fp.write(mx.sha1OfFile(jdkTgzPath)) 254189251Ssam 255189251Ssam def _create_link(source, link_name): 256189251Ssam if exists(link_name): 257189251Ssam os.remove(link_name) 258189251Ssam mx.log('Creating ' + link_name + ' -> ' + source) 259189251Ssam os.symlink(source, link_name) 260189251Ssam 261189251Ssam for arch in arches[1:]: 262189251Ssam link_name = join(_suite.get_output_root(), 'jdk-bundles', 'jdk9-{}-{}.tar.gz'.format(_get_openjdk_os(), arch)) 263189251Ssam jdkTgzName = os.path.basename(jdkTgzPath) 264189251Ssam _create_link(jdkTgzName, link_name) 265281806Srpaulo _create_link(jdkTgzName + '.sha1', link_name + '.sha1') 266281806Srpaulo 267281806Srpaulodef _runmultimake(args): 268281806Srpaulo """run the JDK make process for one or more configurations""" 269281806Srpaulo 270281806Srpaulo jvmVariantsDefault = ','.join(_jdkJvmVariants) 271281806Srpaulo debugLevelsDefault = ','.join(_jdkDebugLevels) 272281806Srpaulo 273281806Srpaulo parser = ArgumentParser(prog='mx multimake') 274281806Srpaulo parser.add_argument('--jdk-jvm-variants', '--vms', help='a comma separated list of VMs to build (default: ' + jvmVariantsDefault + ')', metavar='<args>', default=jvmVariantsDefault) 275281806Srpaulo parser.add_argument('--jdk-debug-levels', '--builds', help='a comma separated list of JDK debug levels (default: ' + debugLevelsDefault + ')', metavar='<args>', default=debugLevelsDefault) 276281806Srpaulo parser.add_argument('-n', '--no-check', action='store_true', help='omit running "java -version" after each build') 277281806Srpaulo select = parser.add_mutually_exclusive_group() 278189251Ssam select.add_argument('-c', '--console', action='store_true', help='send build output to console instead of log files') 279189251Ssam select.add_argument('-d', '--output-dir', help='directory for log files instead of current working directory', default=os.getcwd(), metavar='<dir>') 280189251Ssam 281281806Srpaulo args = parser.parse_args(args) 282281806Srpaulo jvmVariants = args.jdk_jvm_variants.split(',') 283281806Srpaulo debugLevels = [_translateLegacyDebugLevel(dl) for dl in args.jdk_debug_levels.split(',')] 284281806Srpaulo 285281806Srpaulo allStart = time.time() 286281806Srpaulo for jvmVariant in jvmVariants: 287281806Srpaulo for debugLevel in debugLevels: 288281806Srpaulo if not args.console: 289281806Srpaulo logFile = join(mx.ensure_dir_exists(args.output_dir), jvmVariant + '-' + debugLevel + '.log') 290281806Srpaulo log = open(logFile, 'wb') 291189251Ssam start = time.time() 292189251Ssam mx.log('BEGIN: ' + jvmVariant + '-' + debugLevel + '\t(see: ' + logFile + ')') 293189251Ssam verbose = ['-v'] if mx.get_opts().verbose else [] 294189251Ssam # Run as subprocess so that output can be directed to a file 295189251Ssam cmd = [sys.executable, '-u', mx.__file__] + verbose + ['--jdk-jvm-variant=' + jvmVariant, '--jdk-debug-level=' + debugLevel, 'make'] 296189251Ssam mx.logv("executing command: " + str(cmd)) 297189251Ssam subprocess.check_call(cmd, cwd=_suite.dir, stdout=log, stderr=subprocess.STDOUT) 298189251Ssam duration = datetime.timedelta(seconds=time.time() - start) 299189251Ssam mx.log('END: ' + jvmVariant + '-' + debugLevel + '\t[' + str(duration) + ']') 300189251Ssam else: 301189251Ssam with VM(jvmVariant=jvmVariant, debugLevel=debugLevel): 302189251Ssam _runmake([]) 303189251Ssam if not args.no_check: 304189251Ssam with VM(jvmciMode='jit'): 305189251Ssam run_vm(['-XX:-BootstrapJVMCI', '-version']) 306189251Ssam allDuration = datetime.timedelta(seconds=time.time() - allStart) 307189251Ssam mx.log('TOTAL TIME: ' + '[' + str(allDuration) + ']') 308189251Ssam 309189251Ssamclass HotSpotProject(mx.NativeProject): 310189251Ssam """ 311189251Ssam Defines a NativeProject representing the HotSpot binaries built via make. 312189251Ssam """ 313189251Ssam def __init__(self, suite, name, deps, workingSets, **args): 314189251Ssam assert name == 'hotspot' 315189251Ssam mx.NativeProject.__init__(self, suite, name, "", [], deps, workingSets, None, None, join(suite.mxDir, name)) 316189251Ssam 317189251Ssam def eclipse_config_up_to_date(self, configZip): 318189251Ssam # Assume that any change to this module might imply changes to the generated IDE files 319189251Ssam if configZip.isOlderThan(__file__): 320189251Ssam return False 321189251Ssam for _, source in self._get_eclipse_settings_sources().iteritems(): 322189251Ssam if configZip.isOlderThan(source): 323189251Ssam return False 324189251Ssam return True 325281806Srpaulo 326281806Srpaulo def _get_eclipse_settings_sources(self): 327189251Ssam """ 328189251Ssam Gets a dictionary from the name of an Eclipse settings file to 329189251Ssam the file providing its generated content. 330189251Ssam """ 331189251Ssam if not hasattr(self, '_eclipse_settings'): 332189251Ssam esdict = {} 333189251Ssam templateSettingsDir = join(self.dir, 'templates', 'eclipse', 'settings') 334189251Ssam if exists(templateSettingsDir): 335281806Srpaulo for name in os.listdir(templateSettingsDir): 336281806Srpaulo source = join(templateSettingsDir, name) 337189251Ssam esdict[name] = source 338189251Ssam self._eclipse_settings = esdict 339189251Ssam return self._eclipse_settings 340189251Ssam 341189251Ssam def _eclipseinit(self, files=None, libFiles=None): 342189251Ssam """ 343189251Ssam Generates an Eclipse project for each HotSpot build configuration. 344189251Ssam """ 345189251Ssam 346189251Ssam roots = [ 347189251Ssam 'ASSEMBLY_EXCEPTION', 348252726Srpaulo 'LICENSE', 349189251Ssam 'README', 350189251Ssam 'THIRD_PARTY_README', 351189251Ssam 'agent', 352189251Ssam 'make', 353189251Ssam 'src', 354189251Ssam 'test' 355189251Ssam ] 356189251Ssam 357189251Ssam for jvmVariant in _jdkJvmVariants: 358189251Ssam for debugLevel in _jdkDebugLevels: 359189251Ssam name = jvmVariant + '-' + debugLevel 360189251Ssam eclProjectDir = join(self.dir, 'eclipse', name) 361281806Srpaulo mx.ensure_dir_exists(eclProjectDir) 362252726Srpaulo 363252726Srpaulo out = mx.XMLDoc() 364252726Srpaulo out.open('projectDescription') 365281806Srpaulo out.element('name', data='hotspot:' + name) 366281806Srpaulo out.element('comment', data='') 367281806Srpaulo out.element('projects', data='') 368281806Srpaulo out.open('buildSpec') 369281806Srpaulo out.open('buildCommand') 370281806Srpaulo out.element('name', data='org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder') 371189251Ssam out.element('triggers', data='full,incremental') 372189251Ssam out.element('arguments', data='') 373189251Ssam out.close('buildCommand') 374189251Ssam 375189251Ssam out.close('buildSpec') 376189251Ssam out.open('natures') 377189251Ssam out.element('nature', data='org.eclipse.cdt.core.cnature') 378189251Ssam out.element('nature', data='org.eclipse.cdt.core.ccnature') 379189251Ssam out.element('nature', data='org.eclipse.cdt.managedbuilder.core.managedBuildNature') 380189251Ssam out.element('nature', data='org.eclipse.cdt.managedbuilder.core.ScannerConfigNature') 381252726Srpaulo out.close('natures') 382189251Ssam 383189251Ssam if roots: 384189251Ssam out.open('linkedResources') 385189251Ssam for r in roots: 386189251Ssam f = join(_suite.dir, r) 387189251Ssam out.open('link') 388189251Ssam out.element('name', data=r) 389189251Ssam out.element('type', data='2' if isdir(f) else '1') 390 out.element('locationURI', data=mx.get_eclipse_project_rel_locationURI(f, eclProjectDir)) 391 out.close('link') 392 393 out.open('link') 394 out.element('name', data='generated') 395 out.element('type', data='2') 396 generated = join(_get_hotspot_build_dir(jvmVariant, debugLevel), 'generated') 397 out.element('locationURI', data=mx.get_eclipse_project_rel_locationURI(generated, eclProjectDir)) 398 out.close('link') 399 400 out.close('linkedResources') 401 out.close('projectDescription') 402 projectFile = join(eclProjectDir, '.project') 403 mx.update_file(projectFile, out.xml(indent='\t', newl='\n')) 404 if files: 405 files.append(projectFile) 406 407 cprojectTemplate = join(self.dir, 'templates', 'eclipse', 'cproject') 408 cprojectFile = join(eclProjectDir, '.cproject') 409 with open(cprojectTemplate) as f: 410 content = f.read() 411 mx.update_file(cprojectFile, content) 412 if files: 413 files.append(cprojectFile) 414 415 settingsDir = join(eclProjectDir, ".settings") 416 mx.ensure_dir_exists(settingsDir) 417 for name, source in self._get_eclipse_settings_sources().iteritems(): 418 out = StringIO.StringIO() 419 print >> out, '# GENERATED -- DO NOT EDIT' 420 print >> out, '# Source:', source 421 with open(source) as f: 422 print >> out, f.read() 423 content = out.getvalue() 424 mx.update_file(join(settingsDir, name), content) 425 if files: 426 files.append(join(settingsDir, name)) 427 428 def getBuildTask(self, args): 429 return JDKBuildTask(self, args, _vm.debugLevel, _vm.jvmVariant) 430 431 432class JDKBuildTask(mx.NativeBuildTask): 433 def __init__(self, project, args, debugLevel, jvmVariant): 434 mx.NativeBuildTask.__init__(self, args, project) 435 self.jvmVariant = jvmVariant 436 self.debugLevel = debugLevel 437 438 def __str__(self): 439 return 'Building JDK[{}, {}]'.format(self.debugLevel, self.jvmVariant) 440 441 def build(self): 442 if mx.get_opts().use_jdk_image: 443 _runmake(['images']) 444 else: 445 _runmake([]) 446 self._newestOutput = None 447 448 def clean(self, forBuild=False): 449 if forBuild: # Let make handle incremental builds 450 return 451 if exists(_get_jdk_build_dir(self.debugLevel)): 452 _runmake(['clean']) 453 self._newestOutput = None 454 455# Backwards compatibility for mx_jvmci:8 API 456def buildvms(args): 457 _runmultimake(args) 458 459def run_vm(args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, debugLevel=None, vmbuild=None): 460 """run a Java program by executing the java executable in a JVMCI JDK""" 461 jdkTag = mx.get_jdk_option().tag 462 if jdkTag and jdkTag != _JVMCI_JDK_TAG: 463 mx.abort('The "--jdk" option must have the tag "' + _JVMCI_JDK_TAG + '" when running a command requiring a JVMCI VM') 464 jdk = get_jvmci_jdk(debugLevel=debugLevel or _translateLegacyDebugLevel(vmbuild)) 465 return jdk.run_java(args, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout) 466 467def _unittest_vm_launcher(vmArgs, mainClass, mainClassArgs): 468 run_vm(vmArgs + [mainClass] + mainClassArgs) 469 470mx_unittest.set_vm_launcher('JVMCI VM launcher', _unittest_vm_launcher) 471 472def _jvmci_gate_runner(args, tasks): 473 # Build release server VM now so we can run the unit tests 474 with Task('BuildHotSpotJVMCIHosted: release', tasks) as t: 475 if t: _runmultimake(['--jdk-jvm-variants', 'server', '--jdk-debug-levels', 'release']) 476 477 # Run unit tests in hosted mode 478 with VM(jvmVariant='server', debugLevel='release', jvmciMode='hosted'): 479 with Task('JVMCI UnitTests: hosted-release', tasks) as t: 480 if t: unittest(['--suite', 'jvmci', '--enable-timing', '--verbose', '--fail-fast']) 481 482 # Build the other VM flavors 483 with Task('BuildHotSpotJVMCIOthers: fastdebug', tasks) as t: 484 if t: _runmultimake(['--jdk-jvm-variants', 'server', '--jdk-debug-levels', 'fastdebug']) 485 486 with Task('CleanAndBuildIdealGraphVisualizer', tasks, disableJacoco=True) as t: 487 if t and platform.processor() != 'sparc': 488 buildxml = mx._cygpathU2W(join(_suite.dir, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml')) 489 mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'], env=_igvBuildEnv()) 490 491mx_gate.add_gate_runner(_suite, _jvmci_gate_runner) 492mx_gate.add_gate_argument('-g', '--only-build-jvmci', action='store_false', dest='buildNonJVMCI', help='only build the JVMCI VM') 493 494def _igvJdk(): 495 v8u20 = mx.VersionSpec("1.8.0_20") 496 v8u40 = mx.VersionSpec("1.8.0_40") 497 v8 = mx.VersionSpec("1.8") 498 def _igvJdkVersionCheck(version): 499 return version >= v8 and (version < v8u20 or version >= v8u40) 500 return mx.get_jdk(_igvJdkVersionCheck, versionDescription='>= 1.8 and < 1.8.0u20 or >= 1.8.0u40', purpose="building & running IGV").home 501 502def _igvBuildEnv(): 503 # When the http_proxy environment variable is set, convert it to the proxy settings that ant needs 504 env = dict(os.environ) 505 proxy = os.environ.get('http_proxy') 506 if not (proxy is None) and len(proxy) > 0: 507 if '://' in proxy: 508 # Remove the http:// prefix (or any other protocol prefix) 509 proxy = proxy.split('://', 1)[1] 510 # Separate proxy server name and port number 511 proxyName, proxyPort = proxy.split(':', 1) 512 proxyEnv = '-DproxyHost="' + proxyName + '" -DproxyPort=' + proxyPort 513 env['ANT_OPTS'] = proxyEnv 514 515 env['JAVA_HOME'] = _igvJdk() 516 return env 517 518def igv(args): 519 """run the Ideal Graph Visualizer""" 520 logFile = '.ideal_graph_visualizer.log' 521 with open(join(_suite.dir, logFile), 'w') as fp: 522 mx.logv('[Ideal Graph Visualizer log is in ' + fp.name + ']') 523 nbplatform = join(_suite.dir, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'nbplatform') 524 525 # Remove NetBeans platform if it is earlier than the current supported version 526 if exists(nbplatform): 527 updateTrackingFile = join(nbplatform, 'platform', 'update_tracking', 'org-netbeans-core.xml') 528 if not exists(updateTrackingFile): 529 mx.log('Could not find \'' + updateTrackingFile + '\', removing NetBeans platform') 530 shutil.rmtree(nbplatform) 531 else: 532 dom = xml.dom.minidom.parse(updateTrackingFile) 533 currentVersion = mx.VersionSpec(dom.getElementsByTagName('module_version')[0].getAttribute('specification_version')) 534 supportedVersion = mx.VersionSpec('3.43.1') 535 if currentVersion < supportedVersion: 536 mx.log('Replacing NetBeans platform version ' + str(currentVersion) + ' with version ' + str(supportedVersion)) 537 shutil.rmtree(nbplatform) 538 elif supportedVersion < currentVersion: 539 mx.log('Supported NetBeans version in igv command should be updated to ' + str(currentVersion)) 540 541 if not exists(nbplatform): 542 mx.logv('[This execution may take a while as the NetBeans platform needs to be downloaded]') 543 544 env = _igvBuildEnv() 545 # make the jar for Batik 1.7 available. 546 env['IGV_BATIK_JAR'] = mx.library('BATIK').get_path(True) 547 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): 548 mx.abort("IGV ant build & launch failed. Check '" + logFile + "'. You can also try to delete 'src/share/tools/IdealGraphVisualizer/nbplatform'.") 549 550def c1visualizer(args): 551 """run the Cl Compiler Visualizer""" 552 libpath = join(_suite.dir, 'lib') 553 if mx.get_os() == 'windows': 554 executable = join(libpath, 'c1visualizer', 'bin', 'c1visualizer.exe') 555 else: 556 executable = join(libpath, 'c1visualizer', 'bin', 'c1visualizer') 557 558 # Check whether the current C1Visualizer installation is the up-to-date 559 if exists(executable) and not exists(mx.library('C1VISUALIZER_DIST').get_path(resolve=False)): 560 mx.log('Updating C1Visualizer') 561 shutil.rmtree(join(libpath, 'c1visualizer')) 562 563 archive = mx.library('C1VISUALIZER_DIST').get_path(resolve=True) 564 565 if not exists(executable): 566 zf = zipfile.ZipFile(archive, 'r') 567 zf.extractall(libpath) 568 569 if not exists(executable): 570 mx.abort('C1Visualizer binary does not exist: ' + executable) 571 572 if mx.get_os() != 'windows': 573 # Make sure that execution is allowed. The zip file does not always specfiy that correctly 574 os.chmod(executable, 0777) 575 576 mx.run([executable]) 577 578def hsdis(args, copyToDir=None): 579 """download the hsdis library 580 581 This is needed to support HotSpot's assembly dumping features. 582 By default it downloads the Intel syntax version, use the 'att' argument to install AT&T syntax.""" 583 flavor = 'intel' 584 if 'att' in args: 585 flavor = 'att' 586 if mx.get_arch() == "sparcv9": 587 flavor = "sparcv9" 588 lib = mx.add_lib_suffix('hsdis-' + mx.get_arch()) 589 path = join(_suite.dir, 'lib', lib) 590 591 sha1s = { 592 'att/hsdis-amd64.dll' : 'bcbd535a9568b5075ab41e96205e26a2bac64f72', 593 'att/hsdis-amd64.so' : '58919ba085d4ef7a513f25bae75e7e54ee73c049', 594 'intel/hsdis-amd64.dll' : '6a388372cdd5fe905c1a26ced614334e405d1f30', 595 'intel/hsdis-amd64.so' : '844ed9ffed64fe9599638f29a8450c50140e3192', 596 'intel/hsdis-amd64.dylib' : 'fdb13ef0d7d23d93dacaae9c98837bea0d4fc5a2', 597 'sparcv9/hsdis-sparcv9.so': '970640a9af0bd63641f9063c11275b371a59ee60', 598 } 599 600 flavoredLib = flavor + "/" + lib 601 if flavoredLib not in sha1s: 602 mx.logv("hsdis not supported on this plattform or architecture") 603 return 604 605 if not exists(path): 606 sha1 = sha1s[flavoredLib] 607 sha1path = path + '.sha1' 608 mx.download_file_with_sha1('hsdis', path, ['https://lafo.ssw.uni-linz.ac.at/pub/hsdis/' + flavoredLib], sha1, sha1path, True, True, sources=False) 609 if copyToDir is not None and exists(copyToDir): 610 shutil.copy(path, copyToDir) 611 612def hcfdis(args): 613 """disassemble HexCodeFiles embedded in text files 614 615 Run a tool over the input files to convert all embedded HexCodeFiles 616 to a disassembled format.""" 617 618 parser = ArgumentParser(prog='mx hcfdis') 619 parser.add_argument('-m', '--map', help='address to symbol map applied to disassembler output') 620 parser.add_argument('files', nargs=REMAINDER, metavar='files...') 621 622 args = parser.parse_args(args) 623 624 path = mx.library('HCFDIS').get_path(resolve=True) 625 mx.run_java(['-cp', path, 'com.oracle.max.hcfdis.HexCodeFileDis'] + args.files) 626 627 if args.map is not None: 628 addressRE = re.compile(r'0[xX]([A-Fa-f0-9]+)') 629 with open(args.map) as fp: 630 lines = fp.read().splitlines() 631 symbols = dict() 632 for l in lines: 633 addressAndSymbol = l.split(' ', 1) 634 if len(addressAndSymbol) == 2: 635 address, symbol = addressAndSymbol 636 if address.startswith('0x'): 637 address = long(address, 16) 638 symbols[address] = symbol 639 for f in args.files: 640 with open(f) as fp: 641 lines = fp.read().splitlines() 642 updated = False 643 for i in range(0, len(lines)): 644 l = lines[i] 645 for m in addressRE.finditer(l): 646 sval = m.group(0) 647 val = long(sval, 16) 648 sym = symbols.get(val) 649 if sym: 650 l = l.replace(sval, sym) 651 updated = True 652 lines[i] = l 653 if updated: 654 mx.log('updating ' + f) 655 with open('new_' + f, "w") as fp: 656 for l in lines: 657 print >> fp, l 658 659def jol(args): 660 """Java Object Layout""" 661 joljar = mx.library('JOL_INTERNALS').get_path(resolve=True) 662 candidates = mx.findclass(args, logToConsole=False, matcher=lambda s, classname: s == classname or classname.endswith('.' + s) or classname.endswith('$' + s)) 663 664 if len(candidates) > 0: 665 candidates = mx.select_items(sorted(candidates)) 666 else: 667 # mx.findclass can be mistaken, don't give up yet 668 candidates = args 669 670 run_vm(['-javaagent:' + joljar, '-cp', os.pathsep.join([mx.classpath(), joljar]), "org.openjdk.jol.MainObjectInternals"] + candidates) 671 672class JVMCIArchiveParticipant: 673 def __init__(self, dist): 674 self.dist = dist 675 676 def __opened__(self, arc, srcArc, services): 677 self.services = services 678 self.jvmciServices = services 679 self.arc = arc 680 681 def __add__(self, arcname, contents): 682 return False 683 684 def __addsrc__(self, arcname, contents): 685 return False 686 687 def __closing__(self): 688 pass 689 690def _get_openjdk_os(): 691 # See: common/autoconf/platform.m4 692 os = mx.get_os() 693 if 'darwin' in os: 694 os = 'macosx' 695 elif 'linux' in os: 696 os = 'linux' 697 elif 'solaris' in os: 698 os = 'solaris' 699 elif 'cygwin' in os or 'mingw' in os: 700 os = 'windows' 701 return os 702 703def _get_openjdk_cpu(): 704 cpu = mx.get_arch() 705 if cpu == 'amd64': 706 cpu = 'x86_64' 707 elif cpu == 'sparcv9': 708 cpu = 'sparcv9' 709 return cpu 710 711def _get_openjdk_os_cpu(): 712 return _get_openjdk_os() + '-' + _get_openjdk_cpu() 713 714def _get_jdk_build_dir(debugLevel=None): 715 """ 716 Gets the directory into which the JDK is built. This directory contains 717 the exploded JDK under jdk/ and the JDK image under images/jdk/. 718 """ 719 if debugLevel is None: 720 debugLevel = _vm.debugLevel 721 name = '{}-{}-{}-{}'.format(_get_openjdk_os_cpu(), 'normal', _vm.jvmVariant, debugLevel) 722 return join(dirname(_suite.dir), 'build', name) 723 724_jvmci_bootclasspath_prepends = [] 725 726def _get_hotspot_build_dir(jvmVariant=None, debugLevel=None): 727 """ 728 Gets the directory in which a particular HotSpot configuration is built 729 (e.g., <JDK_REPO_ROOT>/build/macosx-x86_64-normal-server-release/hotspot/bsd_amd64_compiler2) 730 """ 731 if jvmVariant is None: 732 jvmVariant = _vm.jvmVariant 733 734 os = mx.get_os() 735 if os == 'darwin': 736 os = 'bsd' 737 arch = mx.get_arch() 738 buildname = {'client': 'compiler1', 'server': 'compiler2'}.get(jvmVariant, jvmVariant) 739 740 name = '{}_{}_{}'.format(os, arch, buildname) 741 return join(_get_jdk_build_dir(debugLevel=debugLevel), 'hotspot', name) 742 743def add_bootclasspath_prepend(dep): 744 assert isinstance(dep, mx.ClasspathDependency) 745 _jvmci_bootclasspath_prepends.append(dep) 746 747class JVMCI9JDKConfig(mx.JDKConfig): 748 def __init__(self, debugLevel): 749 self.debugLevel = debugLevel 750 jdkBuildDir = _get_jdk_build_dir(debugLevel) 751 jdkDir = join(jdkBuildDir, 'images', 'jdk') if mx.get_opts().use_jdk_image else join(jdkBuildDir, 'jdk') 752 mx.JDKConfig.__init__(self, jdkDir, tag=_JVMCI_JDK_TAG) 753 754 def parseVmArgs(self, args, addDefaultArgs=True): 755 args = mx.expand_project_in_args(args, insitu=False) 756 jacocoArgs = mx_gate.get_jacoco_agent_args() 757 if jacocoArgs: 758 args = jacocoArgs + args 759 760 args = ['-Xbootclasspath/p:' + dep.classpath_repr() for dep in _jvmci_bootclasspath_prepends] + args 761 762 jvmciModeArgs = _jvmciModes[_vm.jvmciMode] 763 if jvmciModeArgs: 764 bcpDeps = [jdkDist.dist() for jdkDist in jdkDeployedDists] 765 if bcpDeps: 766 args = ['-Xbootclasspath/p:' + os.pathsep.join([d.classpath_repr() for d in bcpDeps])] + args 767 768 # Set the default JVMCI compiler 769 for jdkDist in reversed(jdkDeployedDists): 770 assert isinstance(jdkDist, JvmciJDKDeployedDist), jdkDist 771 if jdkDist._compilers: 772 jvmciCompiler = jdkDist._compilers[-1] 773 args = ['-Djvmci.compiler=' + jvmciCompiler] + args 774 break 775 776 if '-version' in args: 777 ignoredArgs = args[args.index('-version') + 1:] 778 if len(ignoredArgs) > 0: 779 mx.log("Warning: The following options will be ignored by the vm because they come after the '-version' argument: " + ' '.join(ignoredArgs)) 780 return self.processArgs(args, addDefaultArgs=addDefaultArgs) 781 782 # Overrides JDKConfig 783 def run_java(self, args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, env=None, addDefaultArgs=True): 784 if vm is None: 785 vm = 'server' 786 787 args = self.parseVmArgs(args, addDefaultArgs=addDefaultArgs) 788 789 jvmciModeArgs = _jvmciModes[_vm.jvmciMode] 790 cmd = [self.java] + ['-' + vm] + jvmciModeArgs + args 791 return mx.run(cmd, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd) 792 793""" 794The dict of JVMCI JDKs indexed by debug-level names. 795""" 796_jvmci_jdks = {} 797 798def get_jvmci_jdk(debugLevel=None): 799 """ 800 Gets the JVMCI JDK corresponding to 'debugLevel'. 801 """ 802 if not debugLevel: 803 debugLevel = _vm.debugLevel 804 jdk = _jvmci_jdks.get(debugLevel) 805 if jdk is None: 806 try: 807 jdk = JVMCI9JDKConfig(debugLevel) 808 except mx.JDKConfigException as e: 809 jdkBuildDir = _get_jdk_build_dir(debugLevel) 810 msg = 'Error with the JDK built into {}:\n{}\nTry (re)building it with: mx --jdk-debug-level={} make' 811 if mx.get_opts().use_jdk_image: 812 msg += ' images' 813 mx.abort(msg.format(jdkBuildDir, e.message, debugLevel)) 814 _jvmci_jdks[debugLevel] = jdk 815 return jdk 816 817class JVMCIJDKFactory(mx.JDKFactory): 818 def getJDKConfig(self): 819 jdk = get_jvmci_jdk(_vm.debugLevel) 820 return jdk 821 822 def description(self): 823 return "JVMCI JDK" 824 825mx.update_commands(_suite, { 826 'make': [_runmake, '[args...]', _makehelp], 827 'multimake': [_runmultimake, '[options]'], 828 'c1visualizer' : [c1visualizer, ''], 829 'hsdis': [hsdis, '[att]'], 830 'hcfdis': [hcfdis, ''], 831 'igv' : [igv, ''], 832 'jol' : [jol, ''], 833 'vm': [run_vm, '[-options] class [args...]'], 834}) 835 836mx.add_argument('-M', '--jvmci-mode', action='store', choices=sorted(_jvmciModes.viewkeys()), help='the JVM variant type to build/run (default: ' + _vm.jvmciMode + ')') 837mx.add_argument('--jdk-jvm-variant', '--vm', action='store', choices=_jdkJvmVariants + sorted(_legacyVms.viewkeys()), help='the JVM variant type to build/run (default: ' + _vm.jvmVariant + ')') 838mx.add_argument('--jdk-debug-level', '--vmbuild', action='store', choices=_jdkDebugLevels + sorted(_legacyVmbuilds.viewkeys()), help='the JDK debug level to build/run (default: ' + _vm.debugLevel + ')') 839mx.add_argument('-I', '--use-jdk-image', action='store_true', help='build/run JDK image instead of exploded JDK') 840 841def mx_post_parse_cmd_line(opts): 842 mx.addJDKFactory(_JVMCI_JDK_TAG, mx.JavaCompliance('9'), JVMCIJDKFactory()) 843 mx.set_java_command_default_jdk_tag(_JVMCI_JDK_TAG) 844 845 jdkTag = mx.get_jdk_option().tag 846 847 jvmVariant = None 848 debugLevel = None 849 jvmciMode = None 850 851 if opts.jdk_jvm_variant is not None: 852 jvmVariant = opts.jdk_jvm_variant 853 if jdkTag and jdkTag != _JVMCI_JDK_TAG: 854 mx.warn('Ignoring "--jdk-jvm-variant" option as "--jdk" tag is not "' + _JVMCI_JDK_TAG + '"') 855 856 if opts.jdk_debug_level is not None: 857 debugLevel = _translateLegacyDebugLevel(opts.jdk_debug_level) 858 if jdkTag and jdkTag != _JVMCI_JDK_TAG: 859 mx.warn('Ignoring "--jdk-debug-level" option as "--jdk" tag is not "' + _JVMCI_JDK_TAG + '"') 860 861 if opts.jvmci_mode is not None: 862 jvmciMode = opts.jvmci_mode 863 if jdkTag and jdkTag != _JVMCI_JDK_TAG: 864 mx.warn('Ignoring "--jvmci-mode" option as "--jdk" tag is not "' + _JVMCI_JDK_TAG + '"') 865 866 _vm.update(jvmVariant, debugLevel, jvmciMode) 867 868 for jdkDist in jdkDeployedDists: 869 jdkDist.post_parse_cmd_line() 870