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