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