mx_jvmci.py revision 11328:7b91a1088135
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'] 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', 162 '--with-jvm-variants=' + _vm.jvmVariant, '--disable-warnings-as-errors', '--with-boot-jdk=' + jdk8.home] 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 179 if 'images' in cmd: 180 jdkImageDir = join(jdkBuildDir, 'images', 'jdk') 181 182 # The OpenJDK build creates an empty cacerts file so copy one from 183 # the default JDK (which is assumed to be an OracleJDK) 184 srcCerts = join(mx.get_jdk(tag='default').home, 'lib', 'security', 'cacerts') 185 if not exists(srcCerts): 186 # Might be building with JDK8 which has cacerts under jre/ 187 srcCerts = join(mx.get_jdk(tag='default').home, 'jre', 'lib', 'security', 'cacerts') 188 dstCerts = join(jdkImageDir, 'lib', 'security', 'cacerts') 189 shutil.copyfile(srcCerts, dstCerts) 190 191 _create_jdk_bundle(jdkBuildDir, _vm.debugLevel, jdkImageDir) 192 193def _get_jdk_bundle_arches(): 194 """ 195 Gets a list of names that will be the part of a JDK bundle's file name denoting the architecture. 196 The first element in the list is the canonical name. Symlinks should be created for the 197 remaining names. 198 """ 199 cpu = mx.get_arch() 200 if cpu == 'amd64': 201 return ['x64', 'x86_64', 'amd64'] 202 elif cpu == 'sparcv9': 203 return ['sparcv9'] 204 mx.abort('Unsupported JDK bundle arch: ' + cpu) 205 206def _create_jdk_bundle(jdkBuildDir, debugLevel, jdkImageDir): 207 """ 208 Creates a tar.gz JDK archive, an accompanying tar.gz.sha1 file with its 209 SHA1 signature plus symlinks to the archive for non-canonical architecture names. 210 """ 211 212 arches = _get_jdk_bundle_arches() 213 jdkTgzPath = join(_suite.get_output_root(), 'jdk-bundles', 'jdk9-{}-{}-{}.tar.gz'.format(debugLevel, _get_openjdk_os(), arches[0])) 214 with mx.Archiver(jdkTgzPath, kind='tgz') as arc: 215 mx.log('Creating ' + jdkTgzPath) 216 for root, _, filenames in os.walk(jdkImageDir): 217 for name in filenames: 218 f = join(root, name) 219 arcname = 'jdk1.9.0/' + os.path.relpath(f, jdkImageDir) 220 arc.zf.add(name=f, arcname=arcname, recursive=False) 221 222 with open(jdkTgzPath + '.sha1', 'w') as fp: 223 mx.log('Creating ' + jdkTgzPath + '.sha1') 224 fp.write(mx.sha1OfFile(jdkTgzPath)) 225 226 def _create_link(source, link_name): 227 if exists(link_name): 228 os.remove(link_name) 229 mx.log('Creating ' + link_name + ' -> ' + source) 230 os.symlink(source, link_name) 231 232 for arch in arches[1:]: 233 link_name = join(_suite.get_output_root(), 'jdk-bundles', 'jdk9-{}-{}-{}.tar.gz'.format(debugLevel, _get_openjdk_os(), arch)) 234 jdkTgzName = os.path.basename(jdkTgzPath) 235 _create_link(jdkTgzName, link_name) 236 _create_link(jdkTgzName + '.sha1', link_name + '.sha1') 237 238def _runmultimake(args): 239 """run the JDK make process for one or more configurations""" 240 241 jvmVariantsDefault = ','.join(_jdkJvmVariants) 242 debugLevelsDefault = ','.join(_jdkDebugLevels) 243 244 parser = ArgumentParser(prog='mx multimake') 245 parser.add_argument('--jdk-jvm-variants', '--vms', help='a comma separated list of VMs to build (default: ' + jvmVariantsDefault + ')', metavar='<args>', default=jvmVariantsDefault) 246 parser.add_argument('--jdk-debug-levels', '--builds', help='a comma separated list of JDK debug levels (default: ' + debugLevelsDefault + ')', metavar='<args>', default=debugLevelsDefault) 247 parser.add_argument('-n', '--no-check', action='store_true', help='omit running "java -version" after each build') 248 select = parser.add_mutually_exclusive_group() 249 select.add_argument('-c', '--console', action='store_true', help='send build output to console instead of log files') 250 select.add_argument('-d', '--output-dir', help='directory for log files instead of current working directory', default=os.getcwd(), metavar='<dir>') 251 252 args = parser.parse_args(args) 253 jvmVariants = args.jdk_jvm_variants.split(',') 254 debugLevels = [_translateLegacyDebugLevel(dl) for dl in args.jdk_debug_levels.split(',')] 255 256 allStart = time.time() 257 for jvmVariant in jvmVariants: 258 for debugLevel in debugLevels: 259 if not args.console: 260 logFile = join(mx.ensure_dir_exists(args.output_dir), jvmVariant + '-' + debugLevel + '.log') 261 log = open(logFile, 'wb') 262 start = time.time() 263 mx.log('BEGIN: ' + jvmVariant + '-' + debugLevel + '\t(see: ' + logFile + ')') 264 verbose = ['-v'] if mx.get_opts().verbose else [] 265 # Run as subprocess so that output can be directed to a file 266 cmd = [sys.executable, '-u', mx.__file__] + verbose + ['--jdk-jvm-variant=' + jvmVariant, '--jdk-debug-level=' + debugLevel, 'make'] 267 mx.logv("executing command: " + str(cmd)) 268 subprocess.check_call(cmd, cwd=_suite.dir, stdout=log, stderr=subprocess.STDOUT) 269 duration = datetime.timedelta(seconds=time.time() - start) 270 mx.log('END: ' + jvmVariant + '-' + debugLevel + '\t[' + str(duration) + ']') 271 else: 272 with VM(jvmVariant=jvmVariant, debugLevel=debugLevel): 273 _runmake([]) 274 if not args.no_check: 275 with VM(jvmciMode='jit'): 276 run_vm(['-XX:-BootstrapJVMCI', '-version']) 277 allDuration = datetime.timedelta(seconds=time.time() - allStart) 278 mx.log('TOTAL TIME: ' + '[' + str(allDuration) + ']') 279 280class HotSpotProject(mx.NativeProject): 281 """ 282 Defines a NativeProject representing the HotSpot binaries built via make. 283 """ 284 def __init__(self, suite, name, deps, workingSets, **args): 285 assert name == 'hotspot' 286 mx.NativeProject.__init__(self, suite, name, "", [], deps, workingSets, None, None, join(suite.mxDir, name)) 287 288 def eclipse_config_up_to_date(self, configZip): 289 # Assume that any change to this module might imply changes to the generated IDE files 290 if configZip.isOlderThan(__file__): 291 return False 292 for _, source in self._get_eclipse_settings_sources().iteritems(): 293 if configZip.isOlderThan(source): 294 return False 295 return True 296 297 def _get_eclipse_settings_sources(self): 298 """ 299 Gets a dictionary from the name of an Eclipse settings file to 300 the file providing its generated content. 301 """ 302 if not hasattr(self, '_eclipse_settings'): 303 esdict = {} 304 templateSettingsDir = join(self.dir, 'templates', 'eclipse', 'settings') 305 if exists(templateSettingsDir): 306 for name in os.listdir(templateSettingsDir): 307 source = join(templateSettingsDir, name) 308 esdict[name] = source 309 self._eclipse_settings = esdict 310 return self._eclipse_settings 311 312 def _eclipseinit(self, files=None, libFiles=None): 313 """ 314 Generates an Eclipse project for each HotSpot build configuration. 315 """ 316 317 roots = [ 318 'ASSEMBLY_EXCEPTION', 319 'LICENSE', 320 'README', 321 'THIRD_PARTY_README', 322 'agent', 323 'make', 324 'src', 325 'test' 326 ] 327 328 for jvmVariant in _jdkJvmVariants: 329 for debugLevel in _jdkDebugLevels: 330 name = jvmVariant + '-' + debugLevel 331 eclProjectDir = join(self.dir, 'eclipse', name) 332 mx.ensure_dir_exists(eclProjectDir) 333 334 out = mx.XMLDoc() 335 out.open('projectDescription') 336 out.element('name', data='hotspot:' + name) 337 out.element('comment', data='') 338 out.element('projects', data='') 339 out.open('buildSpec') 340 out.open('buildCommand') 341 out.element('name', data='org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder') 342 out.element('triggers', data='full,incremental') 343 out.element('arguments', data='') 344 out.close('buildCommand') 345 346 out.close('buildSpec') 347 out.open('natures') 348 out.element('nature', data='org.eclipse.cdt.core.cnature') 349 out.element('nature', data='org.eclipse.cdt.core.ccnature') 350 out.element('nature', data='org.eclipse.cdt.managedbuilder.core.managedBuildNature') 351 out.element('nature', data='org.eclipse.cdt.managedbuilder.core.ScannerConfigNature') 352 out.close('natures') 353 354 if roots: 355 out.open('linkedResources') 356 for r in roots: 357 f = join(_suite.dir, r) 358 out.open('link') 359 out.element('name', data=r) 360 out.element('type', data='2' if isdir(f) else '1') 361 out.element('locationURI', data=mx.get_eclipse_project_rel_locationURI(f, eclProjectDir)) 362 out.close('link') 363 364 out.open('link') 365 out.element('name', data='generated') 366 out.element('type', data='2') 367 generated = join(_get_hotspot_build_dir(jvmVariant, debugLevel), 'generated') 368 out.element('locationURI', data=mx.get_eclipse_project_rel_locationURI(generated, eclProjectDir)) 369 out.close('link') 370 371 out.close('linkedResources') 372 out.close('projectDescription') 373 projectFile = join(eclProjectDir, '.project') 374 mx.update_file(projectFile, out.xml(indent='\t', newl='\n')) 375 if files: 376 files.append(projectFile) 377 378 cprojectTemplate = join(self.dir, 'templates', 'eclipse', 'cproject') 379 cprojectFile = join(eclProjectDir, '.cproject') 380 with open(cprojectTemplate) as f: 381 content = f.read() 382 mx.update_file(cprojectFile, content) 383 if files: 384 files.append(cprojectFile) 385 386 settingsDir = join(eclProjectDir, ".settings") 387 mx.ensure_dir_exists(settingsDir) 388 for name, source in self._get_eclipse_settings_sources().iteritems(): 389 out = StringIO.StringIO() 390 print >> out, '# GENERATED -- DO NOT EDIT' 391 print >> out, '# Source:', source 392 with open(source) as f: 393 print >> out, f.read() 394 content = out.getvalue() 395 mx.update_file(join(settingsDir, name), content) 396 if files: 397 files.append(join(settingsDir, name)) 398 399 def getBuildTask(self, args): 400 return JDKBuildTask(self, args, _vm.debugLevel, _vm.jvmVariant) 401 402 403class JDKBuildTask(mx.NativeBuildTask): 404 def __init__(self, project, args, debugLevel, jvmVariant): 405 mx.NativeBuildTask.__init__(self, args, project) 406 self.jvmVariant = jvmVariant 407 self.debugLevel = debugLevel 408 409 def __str__(self): 410 return 'Building JDK[{}, {}]'.format(self.debugLevel, self.jvmVariant) 411 412 def build(self): 413 if mx.get_opts().use_jdk_image: 414 _runmake(['images']) 415 else: 416 _runmake([]) 417 self._newestOutput = None 418 419 def clean(self, forBuild=False): 420 if forBuild: # Let make handle incremental builds 421 return 422 if exists(_get_jdk_build_dir(self.debugLevel)): 423 _runmake(['clean']) 424 self._newestOutput = None 425 426# Backwards compatibility for mx_jvmci:8 API 427def buildvms(args): 428 _runmultimake(args) 429 430def run_vm(args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, debugLevel=None, vmbuild=None): 431 """run a Java program by executing the java executable in a JVMCI JDK""" 432 jdkTag = mx.get_jdk_option().tag 433 if jdkTag and jdkTag != _JVMCI_JDK_TAG: 434 mx.abort('The "--jdk" option must have the tag "' + _JVMCI_JDK_TAG + '" when running a command requiring a JVMCI VM') 435 jdk = get_jvmci_jdk(debugLevel=debugLevel or _translateLegacyDebugLevel(vmbuild)) 436 return jdk.run_java(args, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout) 437 438def _unittest_vm_launcher(vmArgs, mainClass, mainClassArgs): 439 run_vm(vmArgs + [mainClass] + mainClassArgs) 440 441mx_unittest.set_vm_launcher('JVMCI VM launcher', _unittest_vm_launcher) 442 443def _jvmci_gate_runner(args, tasks): 444 # Build release server VM now so we can run the unit tests 445 with Task('BuildHotSpotJVMCIHosted: release', tasks) as t: 446 if t: _runmultimake(['--jdk-jvm-variants', 'server', '--jdk-debug-levels', 'release']) 447 448 # Run unit tests in hosted mode 449 with VM(jvmVariant='server', debugLevel='release', jvmciMode='hosted'): 450 with Task('JVMCI UnitTests: hosted-release', tasks) as t: 451 if t: unittest(['--suite', 'jvmci', '--enable-timing', '--verbose', '--fail-fast']) 452 453 # Build the other VM flavors 454 with Task('BuildHotSpotJVMCIOthers: fastdebug', tasks) as t: 455 if t: _runmultimake(['--jdk-jvm-variants', 'server', '--jdk-debug-levels', 'fastdebug']) 456 457 with Task('CleanAndBuildIdealGraphVisualizer', tasks, disableJacoco=True) as t: 458 if t and platform.processor() != 'sparc': 459 buildxml = mx._cygpathU2W(join(_suite.dir, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml')) 460 mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'], env=_igvBuildEnv()) 461 462mx_gate.add_gate_runner(_suite, _jvmci_gate_runner) 463mx_gate.add_gate_argument('-g', '--only-build-jvmci', action='store_false', dest='buildNonJVMCI', help='only build the JVMCI VM') 464 465def _igvJdk(): 466 v8u20 = mx.VersionSpec("1.8.0_20") 467 v8u40 = mx.VersionSpec("1.8.0_40") 468 v8 = mx.VersionSpec("1.8") 469 def _igvJdkVersionCheck(version): 470 return version >= v8 and (version < v8u20 or version >= v8u40) 471 return mx.get_jdk(_igvJdkVersionCheck, versionDescription='>= 1.8 and < 1.8.0u20 or >= 1.8.0u40', purpose="building & running IGV").home 472 473def _igvBuildEnv(): 474 # When the http_proxy environment variable is set, convert it to the proxy settings that ant needs 475 env = dict(os.environ) 476 proxy = os.environ.get('http_proxy') 477 if not (proxy is None) and len(proxy) > 0: 478 if '://' in proxy: 479 # Remove the http:// prefix (or any other protocol prefix) 480 proxy = proxy.split('://', 1)[1] 481 # Separate proxy server name and port number 482 proxyName, proxyPort = proxy.split(':', 1) 483 proxyEnv = '-DproxyHost="' + proxyName + '" -DproxyPort=' + proxyPort 484 env['ANT_OPTS'] = proxyEnv 485 486 env['JAVA_HOME'] = _igvJdk() 487 return env 488 489def igv(args): 490 """run the Ideal Graph Visualizer""" 491 logFile = '.ideal_graph_visualizer.log' 492 with open(join(_suite.dir, logFile), 'w') as fp: 493 mx.logv('[Ideal Graph Visualizer log is in ' + fp.name + ']') 494 nbplatform = join(_suite.dir, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'nbplatform') 495 496 # Remove NetBeans platform if it is earlier than the current supported version 497 if exists(nbplatform): 498 updateTrackingFile = join(nbplatform, 'platform', 'update_tracking', 'org-netbeans-core.xml') 499 if not exists(updateTrackingFile): 500 mx.log('Could not find \'' + updateTrackingFile + '\', removing NetBeans platform') 501 shutil.rmtree(nbplatform) 502 else: 503 dom = xml.dom.minidom.parse(updateTrackingFile) 504 currentVersion = mx.VersionSpec(dom.getElementsByTagName('module_version')[0].getAttribute('specification_version')) 505 supportedVersion = mx.VersionSpec('3.43.1') 506 if currentVersion < supportedVersion: 507 mx.log('Replacing NetBeans platform version ' + str(currentVersion) + ' with version ' + str(supportedVersion)) 508 shutil.rmtree(nbplatform) 509 elif supportedVersion < currentVersion: 510 mx.log('Supported NetBeans version in igv command should be updated to ' + str(currentVersion)) 511 512 if not exists(nbplatform): 513 mx.logv('[This execution may take a while as the NetBeans platform needs to be downloaded]') 514 515 env = _igvBuildEnv() 516 # make the jar for Batik 1.7 available. 517 env['IGV_BATIK_JAR'] = mx.library('BATIK').get_path(True) 518 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): 519 mx.abort("IGV ant build & launch failed. Check '" + logFile + "'. You can also try to delete 'src/share/tools/IdealGraphVisualizer/nbplatform'.") 520 521def c1visualizer(args): 522 """run the Cl Compiler Visualizer""" 523 libpath = join(_suite.dir, 'lib') 524 if mx.get_os() == 'windows': 525 executable = join(libpath, 'c1visualizer', 'bin', 'c1visualizer.exe') 526 else: 527 executable = join(libpath, 'c1visualizer', 'bin', 'c1visualizer') 528 529 # Check whether the current C1Visualizer installation is the up-to-date 530 if exists(executable) and not exists(mx.library('C1VISUALIZER_DIST').get_path(resolve=False)): 531 mx.log('Updating C1Visualizer') 532 shutil.rmtree(join(libpath, 'c1visualizer')) 533 534 archive = mx.library('C1VISUALIZER_DIST').get_path(resolve=True) 535 536 if not exists(executable): 537 zf = zipfile.ZipFile(archive, 'r') 538 zf.extractall(libpath) 539 540 if not exists(executable): 541 mx.abort('C1Visualizer binary does not exist: ' + executable) 542 543 if mx.get_os() != 'windows': 544 # Make sure that execution is allowed. The zip file does not always specfiy that correctly 545 os.chmod(executable, 0777) 546 547 mx.run([executable]) 548 549def hsdis(args, copyToDir=None): 550 """download the hsdis library 551 552 This is needed to support HotSpot's assembly dumping features. 553 By default it downloads the Intel syntax version, use the 'att' argument to install AT&T syntax.""" 554 flavor = 'intel' 555 if 'att' in args: 556 flavor = 'att' 557 if mx.get_arch() == "sparcv9": 558 flavor = "sparcv9" 559 lib = mx.add_lib_suffix('hsdis-' + mx.get_arch()) 560 path = join(_suite.dir, 'lib', lib) 561 562 sha1s = { 563 'att/hsdis-amd64.dll' : 'bcbd535a9568b5075ab41e96205e26a2bac64f72', 564 'att/hsdis-amd64.so' : '58919ba085d4ef7a513f25bae75e7e54ee73c049', 565 'intel/hsdis-amd64.dll' : '6a388372cdd5fe905c1a26ced614334e405d1f30', 566 'intel/hsdis-amd64.so' : '844ed9ffed64fe9599638f29a8450c50140e3192', 567 'intel/hsdis-amd64.dylib' : 'fdb13ef0d7d23d93dacaae9c98837bea0d4fc5a2', 568 'sparcv9/hsdis-sparcv9.so': '970640a9af0bd63641f9063c11275b371a59ee60', 569 } 570 571 flavoredLib = flavor + "/" + lib 572 if flavoredLib not in sha1s: 573 mx.logv("hsdis not supported on this plattform or architecture") 574 return 575 576 if not exists(path): 577 sha1 = sha1s[flavoredLib] 578 sha1path = path + '.sha1' 579 mx.download_file_with_sha1('hsdis', path, ['https://lafo.ssw.uni-linz.ac.at/pub/hsdis/' + flavoredLib], sha1, sha1path, True, True, sources=False) 580 if copyToDir is not None and exists(copyToDir): 581 shutil.copy(path, copyToDir) 582 583def hcfdis(args): 584 """disassemble HexCodeFiles embedded in text files 585 586 Run a tool over the input files to convert all embedded HexCodeFiles 587 to a disassembled format.""" 588 589 parser = ArgumentParser(prog='mx hcfdis') 590 parser.add_argument('-m', '--map', help='address to symbol map applied to disassembler output') 591 parser.add_argument('files', nargs=REMAINDER, metavar='files...') 592 593 args = parser.parse_args(args) 594 595 path = mx.library('HCFDIS').get_path(resolve=True) 596 mx.run_java(['-cp', path, 'com.oracle.max.hcfdis.HexCodeFileDis'] + args.files) 597 598 if args.map is not None: 599 addressRE = re.compile(r'0[xX]([A-Fa-f0-9]+)') 600 with open(args.map) as fp: 601 lines = fp.read().splitlines() 602 symbols = dict() 603 for l in lines: 604 addressAndSymbol = l.split(' ', 1) 605 if len(addressAndSymbol) == 2: 606 address, symbol = addressAndSymbol 607 if address.startswith('0x'): 608 address = long(address, 16) 609 symbols[address] = symbol 610 for f in args.files: 611 with open(f) as fp: 612 lines = fp.read().splitlines() 613 updated = False 614 for i in range(0, len(lines)): 615 l = lines[i] 616 for m in addressRE.finditer(l): 617 sval = m.group(0) 618 val = long(sval, 16) 619 sym = symbols.get(val) 620 if sym: 621 l = l.replace(sval, sym) 622 updated = True 623 lines[i] = l 624 if updated: 625 mx.log('updating ' + f) 626 with open('new_' + f, "w") as fp: 627 for l in lines: 628 print >> fp, l 629 630def jol(args): 631 """Java Object Layout""" 632 joljar = mx.library('JOL_INTERNALS').get_path(resolve=True) 633 candidates = mx.findclass(args, logToConsole=False, matcher=lambda s, classname: s == classname or classname.endswith('.' + s) or classname.endswith('$' + s)) 634 635 if len(candidates) > 0: 636 candidates = mx.select_items(sorted(candidates)) 637 else: 638 # mx.findclass can be mistaken, don't give up yet 639 candidates = args 640 641 run_vm(['-javaagent:' + joljar, '-cp', os.pathsep.join([mx.classpath(), joljar]), "org.openjdk.jol.MainObjectInternals"] + candidates) 642 643def _get_openjdk_os(): 644 # See: common/autoconf/platform.m4 645 os = mx.get_os() 646 if 'darwin' in os: 647 os = 'macosx' 648 elif 'linux' in os: 649 os = 'linux' 650 elif 'solaris' in os: 651 os = 'solaris' 652 elif 'cygwin' in os or 'mingw' in os: 653 os = 'windows' 654 return os 655 656def _get_openjdk_cpu(): 657 cpu = mx.get_arch() 658 if cpu == 'amd64': 659 cpu = 'x86_64' 660 elif cpu == 'sparcv9': 661 cpu = 'sparcv9' 662 return cpu 663 664def _get_openjdk_os_cpu(): 665 return _get_openjdk_os() + '-' + _get_openjdk_cpu() 666 667def _get_jdk_build_dir(debugLevel=None): 668 """ 669 Gets the directory into which the JDK is built. This directory contains 670 the exploded JDK under jdk/ and the JDK image under images/jdk/. 671 """ 672 if debugLevel is None: 673 debugLevel = _vm.debugLevel 674 name = '{}-{}-{}-{}'.format(_get_openjdk_os_cpu(), 'normal', _vm.jvmVariant, debugLevel) 675 return join(dirname(_suite.dir), 'build', name) 676 677_jvmci_bootclasspath_prepends = [] 678 679def _get_hotspot_build_dir(jvmVariant=None, debugLevel=None): 680 """ 681 Gets the directory in which a particular HotSpot configuration is built 682 (e.g., <JDK_REPO_ROOT>/build/macosx-x86_64-normal-server-release/hotspot/bsd_amd64_compiler2) 683 """ 684 if jvmVariant is None: 685 jvmVariant = _vm.jvmVariant 686 687 os = mx.get_os() 688 if os == 'darwin': 689 os = 'bsd' 690 arch = mx.get_arch() 691 buildname = {'client': 'compiler1', 'server': 'compiler2'}.get(jvmVariant, jvmVariant) 692 693 name = '{}_{}_{}'.format(os, arch, buildname) 694 return join(_get_jdk_build_dir(debugLevel=debugLevel), 'hotspot', name) 695 696class JVMCI9JDKConfig(mx.JDKConfig): 697 def __init__(self, debugLevel): 698 self.debugLevel = debugLevel 699 jdkBuildDir = _get_jdk_build_dir(debugLevel) 700 jdkDir = join(jdkBuildDir, 'images', 'jdk') if mx.get_opts().use_jdk_image else join(jdkBuildDir, 'jdk') 701 mx.JDKConfig.__init__(self, jdkDir, tag=_JVMCI_JDK_TAG) 702 703 def parseVmArgs(self, args, addDefaultArgs=True): 704 args = mx.expand_project_in_args(args, insitu=False) 705 jacocoArgs = mx_gate.get_jacoco_agent_args() 706 if jacocoArgs: 707 args = jacocoArgs + args 708 709 args = ['-Xbootclasspath/p:' + dep.classpath_repr() for dep in _jvmci_bootclasspath_prepends] + args 710 711 # Remove JVMCI jars from class path. They are only necessary when 712 # compiling with a javac from JDK8 or earlier. 713 cpIndex, cp = mx.find_classpath_arg(args) 714 if cp: 715 excluded = frozenset([dist.path for dist in _suite.dists]) 716 cp = os.pathsep.join([e for e in cp.split(os.pathsep) if e not in excluded]) 717 args[cpIndex] = cp 718 719 if '-version' in args: 720 ignoredArgs = args[args.index('-version') + 1:] 721 if len(ignoredArgs) > 0: 722 mx.log("Warning: The following options will be ignored by the vm because they come after the '-version' argument: " + ' '.join(ignoredArgs)) 723 return self.processArgs(args, addDefaultArgs=addDefaultArgs) 724 725 # Overrides JDKConfig 726 def run_java(self, args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, env=None, addDefaultArgs=True): 727 if vm is None: 728 vm = 'server' 729 730 args = self.parseVmArgs(args, addDefaultArgs=addDefaultArgs) 731 732 jvmciModeArgs = _jvmciModes[_vm.jvmciMode] 733 cmd = [self.java] + ['-' + vm] + jvmciModeArgs + args 734 return mx.run(cmd, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd) 735 736""" 737The dict of JVMCI JDKs indexed by debug-level names. 738""" 739_jvmci_jdks = {} 740 741def get_jvmci_jdk(debugLevel=None): 742 """ 743 Gets the JVMCI JDK corresponding to 'debugLevel'. 744 """ 745 if not debugLevel: 746 debugLevel = _vm.debugLevel 747 jdk = _jvmci_jdks.get(debugLevel) 748 if jdk is None: 749 try: 750 jdk = JVMCI9JDKConfig(debugLevel) 751 except mx.JDKConfigException as e: 752 jdkBuildDir = _get_jdk_build_dir(debugLevel) 753 msg = 'Error with the JDK built into {}:\n{}\nTry (re)building it with: mx --jdk-debug-level={} make' 754 if mx.get_opts().use_jdk_image: 755 msg += ' images' 756 mx.abort(msg.format(jdkBuildDir, e.message, debugLevel)) 757 _jvmci_jdks[debugLevel] = jdk 758 return jdk 759 760class JVMCI9JDKFactory(mx.JDKFactory): 761 def getJDKConfig(self): 762 jdk = get_jvmci_jdk(_vm.debugLevel) 763 return jdk 764 765 def description(self): 766 return "JVMCI JDK" 767 768mx.update_commands(_suite, { 769 'make': [_runmake, '[args...]', _makehelp], 770 'multimake': [_runmultimake, '[options]'], 771 'c1visualizer' : [c1visualizer, ''], 772 'hsdis': [hsdis, '[att]'], 773 'hcfdis': [hcfdis, ''], 774 'igv' : [igv, ''], 775 'jol' : [jol, ''], 776 'vm': [run_vm, '[-options] class [args...]'], 777}) 778 779mx.add_argument('-M', '--jvmci-mode', action='store', choices=sorted(_jvmciModes.viewkeys()), help='the JVM variant type to build/run (default: ' + _vm.jvmciMode + ')') 780mx.add_argument('--jdk-jvm-variant', '--vm', action='store', choices=_jdkJvmVariants + sorted(_legacyVms.viewkeys()), help='the JVM variant type to build/run (default: ' + _vm.jvmVariant + ')') 781mx.add_argument('--jdk-debug-level', '--vmbuild', action='store', choices=_jdkDebugLevels + sorted(_legacyVmbuilds.viewkeys()), help='the JDK debug level to build/run (default: ' + _vm.debugLevel + ')') 782mx.add_argument('-I', '--use-jdk-image', action='store_true', help='build/run JDK image instead of exploded JDK') 783 784mx.addJDKFactory(_JVMCI_JDK_TAG, mx.JavaCompliance('9'), JVMCI9JDKFactory()) 785 786def mx_post_parse_cmd_line(opts): 787 mx.set_java_command_default_jdk_tag(_JVMCI_JDK_TAG) 788 789 jdkTag = mx.get_jdk_option().tag 790 791 jvmVariant = None 792 debugLevel = None 793 jvmciMode = None 794 795 if opts.jdk_jvm_variant is not None: 796 jvmVariant = opts.jdk_jvm_variant 797 if jdkTag and jdkTag != _JVMCI_JDK_TAG: 798 mx.warn('Ignoring "--jdk-jvm-variant" option as "--jdk" tag is not "' + _JVMCI_JDK_TAG + '"') 799 800 if opts.jdk_debug_level is not None: 801 debugLevel = _translateLegacyDebugLevel(opts.jdk_debug_level) 802 if jdkTag and jdkTag != _JVMCI_JDK_TAG: 803 mx.warn('Ignoring "--jdk-debug-level" option as "--jdk" tag is not "' + _JVMCI_JDK_TAG + '"') 804 805 if opts.jvmci_mode is not None: 806 jvmciMode = opts.jvmci_mode 807 if jdkTag and jdkTag != _JVMCI_JDK_TAG: 808 mx.warn('Ignoring "--jvmci-mode" option as "--jdk" tag is not "' + _JVMCI_JDK_TAG + '"') 809 810 _vm.update(jvmVariant, debugLevel, jvmciMode) 811