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