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