From d07c63cf39b1ca0ad5d8922261461b27a52be5b7 Mon Sep 17 00:00:00 2001 From: James Graham Date: Thu, 13 Aug 2015 13:04:58 +0100 Subject: [PATCH 001/131] Bug 1181520 - Remove support for passing in reftest arguments via the command line, r=jmaher This unifies how reftests are invoked across desktop and mobile, and paves the way for introducing more complex datatypes that are unreasonable to express on the command line. --- layout/tools/reftest/reftest-cmdline.js | 33 +------------------------ layout/tools/reftest/reftest.js | 19 -------------- layout/tools/reftest/runreftest.py | 3 ++- 3 files changed, 3 insertions(+), 52 deletions(-) diff --git a/layout/tools/reftest/reftest-cmdline.js b/layout/tools/reftest/reftest-cmdline.js index fde70c9c04ae..5094f6b8bdc2 100644 --- a/layout/tools/reftest/reftest-cmdline.js +++ b/layout/tools/reftest/reftest-cmdline.js @@ -21,37 +21,6 @@ RefTestCmdLineHandler.prototype = /* nsICommandLineHandler */ handle : function handler_handle(cmdLine) { - var args = { }; - args.wrappedJSObject = args; - try { - var uristr = cmdLine.handleFlagWithParam("reftest", false); - if (uristr == null) - return; - try { - args.uri = cmdLine.resolveURI(uristr).spec; - } - catch (e) { - return; - } - } - catch (e) { - cmdLine.handleFlag("reftest", true); - } - - try { - var nocache = cmdLine.handleFlag("reftestnocache", false); - args.nocache = nocache; - } - catch (e) { - } - - try { - var skipslowtests = cmdLine.handleFlag("reftestskipslowtests", false); - args.skipslowtests = skipslowtests; - } - catch (e) { - } - /* Ignore the platform's online/offline status while running reftests. */ var ios = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService2); @@ -78,7 +47,7 @@ RefTestCmdLineHandler.prototype = function loadReftests() { wwatch.openWindow(null, "chrome://reftest/content/reftest.xul", "_blank", - "chrome,dialog=no,all", args); + "chrome,dialog=no,all", {}); } var remote = false; diff --git a/layout/tools/reftest/reftest.js b/layout/tools/reftest/reftest.js index 8bd0ed039d5b..b8b5ba73219d 100644 --- a/layout/tools/reftest/reftest.js +++ b/layout/tools/reftest/reftest.js @@ -450,7 +450,6 @@ function Shuffle(array) function StartTests() { var uri; -#if BOOTSTRAP /* These prefs are optional, so we don't need to spit an error to the log */ try { var prefs = Components.classes["@mozilla.org/preferences-service;1"]. @@ -487,24 +486,6 @@ function StartTests() gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | Unable to find reftest.uri pref. Please ensure your profile is setup properly\n"); DoneTests(); } -#else - try { - // Need to read the manifest once we have gHttpServerPort.. - var args = window.arguments[0].wrappedJSObject; - - if ("nocache" in args && args["nocache"]) - gNoCanvasCache = true; - - if ("skipslowtests" in args && args.skipslowtests) - gRunSlowTests = false; - - uri = args.uri; - } catch (e) { - ++gTestResults.Exception; - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n"); - DoneTests(); - } -#endif if (gShuffle) { gNoCanvasCache = true; diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py index 2c5bb2016150..32d18f68ba1a 100644 --- a/layout/tools/reftest/runreftest.py +++ b/layout/tools/reftest/runreftest.py @@ -205,6 +205,7 @@ class RefTest(object): if options.shuffle: prefs['reftest.shuffle'] = True prefs['reftest.focusFilterMode'] = options.focusFilterMode + prefs['reftest.uri'] = "file://%s" % os.path.abspath(manifest) # Ensure that telemetry is disabled, so we don't connect to the telemetry # server in the middle of the tests. @@ -610,7 +611,7 @@ class RefTest(object): try: reftestlist = self.getManifestPath(testPath) if cmdlineArgs == None: - cmdlineArgs = ['-reftest', reftestlist] + cmdlineArgs = [] profile = self.createReftestProfile(options, reftestlist) profileDir = profile.profile # name makes more sense From 805aa4b0bfef788a3640d8c19fb2f962619135f4 Mon Sep 17 00:00:00 2001 From: James Graham Date: Tue, 25 Aug 2015 14:07:23 +0100 Subject: [PATCH 002/131] Bug 1181516 - Allow reftests to take paths to multiple directories containing tests on the command line, r=jmaher This makes reftest command line arguments behave more like other test suites, so we can use a simple unified syntax for e.g. |mach try|. The patch also reworks the command line argument parsing to use argparse rather than optparse, and causes mach to reuse the same parser as the suite. --- layout/tools/reftest/Makefile.in | 1 + layout/tools/reftest/b2g_desktop.py | 23 +- layout/tools/reftest/mach_commands.py | 471 ++++--------- layout/tools/reftest/reftest.js | 62 +- layout/tools/reftest/reftestcommandline.py | 740 +++++++++++++++++++++ layout/tools/reftest/remotereftest.py | 222 +------ layout/tools/reftest/runreftest.py | 334 +++------- layout/tools/reftest/runreftestb2g.py | 254 +------ testing/testsuite-targets.mk | 4 +- 9 files changed, 1077 insertions(+), 1034 deletions(-) create mode 100644 layout/tools/reftest/reftestcommandline.py diff --git a/layout/tools/reftest/Makefile.in b/layout/tools/reftest/Makefile.in index 044ae5fc1a61..f64b2351a26f 100644 --- a/layout/tools/reftest/Makefile.in +++ b/layout/tools/reftest/Makefile.in @@ -7,6 +7,7 @@ _DEST_DIR = $(DEPTH)/_tests/reftest _HARNESS_FILES = \ $(srcdir)/runreftest.py \ + $(srcdir)/reftestcommandline.py \ $(srcdir)/remotereftest.py \ $(srcdir)/runreftestb2g.py \ $(srcdir)/b2g_desktop.py \ diff --git a/layout/tools/reftest/b2g_desktop.py b/layout/tools/reftest/b2g_desktop.py index 97a104b58fe5..45c0cd6c6942 100644 --- a/layout/tools/reftest/b2g_desktop.py +++ b/layout/tools/reftest/b2g_desktop.py @@ -9,7 +9,7 @@ import sys here = os.path.abspath(os.path.dirname(__file__)) -from runreftest import RefTest, ReftestOptions +from runreftest import RefTest from marionette_driver import expected from marionette_driver.by import By @@ -51,12 +51,10 @@ class B2GDesktopReftest(RefTest): f.close() self.marionette.execute_script(self.test_script) - def run_tests(self, test_path, options): - reftestlist = self.getManifestPath(test_path) - if not reftestlist.startswith('file://'): - reftestlist = 'file://%s' % reftestlist + def run_tests(self, tests, options): + manifests = self.resolver.resolveManifests(options, tests) - self.profile = self.create_profile(options, reftestlist, + self.profile = self.create_profile(options, manifests, profile_to_clone=options.profile) env = self.buildBrowserEnv(options, self.profile.profile) kp_kwargs = { 'processOutputLine': [self._on_output], @@ -107,8 +105,8 @@ class B2GDesktopReftest(RefTest): log.info("%s | Running tests: end.", os.path.basename(__file__)) return status - def create_profile(self, options, reftestlist, profile_to_clone=None): - profile = RefTest.createReftestProfile(self, options, reftestlist, + def create_profile(self, options, manifests, profile_to_clone=None): + profile = RefTest.createReftestProfile(self, options, manifests, profile_to_clone=profile_to_clone) prefs = {} @@ -136,7 +134,6 @@ class B2GDesktopReftest(RefTest): prefs["network.dns.localDomains"] = "app://test-container.gaiamobile.org" prefs["reftest.browser.iframe.enabled"] = False prefs["reftest.remote"] = False - prefs["reftest.uri"] = "%s" % reftestlist # Set a future policy version to avoid the telemetry prompt. prefs["toolkit.telemetry.prompted"] = 999 prefs["toolkit.telemetry.notifiedOptOut"] = 999 @@ -192,7 +189,7 @@ class MuletReftest(B2GDesktopReftest): Wait(self.marionette, timeout).until(expected.element_present( By.CSS_SELECTOR, '#homescreen[loading-state=false]')) -def run_desktop_reftests(parser, options, args): +def run_desktop_reftests(parser, options): marionette_args = {} if options.marionette: host, port = options.marionette.split(':') @@ -204,9 +201,7 @@ def run_desktop_reftests(parser, options, args): else: reftest = B2GDesktopReftest(marionette_args) - options = ReftestOptions.verifyCommonOptions(parser, options, reftest) - if options == None: - sys.exit(1) + parser.validate(options, reftest) # add a -bin suffix if b2g-bin exists, but just b2g was specified if options.app[-4:] != '-bin': @@ -219,4 +214,4 @@ def run_desktop_reftests(parser, options, args): if options.desktop and not options.profile: raise Exception("must specify --profile when specifying --desktop") - sys.exit(reftest.run_tests(args[0], options)) + sys.exit(reftest.run_tests(options.tests, options)) diff --git a/layout/tools/reftest/mach_commands.py b/layout/tools/reftest/mach_commands.py index e4b13e5f8204..7237e05bfdf0 100644 --- a/layout/tools/reftest/mach_commands.py +++ b/layout/tools/reftest/mach_commands.py @@ -23,8 +23,7 @@ from mach.decorators import ( Command, ) - -DEBUGGER_HELP = 'Debugger binary to run test in. Program name or path.' +import reftestcommandline ADB_NOT_FOUND = ''' The %s command requires the adb binary to be on your path. @@ -81,43 +80,10 @@ class ReftestRunner(MozbuildObject): self.tests_dir = os.path.join(self.topobjdir, '_tests') self.reftest_dir = os.path.join(self.tests_dir, 'reftest') - def _manifest_file(self, suite): - """Returns the manifest file used for a given test suite.""" - files = { - 'reftest': 'reftest.list', - 'reftest-ipc': 'reftest.list', - 'crashtest': 'crashtests.list', - 'crashtest-ipc': 'crashtests.list', - 'jstestbrowser': 'jstests.list' - } - assert suite in files - return files[suite] - - def _find_manifest(self, suite, test_file): - """Return a tuple of (manifest-path, filter-string) for running test_file. - - test_file can be a relative path to a single test file or manifest from - the top source directory, an absolute path to the same, or a directory - containing a manifest. - """ - assert test_file - path_arg = self._wrap_path_argument(test_file) - relpath = path_arg.relpath() - - if os.path.isdir(path_arg.srcdir_path()): - return (mozpath.join(relpath, self._manifest_file(suite)), None) - - if relpath.endswith('.list'): - return (relpath, None) - - return (self._find_manifest(suite, mozpath.dirname(test_file))[0], - mozpath.basename(test_file)) - def _make_shell_string(self, s): return "'%s'" % re.sub("'", r"'\''", s) - def run_b2g_test(self, b2g_home=None, xre_path=None, test_file=None, - suite=None, filter=None, **kwargs): + def run_b2g_test(self, b2g_home=None, xre_path=None, **kwargs): """Runs a b2g reftest. filter is a regular expression (in JS syntax, as could be passed to the @@ -130,324 +96,175 @@ class ReftestRunner(MozbuildObject): suite is the type of reftest to run. It can be one of ('reftest', 'crashtest'). """ - if suite not in ('reftest', 'crashtest'): + if kwargs["suite"] not in ('reftest', 'crashtest'): raise Exception('None or unrecognized reftest suite type.') + sys.path.insert(0, self.reftest_dir) + + test_subdir = {"reftest": os.path.join('layout', 'reftests'), + "crashtest": os.path.join('layout', 'crashtest')}[kwargs["suite"]] + # Find the manifest file - if not test_file: - if suite == 'reftest': - test_file = mozpath.join('layout', 'reftests') - elif suite == 'crashtest': - test_file = mozpath.join('testing', 'crashtest') + if not kwargs["tests"]: + if not os.path.exists(os.path.join(self.topsrcdir, test_subdir)): + test_file = mozpath.relpath(os.path.abspath(test_subdir), + self.topsrcdir) + kwargs["tests"] = [test_subdir] - if not os.path.exists(os.path.join(self.topsrcdir, test_file)): - test_file = mozpath.relpath(os.path.abspath(test_file), - self.topsrcdir) - - (manifest, single_file_filter) = self._find_manifest(suite, test_file) - if not os.path.exists(mozpath.join(self.topsrcdir, manifest)): - raise Exception('No manifest file was found at %s.' % manifest) - if single_file_filter: - if filter: - raise Exception('Cannot run single files in conjunction with --filter') - filter = single_file_filter - - # Need to chdir to reftest_dir otherwise imports fail below. - os.chdir(self.reftest_dir) - - # The imp module can spew warnings if the modules below have - # already been imported, ignore them. - with warnings.catch_warnings(): - warnings.simplefilter('ignore') - - import imp - path = os.path.join(self.reftest_dir, 'runreftestb2g.py') - with open(path, 'r') as fh: - imp.load_module('reftest', fh, path, ('.py', 'r', imp.PY_SOURCE)) - import reftest - - # Set up the reftest options. - parser = reftest.B2GOptions() - options, args = parser.parse_args([]) - - # Tests need to be served from a subdirectory of the server. Symlink - # topsrcdir here to get around this. tests = os.path.join(self.reftest_dir, 'tests') if not os.path.isdir(tests): os.symlink(self.topsrcdir, tests) - args.insert(0, os.path.join('tests', manifest)) - for k, v in kwargs.iteritems(): - setattr(options, k, v) + for i, path in enumerate(kwargs["tests"]): + # Non-absolute paths are relative to the packaged directory, which + # has an extra tests/ at the start + if os.path.exists(os.path.abspath(path)): + path = os.path.relpath(path, os.path.join(self.topsrcdir)) + kwargs["tests"][i] = os.path.join('tests', path) if conditions.is_b2g_desktop(self): - if self.substs.get('ENABLE_MARIONETTE') != '1': - print(MARIONETTE_DISABLED % ('mochitest-b2g-desktop', - self.mozconfig['path'])) - return 1 + return self.run_b2g_desktop(**kwargs) - options.profile = options.profile or os.environ.get('GAIA_PROFILE') - if not options.profile: + return self.run_b2g_remote(b2g_home, xre_path, **kwargs) + + def run_b2g_desktop(self, **kwargs): + if self.substs.get('ENABLE_MARIONETTE') != '1': + print(MARIONETTE_DISABLED % ('mochitest-b2g-desktop', + self.mozconfig['path'])) + return 1 + + if not kwargs["profile"]: + gaia_profile = os.environ.get('GAIA_PROFILE') + if not gaia_profile: print(GAIA_PROFILE_NOT_FOUND % 'reftest-b2g-desktop') return 1 + kwargs["profile"] = gaia_profile - if os.path.isfile(os.path.join(options.profile, 'extensions', \ - 'httpd@gaiamobile.org')): - print(GAIA_PROFILE_IS_DEBUG % ('mochitest-b2g-desktop', - options.profile)) - return 1 - options.desktop = True - options.app = self.get_binary_path() - if options.oop: - options.browser_arg = '-oop' - if not options.app.endswith('-bin'): - options.app = '%s-bin' % options.app - if not os.path.isfile(options.app): - options.app = options.app[:-len('-bin')] + if os.path.isfile(os.path.join(kwargs["profile"], 'extensions', + 'httpd@gaiamobile.org')): + print(GAIA_PROFILE_IS_DEBUG % ('mochitest-b2g-desktop', + kwargs["profile"])) + return 1 - return reftest.run_desktop_reftests(parser, options, args) + kwargs["desktop"] = True + kwargs["app"] = self.get_binary_path() + if kwargs["oop"]: + options.browser_arg = '-oop' + if not kwargs["app"].endswith('-bin'): + kwargs["app"] = '%s-bin' % options.app + if not os.path.isfile(kwargs["app"]): + options.app = kwargs["app"][:-len('-bin')] + return runreftestb2g.run(**kwargs) + + def run_b2g_remote(self, b2g_home, xre_path, **kwargs): + import runreftestb2g try: which.which('adb') except which.WhichError: # TODO Find adb automatically if it isn't on the path - raise Exception(ADB_NOT_FOUND % ('%s-remote' % suite, b2g_home)) + raise Exception(ADB_NOT_FOUND % ('%s-remote' % kwargs["suite"], b2g_home)) - options.b2gPath = b2g_home - options.logdir = self.reftest_dir - options.httpdPath = os.path.join(self.topsrcdir, 'netwerk', 'test', 'httpserver') - options.xrePath = xre_path - options.ignoreWindowSize = True - options.filter = filter + kwargs["b2gPath"] = b2g_home + kwargs["logdir"] = self.reftest_dir + kwargs["httpdPath"] = os.path.join(self.topsrcdir, 'netwerk', 'test', 'httpserver') + kwargs["xrePath"] = xre_path + kwargs["ignoreWindowSize"] = True # Don't enable oop for crashtest until they run oop in automation - if suite == 'reftest': - options.oop = True + if kwargs["suite"] == 'reftest': + kwargs["oop"] = True - return reftest.run_remote_reftests(parser, options, args) + return runreftestb2g.run_remote(**kwargs) - def run_desktop_test(self, test_file=None, filter=None, suite=None, - debugger=None, debugger_args=None, parallel=False, shuffle=False, - e10s=False, extraPrefs=None, this_chunk=None, total_chunks=None): - """Runs a reftest. + def run_desktop_test(self, **kwargs): + """Runs a reftest.""" + import runreftest - test_file is a path to a test file. It can be a relative path from the - top source directory, an absolute filename, or a directory containing - test files. - - filter is a regular expression (in JS syntax, as could be passed to the - RegExp constructor) to select which reftests to run from the manifest. - - suite is the type of reftest to run. It can be one of ('reftest', - 'crashtest', 'jstestbrowser'). - - debugger is the program name (in $PATH) or the full path of the - debugger to run. - - debugger_args are the arguments passed to the debugger. - - parallel indicates whether tests should be run in parallel or not. - - shuffle indicates whether to run tests in random order. - """ - - if suite not in ('reftest', 'reftest-ipc', 'crashtest', 'crashtest-ipc', 'jstestbrowser'): + if kwargs["suite"] not in ('reftest', 'crashtest', 'jstestbrowser'): raise Exception('None or unrecognized reftest suite type.') - env = {} - extra_args = [] + default_manifest = { + "reftest": (self.topsrcdir, "layout", "reftests", "reftest.list"), + "crashtest": (self.topsrcdir, "testing", "crashtest", "crashtests.list"), + "jstestbrowser": (self.topobjdir, "dist", "test-stage", "jsreftest", "tests", + "jstests.list") + } - if test_file: - (path, single_file_filter) = self._find_manifest(suite, test_file) - if not os.path.exists(mozpath.join(self.topsrcdir, path)): - raise Exception('No manifest file was found at %s.' % path) - if single_file_filter: - if filter: - raise Exception('Cannot run single files in conjunction with --filter') - filter = single_file_filter - env[b'TEST_PATH'] = path - if filter: - extra_args.extend(['--filter', self._make_shell_string(filter)]) + kwargs["extraProfileFiles"] = [os.path.join(self.topobjdir, "dist", "plugins")] + kwargs["symbolsPath"] = os.path.join(self.topobjdir, "crashreporter-symbols") - pass_thru = False + if not kwargs["tests"]: + kwargs["tests"] = [os.path.join(*default_manifest[kwargs["suite"]])] - if debugger: - extra_args.append('--debugger=\'%s\'' % debugger) - pass_thru = True - if debugger_args: - # Use _make_shell_string (which quotes) so that we - # handle multiple args being passed to the debugger. - extra_args.extend(['--debugger-args', self._make_shell_string(debugger_args)]) - else: - if debugger_args: - print("--debugger-args passed, but no debugger specified.") - return 1 + if kwargs["suite"] == "jstestbrowser": + kwargs["extraProfileFiles"].append(os.path.join(self.topobjdir, "dist", + "test-stage", "jsreftest", + "tests", "user.js")) - if parallel: - extra_args.append('--run-tests-in-parallel') + if not kwargs["runTestsInParallel"]: + kwargs["logFile"] = "%s.log" % kwargs["suite"] - if shuffle: - extra_args.append('--shuffle') - - if e10s: - extra_args.append('--e10s') - - if extraPrefs: - for pref in extraPrefs: - extra_args.extend(['--setpref', pref]) - - if this_chunk: - extra_args.append('--this-chunk=%s' % this_chunk) - - if total_chunks: - extra_args.append('--total-chunks=%s' % total_chunks) - - if extra_args: - args = [os.environ.get(b'EXTRA_TEST_ARGS', '')] - args.extend(extra_args) - env[b'EXTRA_TEST_ARGS'] = ' '.join(args) - - # TODO hook up harness via native Python - return self._run_make(directory='.', target=suite, append_env=env, - pass_thru=pass_thru, ensure_exit_code=False) - - -def ReftestCommand(func): - """Decorator that adds shared command arguments to reftest commands.""" - - debugger = CommandArgument('--debugger', metavar='DEBUGGER', - help=DEBUGGER_HELP) - func = debugger(func) - - debugger_args = CommandArgument('--debugger-args', metavar='DEBUGGER_ARGS', - help='Arguments to pass to the debugger.') - func = debugger_args(func) - - flter = CommandArgument('--filter', metavar='REGEX', - help='A JS regular expression to match test URLs against, to select ' - 'a subset of tests to run.') - func = flter(func) - - path = CommandArgument('test_file', nargs='?', metavar='MANIFEST', - help='Reftest manifest file, or a directory in which to select ' - 'reftest.list. If omitted, the entire test suite is executed.') - func = path(func) - - parallel = CommandArgument('--parallel', action='store_true', - help='Run tests in parallel.') - func = parallel(func) - - shuffle = CommandArgument('--shuffle', action='store_true', - help='Run tests in random order.') - func = shuffle(func) - - e10s = CommandArgument('--e10s', action='store_true', - help='Use content processes.') - func = e10s(func) - - extraPrefs = CommandArgument('--setpref', action='append', - default=[], dest='extraPrefs', metavar='PREF=VALUE', - help='Set prefs in the reftest profile.') - func = extraPrefs(func) - - totalChunks = CommandArgument('--total-chunks', - help = 'How many chunks to split the tests up into.') - func = totalChunks(func) - - thisChunk = CommandArgument('--this-chunk', - help = 'Which chunk to run between 1 and --total-chunks.') - func = thisChunk(func) - - return func - -def B2GCommand(func): - """Decorator that adds shared command arguments to b2g reftest commands.""" - - busybox = CommandArgument('--busybox', default=None, - help='Path to busybox binary to install on device') - func = busybox(func) - - logdir = CommandArgument('--logdir', default=None, - help='directory to store log files') - func = logdir(func) - - sdcard = CommandArgument('--sdcard', default="10MB", - help='Define size of sdcard: 1MB, 50MB...etc') - func = sdcard(func) - - emulator_res = CommandArgument('--emulator-res', default='800x1000', - help='Emulator resolution of the format \'x\'') - func = emulator_res(func) - - marionette = CommandArgument('--marionette', default=None, - help='host:port to use when connecting to Marionette') - func = marionette(func) - - totalChunks = CommandArgument('--total-chunks', dest='totalChunks', - type = int, - help = 'How many chunks to split the tests up into.') - func = totalChunks(func) - - thisChunk = CommandArgument('--this-chunk', dest='thisChunk', - type = int, - help = 'Which chunk to run between 1 and --total-chunks.') - func = thisChunk(func) - - flter = CommandArgument('--filter', metavar='REGEX', - help='A JS regular expression to match test URLs against, to select ' - 'a subset of tests to run.') - func = flter(func) - - oop = CommandArgument('--enable-oop', action='store_true', dest='oop', - help = 'Run tests in out-of-process mode.') - func = oop(func) - - path = CommandArgument('test_file', default=None, nargs='?', - metavar='TEST', - help='Test to run. Can be specified as a single file, a ' \ - 'directory, or omitted. If omitted, the entire test suite is ' \ - 'executed.') - func = path(func) - - return func + #Remove the stdout handler from the internal logger and let mach deal with it + runreftest.log.removeHandler(runreftest.log.handlers[0]) + self.log_manager.enable_unstructured() + rv = runreftest.run(**kwargs) + self.log_manager.disable_unstructured() + return rv @CommandProvider class MachCommands(MachCommandBase): - @Command('reftest', category='testing', description='Run reftests (layout and graphics correctness).') - @ReftestCommand - def run_reftest(self, test_file, **kwargs): - return self._run_reftest(test_file, suite='reftest', **kwargs) + @Command('reftest', + category='testing', + description='Run reftests (layout and graphics correctness).', + parser=reftestcommandline.DesktopArgumentsParser) + def run_reftest(self, **kwargs): + kwargs["suite"] = "reftest" + return self._run_reftest(**kwargs) - @Command('jstestbrowser', category='testing', - description='Run js/src/tests in the browser.') - @ReftestCommand - def run_jstestbrowser(self, test_file, **kwargs): - return self._run_reftest(test_file, suite='jstestbrowser', **kwargs) + @Command('jstestbrowser', + category='testing', + description='Run js/src/tests in the browser.', + parser=reftestcommandline.DesktopArgumentsParser) + def run_jstestbrowser(self, **kwargs): + self._mach_context.commands.dispatch("build", + self._mach_context, + what=["stage-jstests"]) + kwargs["suite"] = "jstestbrowser" + return self._run_reftest(**kwargs) - @Command('reftest-ipc', category='testing', - description='Run IPC reftests (layout and graphics correctness, separate process).') - @ReftestCommand - def run_ipc(self, test_file, **kwargs): - return self._run_reftest(test_file, suite='reftest-ipc', **kwargs) + @Command('reftest-ipc', + category='testing', + description='Run IPC reftests (layout and graphics correctness, separate process).', + parser=reftestcommandline.DesktopArgumentsParser) + def run_ipc(self, **kwargs): + kwargs["ipc"] = True + kwargs["suite"] = "reftest" + return self._run_reftest(**kwargs) - @Command('crashtest', category='testing', - description='Run crashtests (Check if crashes on a page).') - @ReftestCommand - def run_crashtest(self, test_file, **kwargs): - return self._run_reftest(test_file, suite='crashtest', **kwargs) + @Command('crashtest', + category='testing', + description='Run crashtests (Check if crashes on a page).', + parser=reftestcommandline.DesktopArgumentsParser) + def run_crashtest(self, **kwargs): + kwargs["suite"] = "crashtest" + return self._run_reftest(**kwargs) - @Command('crashtest-ipc', category='testing', - description='Run IPC crashtests (Check if crashes on a page, separate process).') - @ReftestCommand - def run_crashtest_ipc(self, test_file, **kwargs): - return self._run_reftest(test_file, suite='crashtest-ipc', **kwargs) + @Command('crashtest-ipc', + category='testing', + description='Run IPC crashtests (Check if crashes on a page, separate process).', + parser=reftestcommandline.DesktopArgumentsParser) + def run_crashtest_ipc(self, **kwargs): + kwargs["ipc"] = True + kwargs["suite"] = "crashtest" + return self._run_reftest(**kwargs) - def _run_reftest(self, test_file=None, suite=None, **kwargs): + def _run_reftest(self, **kwargs): reftest = self._spawn(ReftestRunner) - return reftest.run_desktop_test(test_file, suite=suite, **kwargs) + return reftest.run_desktop_test(**kwargs) # TODO For now b2g commands will only work with the emulator, @@ -466,27 +283,30 @@ class B2GCommands(MachCommandBase): setattr(self, attr, getattr(context, attr, None)) @Command('reftest-remote', category='testing', - description='Run a remote reftest (b2g layout and graphics correctness, remote device).', - conditions=[conditions.is_b2g, is_emulator]) - @B2GCommand - def run_reftest_remote(self, test_file, **kwargs): - return self._run_reftest(test_file, suite='reftest', **kwargs) + description='Run a remote reftest (b2g layout and graphics correctness, remote device).', + conditions=[conditions.is_b2g, is_emulator], + parser=reftestcommandline.B2GArgumentParser) + def run_reftest_remote(self, **kwargs): + kwargs["suite"] = "reftest" + return self._run_reftest(**kwargs) @Command('reftest-b2g-desktop', category='testing', - description='Run a b2g desktop reftest (b2g desktop layout and graphics correctness).', - conditions=[conditions.is_b2g_desktop]) - @B2GCommand - def run_reftest_b2g_desktop(self, test_file, **kwargs): - return self._run_reftest(test_file, suite='reftest', **kwargs) + description='Run a b2g desktop reftest (b2g desktop layout and graphics correctness).', + conditions=[conditions.is_b2g_desktop], + parser=reftestcommandline.B2GArgumentParser) + def run_reftest_b2g_desktop(self, **kwargs): + kwargs["suite"] = "reftest" + return self._run_reftest(**kwargs) @Command('crashtest-remote', category='testing', - description='Run a remote crashtest (Check if b2g crashes on a page, remote device).', - conditions=[conditions.is_b2g, is_emulator]) - @B2GCommand + description='Run a remote crashtest (Check if b2g crashes on a page, remote device).', + conditions=[conditions.is_b2g, is_emulator], + parser=reftestcommandline.B2GArgumentParser) def run_crashtest_remote(self, test_file, **kwargs): - return self._run_reftest(test_file, suite='crashtest', **kwargs) + kwargs["suite"] = "crashtest" + return self._run_reftest(**kwargs) - def _run_reftest(self, test_file=None, suite=None, **kwargs): + def _run_reftest(self, **kwargs): if self.device_name: if self.device_name.startswith('emulator'): emulator = 'arm' @@ -495,5 +315,4 @@ class B2GCommands(MachCommandBase): kwargs['emulator'] = emulator reftest = self._spawn(ReftestRunner) - return reftest.run_b2g_test(self.b2g_home, self.xre_path, - test_file, suite=suite, **kwargs) + return reftest.run_b2g_test(self.b2g_home, self.xre_path, **kwargs) diff --git a/layout/tools/reftest/reftest.js b/layout/tools/reftest/reftest.js index b8b5ba73219d..ca61a086b013 100644 --- a/layout/tools/reftest/reftest.js +++ b/layout/tools/reftest/reftest.js @@ -48,7 +48,7 @@ var gShuffle = false; var gTotalChunks = 0; var gThisChunk = 0; var gContainingWindow = null; -var gURLFilterRegex = null; +var gURLFilterRegex = {}; const FOCUS_FILTER_ALL_TESTS = "all"; const FOCUS_FILTER_NEEDS_FOCUS_TESTS = "needs-focus"; const FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS = "non-needs-focus"; @@ -389,10 +389,6 @@ function InitAndStartRefTests() gThisChunk = 0; } - try { - gURLFilterRegex = new RegExp(prefs.getCharPref("reftest.filter")); - } catch(e) {} - try { gFocusFilterMode = prefs.getCharPref("reftest.focusFilterMode"); } catch(e) {} @@ -449,7 +445,7 @@ function Shuffle(array) function StartTests() { - var uri; + var manifests; /* These prefs are optional, so we don't need to spit an error to the log */ try { var prefs = Components.classes["@mozilla.org/preferences-service;1"]. @@ -476,23 +472,29 @@ function StartTests() gRunSlowTests = false; } - try { - uri = prefs.getCharPref("reftest.uri"); - } catch(e) { - uri = ""; - } - - if (uri == "") { - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | Unable to find reftest.uri pref. Please ensure your profile is setup properly\n"); - DoneTests(); - } - if (gShuffle) { gNoCanvasCache = true; } + gURLs = []; + try { - ReadTopManifest(uri); + var manifests = JSON.parse(prefs.getCharPref("reftest.manifests")); + gURLFilterRegex = manifests[null]; + } catch(e) { + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | Unable to find reftest.manifests pref. Please ensure your profile is setup properly\n"); + DoneTests(); + } + + try { + var globalFilter = manifests.hasOwnProperty("") ? new RegExp(manifests[""]) : null; + var manifestURLs = Object.keys(manifests); + manifestURLs.sort(); + manifestURLs.forEach(function(manifestURL) { + gDumpLog("Readings manifest" + manifestURL + "\n"); + var pathFilters = manifests[manifestURL].map(function(x) {return new RegExp(x)}); + ReadTopManifest(manifestURL, [globalFilter, pathFilters]); + }); BuildUseCounts(); // Filter tests which will be skipped to get a more even distribution when chunking @@ -745,18 +747,22 @@ function AddPrefSettings(aWhere, aPrefName, aPrefValExpression, aSandbox, aTestP return true; } -function ReadTopManifest(aFileURL) +function ReadTopManifest(aFileURL, aFilters) { - gURLs = new Array(); var url = gIOService.newURI(aFileURL, null, null); if (!url) throw "Expected a file or http URL for the manifest."; - ReadManifest(url, EXPECTED_PASS); + ReadManifest(url, EXPECTED_PASS, aFilters); } -function AddTestItem(aTest) +function AddTestItem(aTest, aFilters) { - if (gURLFilterRegex && !gURLFilterRegex.test(aTest.url1.spec)) + if (!aFilters) + aFilters = [null, []]; + + if ((aFilters[0] && !aFilters[0].test(aTest.url1.spec)) || + (aFilters[1].length > 0 && + !aFilters[1].some(function(filter) {return filter.test(aTest.url1.spec)}))) return; if (gFocusFilterMode == FOCUS_FILTER_NEEDS_FOCUS_TESTS && !aTest.needsFocus) @@ -769,7 +775,7 @@ function AddTestItem(aTest) // Note: If you materially change the reftest manifest parsing, // please keep the parser in print-manifest-dirs.py in sync. -function ReadManifest(aURL, inherited_status) +function ReadManifest(aURL, inherited_status, aFilters) { var secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID] .getService(CI.nsIScriptSecurityManager); @@ -986,7 +992,7 @@ function ReadManifest(aURL, inherited_status) var incURI = gIOService.newURI(items[1], null, listURL); secMan.checkLoadURIWithPrincipal(principal, incURI, CI.nsIScriptSecurityManager.DISALLOW_SCRIPT); - ReadManifest(incURI, expected_status); + ReadManifest(incURI, expected_status, aFilters); } else if (items[0] == TYPE_LOAD) { if (items.length != 2) throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to load"; @@ -1016,7 +1022,7 @@ function ReadManifest(aURL, inherited_status) fuzzyMaxPixels: fuzzy_max_pixels, url1: testURI, url2: null, - chaosMode: chaosMode }); + chaosMode: chaosMode }, aFilters); } else if (items[0] == TYPE_SCRIPT) { if (items.length != 2) throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to script"; @@ -1043,7 +1049,7 @@ function ReadManifest(aURL, inherited_status) fuzzyMaxPixels: fuzzy_max_pixels, url1: testURI, url2: null, - chaosMode: chaosMode }); + chaosMode: chaosMode }, aFilters); } else if (items[0] == TYPE_REFTEST_EQUAL || items[0] == TYPE_REFTEST_NOTEQUAL) { if (items.length != 3) throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to " + items[0]; @@ -1073,7 +1079,7 @@ function ReadManifest(aURL, inherited_status) fuzzyMaxPixels: fuzzy_max_pixels, url1: testURI, url2: refURI, - chaosMode: chaosMode }); + chaosMode: chaosMode }, aFilters); } else { throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": unknown test type " + items[0]; } diff --git a/layout/tools/reftest/reftestcommandline.py b/layout/tools/reftest/reftestcommandline.py new file mode 100644 index 000000000000..b258f9d48623 --- /dev/null +++ b/layout/tools/reftest/reftestcommandline.py @@ -0,0 +1,740 @@ +import argparse +import os +from collections import OrderedDict +from urlparse import urlparse + +here = os.path.abspath(os.path.dirname(__file__)) + + +class ReftestArgumentsParser(argparse.ArgumentParser): + def __init__(self, **kwargs): + super(ReftestArgumentsParser, self).__init__(**kwargs) + + # Try to import a MozbuildObject. Success indicates that we are + # running from a source tree. This allows some defaults to be set + # from the source tree. + try: + from mozbuild.base import MozbuildObject + self.build_obj = MozbuildObject.from_environment(cwd=here) + except ImportError: + self.build_obj = None + + self.add_argument("--xre-path", + action="store", + type=str, + dest="xrePath", + # individual scripts will set a sane default + default=None, + help="absolute path to directory containing XRE (probably xulrunner)") + + self.add_argument("--symbols-path", + action="store", + type=str, + dest="symbolsPath", + default=None, + help="absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols") + + self.add_argument("--debugger", + action="store", + dest="debugger", + help="use the given debugger to launch the application") + + self.add_argument("--debugger-args", + action="store", + dest="debuggerArgs", + help="pass the given args to the debugger _before_ " + "the application on the command line") + + self.add_argument("--debugger-interactive", + action="store_true", + dest="debuggerInteractive", + help="prevents the test harness from redirecting " + "stdout and stderr for interactive debuggers") + + self.add_argument("--appname", + action="store", + type=str, + dest="app", + default=None, + help="absolute path to application, overriding default") + + self.add_argument("--extra-profile-file", + action="append", + dest="extraProfileFiles", + default=[], + help="copy specified files/dirs to testing profile") + + self.add_argument("--timeout", + action="store", + dest="timeout", + type=int, + default=5 * 60, # 5 minutes per bug 479518 + help="reftest will timeout in specified number of seconds. [default %(default)s].") + + self.add_argument("--leak-threshold", + action="store", + type=int, + dest="defaultLeakThreshold", + default=0, + help="fail if the number of bytes leaked in default " + "processes through refcounted objects (or bytes " + "in classes with MOZ_COUNT_CTOR and MOZ_COUNT_DTOR) " + "is greater than the given number") + + self.add_argument("--utility-path", + action="store", + type=str, + dest="utilityPath", + default="bindir", + help="absolute path to directory containing utility " + "programs (xpcshell, ssltunnel, certutil)") + + self.add_argument("--total-chunks", + type=int, + dest="totalChunks", + help="how many chunks to split the tests up into") + + self.add_argument("--this-chunk", + type=int, + dest="thisChunk", + help="which chunk to run between 1 and --total-chunks") + + self.add_argument("--log-file", + action="store", + type=str, + dest="logFile", + default=None, + help="file to log output to in addition to stdout") + + self.add_argument("--skip-slow-tests", + dest="skipSlowTests", + action="store_true", + default=False, + help="skip tests marked as slow when running") + + self.add_argument("--ignore-window-size", + dest="ignoreWindowSize", + action="store_true", + default=False, + help="ignore the window size, which may cause spurious failures and passes") + + self.add_argument("--install-extension", + action="append", + dest="extensionsToInstall", + default=[], + help="install the specified extension in the testing profile. " + "The extension file's name should be .xpi where is " + "the extension's id as indicated in its install.rdf. " + "An optional path can be specified too.") + + self.add_argument("--setenv", + action="append", + type=str, + default=[], + dest="environment", + metavar="NAME=VALUE", + help="sets the given variable in the application's " + "environment") + + self.add_argument("--filter", + action="store", + type=str, + dest="filter", + help="specifies a regular expression (as could be passed to the JS " + "RegExp constructor) to test against URLs in the reftest manifest; " + "only test items that have a matching test URL will be run.") + + self.add_argument("--shuffle", + action="store_true", + default=False, + dest="shuffle", + help="run reftests in random order") + + self.add_argument("--focus-filter-mode", + action="store", + type=str, + dest="focusFilterMode", + default="all", + help="filters tests to run by whether they require focus. " + "Valid values are `all', `needs-focus', or `non-needs-focus'. " + "Defaults to `all'.") + + self.add_argument("--e10s", + action="store_true", + default=False, + dest="e10s", + help="enables content processes") + + self.add_argument("--setpref", + action="append", + type=str, + default=[], + dest="extraPrefs", + metavar="PREF=VALUE", + help="defines an extra user preference") + + self.add_argument("--reftest-extension-path", + action="store", + dest="reftestExtensionPath", + help="Path to the reftest extension") + + self.add_argument("--special-powers-extension-path", + action="store", + dest="specialPowersExtensionPath", + help="Path to the special powers extension") + + self.add_argument("--suite", + choices=["reftest", "crashtest", "jstestbrowser"], + default=None, + help=argparse.SUPPRESS) + + self.add_argument("tests", + metavar="TEST_PATH", + nargs="*", + help="Path to test file, manifest file, or directory containing tests") + + def get_ip(self): + import moznetwork + if os.name != "nt": + return moznetwork.get_ip() + else: + self.error( + "ERROR: you must specify a --remote-webserver=\n") + + def set_default_suite(self, options): + manifests = OrderedDict([("reftest.list", "reftest"), + ("crashtests.list", "crashtest"), + ("jstests.list", "jstestbrowser")]) + + for test_path in options.tests: + file_name = os.path.basename(test_path) + if file_name in manifests: + options.suite = manifests[file_name] + return + + for test_path in options.tests: + for manifest_file, suite in manifests.iteritems(): + if os.path.exists(os.path.join(test_path, manifest_file)): + options.suite = suite + return + + self.error("Failed to determine test suite; supply --suite to set this explicitly") + + def validate(self, options, reftest): + import sys + + if not options.tests: + # Can't just set this in the argument parser because mach will set a default + self.error("Must supply at least one path to a manifest file, test directory, or test file to run.") + + if options.suite is None: + self.set_default_suite(options) + + if options.totalChunks is not None and options.thisChunk is None: + self.error( + "thisChunk must be specified when totalChunks is specified") + + if options.totalChunks: + if not 1 <= options.thisChunk <= options.totalChunks: + self.error("thisChunk must be between 1 and totalChunks") + + if options.logFile: + options.logFile = reftest.getFullPath(options.logFile) + + if options.xrePath is not None: + if not os.access(options.xrePath, os.F_OK): + self.error("--xre-path '%s' not found" % options.xrePath) + if not os.path.isdir(options.xrePath): + self.error("--xre-path '%s' is not a directory" % + options.xrePath) + options.xrePath = reftest.getFullPath(options.xrePath) + + if options.reftestExtensionPath is None: + if self.build_obj is not None: + options.reftestExtensionPath = os.path.join(self.build_obj.topobjdir, "_tests", + "reftest", "reftest") + else: + options.reftestExtensionPath = os.path.join(here, "reftest") + + if (options.specialPowersExtensionPath is None and + options.suite in ["crashtest", "jstestbrowser"]): + if self.build_obj is not None: + options.specialPowersExtensionPath = os.path.join(self.build_obj.topobjdir, "_tests", + "reftest", "specialpowers") + else: + options.specialPowersExtensionPath = os.path.join( + here, "specialpowers") + + options.leakThresholds = { + "default": options.defaultLeakThreshold, + "tab": 5000, # See dependencies of bug 1051230. + } + + +class DesktopArgumentsParser(ReftestArgumentsParser): + def __init__(self, **kwargs): + super(DesktopArgumentsParser, self).__init__(**kwargs) + + self.add_argument("--run-tests-in-parallel", + action="store_true", + default=False, + dest="runTestsInParallel", + help="run tests in parallel if possible") + + self.add_argument("--ipc", + action="store_true", + default=False, + help="Run in out-of-processes mode") + + def _prefs_oop(self): + import mozinfo + prefs = ["layers.async-pan-zoom.enabled=true", + "browser.tabs.remote.autostart=true"] + if mozinfo.os == "win": + prefs.append("layers.acceleration.disabled=true") + + return prefs + + def _prefs_gpu(self): + if mozinfo.os != "win": + return ["layers.acceleration.force-enabled=true"] + return [] + + def validate(self, options, reftest): + super(DesktopArgumentsParser, self).validate(options, reftest) + + if options.ipc: + for item in self._prefs_oop(): + if item not in options.extraPrefs: + options.extraPrefs.append(item) + + if options.runTestsInParallel: + if options.logFile is not None: + self.error("cannot specify logfile with parallel tests") + if options.totalChunks is not None or options.thisChunk is not None: + self.error( + "cannot specify thisChunk or totalChunks with parallel tests") + if options.focusFilterMode != "all": + self.error("cannot specify focusFilterMode with parallel tests") + if options.debugger is not None: + self.error("cannot specify a debugger with parallel tests") + + if not options.tests: + self.error("No test files specified.") + + if options.app is None: + bin_dir = (self.build_obj.get_binary_path() if + self.build_obj and self.build_obj.substs[ + 'MOZ_BUILD_APP'] != 'mobile/android' + else None) + + if bin_dir: + options.app = bin_dir + else: + self.error( + "could not find the application path, --appname must be specified") + + options.app = reftest.getFullPath(options.app) + if not os.path.exists(options.app): + self.error("""Error: Path %(app)s doesn't exist. + Are you executing $objdir/_tests/reftest/runreftest.py?""" + % {"app": options.app}) + + if options.xrePath is None: + options.xrePath = os.path.dirname(options.app) + + if options.symbolsPath and len(urlparse(options.symbolsPath).scheme) < 2: + options.symbolsPath = reftest.getFullPath(options.symbolsPath) + + options.utilityPath = reftest.getFullPath(options.utilityPath) + + +class B2GArgumentParser(ReftestArgumentsParser): + def __init__(self, **kwargs): + super(B2GArgumentParser, self).__init__(**kwargs) + + self.add_argument("--browser-arg", + action="store", + type=str, + dest="browser_arg", + help="Optional command-line arg to pass to the browser") + + self.add_argument("--b2gpath", + action="store", + type=str, + dest="b2gPath", + help="path to B2G repo or qemu dir") + + self.add_argument("--marionette", + action="store", + type=str, + dest="marionette", + help="host:port to use when connecting to Marionette") + + self.add_argument("--emulator", + action="store", + type=str, + dest="emulator", + help="Architecture of emulator to use: x86 or arm") + + self.add_argument("--emulator-res", + action="store", + type=str, + dest="emulator_res", + help="Emulator resolution of the format 'x'") + + self.add_argument("--no-window", + action="store_true", + dest="noWindow", + default=False, + help="Pass --no-window to the emulator") + + self.add_argument("--adbpath", + action="store", + type=str, + dest="adb_path", + default="adb", + help="path to adb") + + self.add_argument("--deviceIP", + action="store", + type=str, + dest="deviceIP", + help="ip address of remote device to test") + + self.add_argument("--devicePort", + action="store", + type=str, + dest="devicePort", + default="20701", + help="port of remote device to test") + + self.add_argument("--remote-logfile", + action="store", + type=str, + dest="remoteLogFile", + help="Name of log file on the device relative to the device root. PLEASE ONLY USE A FILENAME.") + + self.add_argument("--remote-webserver", + action="store", + type=str, + dest="remoteWebServer", + help="ip address where the remote web server is hosted at") + + self.add_argument("--http-port", + action="store", + type=str, + dest="httpPort", + help="ip address where the remote web server is hosted at") + + self.add_argument("--ssl-port", + action="store", + type=str, + dest="sslPort", + help="ip address where the remote web server is hosted at") + + self.add_argument("--pidfile", + action="store", + type=str, + dest="pidFile", + default="", + help="name of the pidfile to generate") + + self.add_argument("--gecko-path", + action="store", + type=str, + dest="geckoPath", + help="the path to a gecko distribution that should " + "be installed on the emulator prior to test") + + self.add_argument("--logdir", + action="store", + type=str, + dest="logdir", + help="directory to store log files") + + self.add_argument('--busybox', + action='store', + type=str, + dest='busybox', + help="Path to busybox binary to install on device") + + self.add_argument("--httpd-path", + action="store", + type=str, + dest="httpdPath", + help="path to the httpd.js file") + + self.add_argument("--profile", + action="store", + type=str, + dest="profile", + help="for desktop testing, the path to the " + "gaia profile to use") + + self.add_argument("--desktop", + action="store_true", + dest="desktop", + default=False, + help="Run the tests on a B2G desktop build") + + self.add_argument("--mulet", + action="store_true", + dest="mulet", + default=False, + help="Run the tests on a B2G desktop build") + + self.add_argument("--enable-oop", + action="store_true", + dest="oop", + default=False, + help="Run the tests out of process") + + self.set_defaults(remoteTestRoot=None, + logFile="reftest.log", + autorun=True, + closeWhenDone=True, + testPath="") + + def validate_remote(self, options, automation): + if not options.app: + options.app = automation.DEFAULT_APP + + if not options.remoteTestRoot: + options.remoteTestRoot = automation._devicemanager.deviceRoot + \ + "/reftest" + + options.remoteProfile = options.remoteTestRoot + "/profile" + + productRoot = options.remoteTestRoot + "/" + automation._product + if options.utilityPath is None: + options.utilityPath = productRoot + "/bin" + + if not options.httpPort: + options.httpPort = automation.DEFAULT_HTTP_PORT + + if not options.sslPort: + options.sslPort = automation.DEFAULT_SSL_PORT + + if options.remoteWebServer is None: + options.remoteWebServer = self.get_ip() + + options.webServer = options.remoteWebServer + + if options.geckoPath and not options.emulator: + self.error( + "You must specify --emulator if you specify --gecko-path") + + if options.logdir and not options.emulator: + self.error("You must specify --emulator if you specify --logdir") + + if options.remoteLogFile is None: + options.remoteLogFile = "reftest.log" + + options.localLogName = options.remoteLogFile + options.remoteLogFile = options.remoteTestRoot + \ + '/' + options.remoteLogFile + + # Ensure that the options.logfile (which the base class uses) is set to + # the remote setting when running remote. Also, if the user set the + # log file name there, use that instead of reusing the remotelogfile as + # above. + if (options.logFile): + # If the user specified a local logfile name use that + options.localLogName = options.logFile + options.logFile = options.remoteLogFile + + # Only reset the xrePath if it wasn't provided + if options.xrePath is None: + options.xrePath = options.utilityPath + options.xrePath = os.path.abspath(options.xrePath) + + if options.pidFile != "": + f = open(options.pidFile, 'w') + f.write("%s" % os.getpid()) + f.close() + + # httpd-path is specified by standard makefile targets and may be specified + # on the command line to select a particular version of httpd.js. If not + # specified, try to select the one from from the xre bundle, as + # required in bug 882932. + if not options.httpdPath: + options.httpdPath = os.path.join(options.xrePath, "components") + + return options + + +class RemoteArgumentsParser(ReftestArgumentsParser): + def __init__(self, **kwargs): + super(RemoteArgumentsParser, self).__init__() + + # app, xrePath and utilityPath variables are set in main function + self.set_defaults(logFile="reftest.log", + app="", + xrePath="", + utilityPath="", + localLogName=None) + + self.add_argument("--remote-app-path", + action="store", + type=str, + dest="remoteAppPath", + help="Path to remote executable relative to device root using only forward slashes. Either this or app must be specified, but not both.") + + self.add_argument("--deviceIP", + action="store", + type=str, + dest="deviceIP", + help="ip address of remote device to test") + + self.add_argument("--deviceSerial", + action="store", + type=str, + dest="deviceSerial", + help="adb serial number of remote device to test") + + self.add_argument("--devicePort", + action="store", + type=str, + default="20701", + dest="devicePort", + help="port of remote device to test") + + self.add_argument("--remote-product-name", + action="store", + type=str, + dest="remoteProductName", + default="fennec", + help="Name of product to test - either fennec or firefox, defaults to fennec") + + self.add_argument("--remote-webserver", + action="store", + type=str, + dest="remoteWebServer", + help="IP Address of the webserver hosting the reftest content") + + self.add_argument("--http-port", + action="store", + type=str, + dest="httpPort", + help="port of the web server for http traffic") + + self.add_argument("--ssl-port", + action="store", + type=str, + dest="sslPort", + help="Port for https traffic to the web server") + + self.add_argument("--remote-logfile", + action="store", + type=str, + dest="remoteLogFile", + default="reftest.log", + help="Name of log file on the device relative to device root. PLEASE USE ONLY A FILENAME.") + + self.add_argument("--pidfile", + action="store", + type=str, + dest="pidFile", + default="", + help="name of the pidfile to generate") + + self.add_argument("--bootstrap", + action="store_true", + dest="bootstrap", + default=False, + help="test with a bootstrap addon required for native Fennec") + + self.add_argument("--dm_trans", + action="store", + type=str, + dest="dm_trans", + default="sut", + help="the transport to use to communicate with device: [adb|sut]; default=sut") + + self.add_argument("--remoteTestRoot", + action="store", + type=str, + dest="remoteTestRoot", + help="remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)") + + self.add_argument("--httpd-path", + action="store", + type=str, + dest="httpdPath", + help="path to the httpd.js file") + + def validate_remote(self, options, automation): + # Ensure our defaults are set properly for everything we can infer + if not options.remoteTestRoot: + options.remoteTestRoot = automation._devicemanager.deviceRoot + \ + '/reftest' + options.remoteProfile = options.remoteTestRoot + "/profile" + + if options.remoteWebServer is None: + options.remoteWebServer = self.get_ip() + + # Verify that our remotewebserver is set properly + if options.remoteWebServer == '127.0.0.1': + self.error("ERROR: Either you specified the loopback for the remote webserver or ", + "your local IP cannot be detected. Please provide the local ip in --remote-webserver") + + if not options.httpPort: + options.httpPort = automation.DEFAULT_HTTP_PORT + + if not options.sslPort: + options.sslPort = automation.DEFAULT_SSL_PORT + + # One of remoteAppPath (relative path to application) or the app (executable) must be + # set, but not both. If both are set, we destroy the user's selection for app + # so instead of silently destroying a user specificied setting, we + # error. + if options.remoteAppPath and options.app: + self.error( + "ERROR: You cannot specify both the remoteAppPath and the app") + elif options.remoteAppPath: + options.app = options.remoteTestRoot + "/" + options.remoteAppPath + elif options.app is None: + # Neither remoteAppPath nor app are set -- error + self.error("ERROR: You must specify either appPath or app") + + if options.xrePath is None: + self.error( + "ERROR: You must specify the path to the controller xre directory") + else: + # Ensure xrepath is a full path + options.xrePath = os.path.abspath(options.xrePath) + + options.localLogName = options.remoteLogFile + options.remoteLogFile = options.remoteTestRoot + \ + '/' + options.remoteLogFile + + # Ensure that the options.logfile (which the base class uses) is set to + # the remote setting when running remote. Also, if the user set the + # log file name there, use that instead of reusing the remotelogfile as + # above. + if options.logFile: + # If the user specified a local logfile name use that + options.localLogName = options.logFile + + options.logFile = options.remoteLogFile + + if options.pidFile != "": + with open(options.pidFile, 'w') as f: + f.write(str(os.getpid())) + + # httpd-path is specified by standard makefile targets and may be specified + # on the command line to select a particular version of httpd.js. If not + # specified, try to select the one from hostutils.zip, as required in + # bug 882932. + if not options.httpdPath: + options.httpdPath = os.path.join(options.utilityPath, "components") + + if not options.ignoreWindowSize: + parts = automation._devicemanager.getInfo( + 'screen')['screen'][0].split() + width = int(parts[0].split(':')[1]) + height = int(parts[1].split(':')[1]) + if (width < 1050 or height < 1050): + self.error("ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % ( + width, height)) diff --git a/layout/tools/reftest/remotereftest.py b/layout/tools/reftest/remotereftest.py index 697e988d70ec..89c1ae3056c2 100644 --- a/layout/tools/reftest/remotereftest.py +++ b/layout/tools/reftest/remotereftest.py @@ -9,10 +9,9 @@ import tempfile import traceback # We need to know our current directory so that we can serve our test files from it. -SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0]))) +SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(__file__))) -from runreftest import RefTest -from runreftest import ReftestOptions +from runreftest import RefTest, ReftestResolver from automation import Automation import devicemanager import droid @@ -20,159 +19,26 @@ import mozinfo import moznetwork from remoteautomation import RemoteAutomation, fennecLogcatFilters -class RemoteOptions(ReftestOptions): - def __init__(self, automation): - ReftestOptions.__init__(self) - self.automation = automation +import reftestcommandline - defaults = {} - defaults["logFile"] = "reftest.log" - # app, xrePath and utilityPath variables are set in main function - defaults["app"] = "" - defaults["xrePath"] = "" - defaults["utilityPath"] = "" - defaults["runTestsInParallel"] = False - - self.add_option("--remote-app-path", action="store", - type = "string", dest = "remoteAppPath", - help = "Path to remote executable relative to device root using only forward slashes. Either this or app must be specified, but not both.") - defaults["remoteAppPath"] = None - - self.add_option("--deviceIP", action="store", - type = "string", dest = "deviceIP", - help = "ip address of remote device to test") - defaults["deviceIP"] = None - - self.add_option("--deviceSerial", action="store", - type = "string", dest = "deviceSerial", - help = "adb serial number of remote device to test") - defaults["deviceSerial"] = None - - self.add_option("--devicePort", action="store", - type = "string", dest = "devicePort", - help = "port of remote device to test") - defaults["devicePort"] = 20701 - - self.add_option("--remote-product-name", action="store", - type = "string", dest = "remoteProductName", - help = "Name of product to test - either fennec or firefox, defaults to fennec") - defaults["remoteProductName"] = "fennec" - - self.add_option("--remote-webserver", action="store", - type = "string", dest = "remoteWebServer", - help = "IP Address of the webserver hosting the reftest content") - defaults["remoteWebServer"] = moznetwork.get_ip() - - self.add_option("--http-port", action = "store", - type = "string", dest = "httpPort", - help = "port of the web server for http traffic") - defaults["httpPort"] = automation.DEFAULT_HTTP_PORT - - self.add_option("--ssl-port", action = "store", - type = "string", dest = "sslPort", - help = "Port for https traffic to the web server") - defaults["sslPort"] = automation.DEFAULT_SSL_PORT - - self.add_option("--remote-logfile", action="store", - type = "string", dest = "remoteLogFile", - help = "Name of log file on the device relative to device root. PLEASE USE ONLY A FILENAME.") - defaults["remoteLogFile"] = None - - self.add_option("--pidfile", action = "store", - type = "string", dest = "pidFile", - help = "name of the pidfile to generate") - defaults["pidFile"] = "" - - self.add_option("--bootstrap", action="store_true", dest = "bootstrap", - help = "test with a bootstrap addon required for native Fennec") - defaults["bootstrap"] = False - - self.add_option("--dm_trans", action="store", - type = "string", dest = "dm_trans", - help = "the transport to use to communicate with device: [adb|sut]; default=sut") - defaults["dm_trans"] = "sut" - - self.add_option("--remoteTestRoot", action = "store", - type = "string", dest = "remoteTestRoot", - help = "remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)") - defaults["remoteTestRoot"] = None - - self.add_option("--httpd-path", action = "store", - type = "string", dest = "httpdPath", - help = "path to the httpd.js file") - defaults["httpdPath"] = None - - defaults["localLogName"] = None - - self.set_defaults(**defaults) - - def verifyRemoteOptions(self, options): - if options.runTestsInParallel: - self.error("Cannot run parallel tests here") - - # Ensure our defaults are set properly for everything we can infer - if not options.remoteTestRoot: - options.remoteTestRoot = self.automation._devicemanager.deviceRoot + '/reftest' - options.remoteProfile = options.remoteTestRoot + "/profile" - - # Verify that our remotewebserver is set properly - if (options.remoteWebServer == None or - options.remoteWebServer == '127.0.0.1'): - print "ERROR: Either you specified the loopback for the remote webserver or ", - print "your local IP cannot be detected. Please provide the local ip in --remote-webserver" - return None - - # One of remoteAppPath (relative path to application) or the app (executable) must be - # set, but not both. If both are set, we destroy the user's selection for app - # so instead of silently destroying a user specificied setting, we error. - if (options.remoteAppPath and options.app): - print "ERROR: You cannot specify both the remoteAppPath and the app" - return None - elif (options.remoteAppPath): - options.app = options.remoteTestRoot + "/" + options.remoteAppPath - elif (options.app == None): - # Neither remoteAppPath nor app are set -- error - print "ERROR: You must specify either appPath or app" - return None - - if (options.xrePath == None): - print "ERROR: You must specify the path to the controller xre directory" - return None +class RemoteReftestResolver(ReftestResolver): + def absManifestPath(self, path): + script_abs_path = os.path.join(SCRIPT_DIRECTORY, path) + if os.path.exists(script_abs_path): + rv = script_abs_path + elif os.path.exists(os.path.abspath(path)): + rv = os.path.abspath(path) else: - # Ensure xrepath is a full path - options.xrePath = os.path.abspath(options.xrePath) + print >> sys.stderr, "Could not find manifest %s" % script_abs_path + sys.exit(1) + return os.path.normpath(rv) - # Default to /reftest/reftest.log - if (options.remoteLogFile == None): - options.remoteLogFile = 'reftest.log' + def manifestURL(self, options, path): + # Dynamically build the reftest URL if possible, beware that args[0] should exist 'inside' the webroot + # It's possible for this url to have a leading "..", but reftest.js will fix that up + relPath = os.path.relpath(path, SCRIPT_DIRECTORY) + return "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, relPath) - options.localLogName = options.remoteLogFile - options.remoteLogFile = options.remoteTestRoot + '/' + options.remoteLogFile - - # Ensure that the options.logfile (which the base class uses) is set to - # the remote setting when running remote. Also, if the user set the - # log file name there, use that instead of reusing the remotelogfile as above. - if (options.logFile): - # If the user specified a local logfile name use that - options.localLogName = options.logFile - - options.logFile = options.remoteLogFile - - if (options.pidFile != ""): - f = open(options.pidFile, 'w') - f.write("%s" % os.getpid()) - f.close() - - # httpd-path is specified by standard makefile targets and may be specified - # on the command line to select a particular version of httpd.js. If not - # specified, try to select the one from hostutils.zip, as required in bug 882932. - if not options.httpdPath: - options.httpdPath = os.path.join(options.utilityPath, "components") - - # TODO: Copied from main, but I think these are no longer used in a post xulrunner world - #options.xrePath = options.remoteTestRoot + self.automation._product + '/xulrunner' - #options.utilityPath = options.testRoot + self.automation._product + '/bin' - return options class ReftestServer: """ Web server used to serve Reftests, for closer fidelity to the real web. @@ -260,6 +126,7 @@ class ReftestServer: class RemoteReftest(RefTest): remoteApp = '' + resolver_cls = RemoteReftestResolver def __init__(self, automation, devicemanager, options, scriptDir): RefTest.__init__(self) @@ -342,8 +209,12 @@ class RemoteReftest(RefTest): def stopWebServer(self, options): self.server.stop() - def createReftestProfile(self, options, reftestlist): - profile = RefTest.createReftestProfile(self, options, reftestlist, server=options.remoteWebServer, port=options.httpPort) + def createReftestProfile(self, options, manifest): + profile = RefTest.createReftestProfile(self, + options, + manifest, + server=options.remoteWebServer, + port=options.httpPort) profileDir = profile.profile prefs = {} @@ -355,7 +226,6 @@ class RemoteReftest(RefTest): # Set a future policy version to avoid the telemetry prompt. prefs["toolkit.telemetry.prompted"] = 999 prefs["toolkit.telemetry.notifiedOptOut"] = 999 - prefs["reftest.uri"] = "%s" % reftestlist prefs["datareporting.policy.dataSubmissionPolicyBypassAcceptance"] = True # Point the url-classifier to the local testing server for fast failures @@ -410,9 +280,6 @@ class RemoteReftest(RefTest): print "Automation Error: Failed to copy extra files to device" raise - def getManifestPath(self, path): - return path - def printDeviceInfo(self, printLogcat=False): try: if printLogcat: @@ -473,10 +340,10 @@ class RemoteReftest(RefTest): except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % self.pidFile -def main(args): +def main(): automation = RemoteAutomation(None) - parser = RemoteOptions(automation) - options, args = parser.parse_args() + parser = reftestcommandline.RemoteArgumentsParser() + options = parser.parse_args() if (options.dm_trans == 'sut' and options.deviceIP == None): print "Error: If --dm_trans = sut, you must provide a device IP to connect to via the --deviceIP option" @@ -502,18 +369,7 @@ def main(args): automation.setProduct(options.remoteProductName) # Set up the defaults and ensure options are set - options = parser.verifyRemoteOptions(options) - if (options == None): - print "ERROR: Invalid options specified, use --help for a list of valid options" - return 1 - - if not options.ignoreWindowSize: - parts = dm.getInfo('screen')['screen'][0].split() - width = int(parts[0].split(':')[1]) - height = int(parts[1].split(':')[1]) - if (width < 1050 or height < 1050): - print "ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % (width, height) - return 1 + parser.validate_remote(options, automation) # Check that Firefox is installed expected = options.app.split('/')[-1] @@ -526,7 +382,7 @@ def main(args): automation.setRemoteProfile(options.remoteProfile) automation.setRemoteLog(options.remoteLogFile) reftest = RemoteReftest(automation, dm, options, SCRIPT_DIRECTORY) - options = parser.verifyCommonOptions(options, reftest) + parser.validate(options, reftest) if mozinfo.info['debug']: print "changing timeout for remote debug reftests from %s to 600 seconds" % options.timeout @@ -535,17 +391,6 @@ def main(args): # Hack in a symbolic link for jsreftest os.system("ln -s ../jsreftest " + str(os.path.join(SCRIPT_DIRECTORY, "jsreftest"))) - # Dynamically build the reftest URL if possible, beware that args[0] should exist 'inside' the webroot - manifest = args[0] - if os.path.exists(os.path.join(SCRIPT_DIRECTORY, args[0])): - manifest = "http://" + str(options.remoteWebServer) + ":" + str(options.httpPort) + "/" + args[0] - elif os.path.exists(args[0]): - manifestPath = os.path.abspath(args[0]).split(SCRIPT_DIRECTORY)[1].strip('/') - manifest = "http://" + str(options.remoteWebServer) + ":" + str(options.httpPort) + "/" + manifestPath - else: - print "ERROR: Could not find test manifest '%s'" % manifest - return 1 - # Start the webserver retVal = reftest.startWebServer(options) if retVal: @@ -561,11 +406,8 @@ def main(args): # manifest = "http://" + options.remoteWebServer + "/reftests/layout/reftests/reftest-sanity/reftest.list" retVal = 0 try: - cmdlineArgs = ["-reftest", manifest] - if options.bootstrap: - cmdlineArgs = [] dm.recordLogcat() - retVal = reftest.runTests(manifest, options, cmdlineArgs) + retVal = reftest.runTests(options.tests, options) except: print "Automation Error: Exception caught while running tests" traceback.print_exc() @@ -578,5 +420,5 @@ def main(args): return retVal if __name__ == "__main__": - sys.exit(main(sys.argv[1:])) + sys.exit(main()) diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py index 32d18f68ba1a..353a745c4d04 100644 --- a/layout/tools/reftest/runreftest.py +++ b/layout/tools/reftest/runreftest.py @@ -6,9 +6,8 @@ Runs the reftest test harness. """ -from optparse import OptionParser -from urlparse import urlparse import collections +import json import multiprocessing import os import re @@ -19,8 +18,9 @@ import sys import threading SCRIPT_DIRECTORY = os.path.abspath( - os.path.realpath(os.path.dirname(sys.argv[0]))) -sys.path.insert(0, SCRIPT_DIRECTORY) + os.path.realpath(os.path.dirname(__file__))) +if SCRIPT_DIRECTORY not in sys.path: + sys.path.insert(0, SCRIPT_DIRECTORY) import mozcrash import mozdebug @@ -32,13 +32,7 @@ import mozrunner from mozrunner.utils import get_stack_fixer_function, test_environment from mozscreenshot import printstatus, dump_screen -here = os.path.abspath(os.path.dirname(__file__)) - -try: - from mozbuild.base import MozbuildObject - build_obj = MozbuildObject.from_environment(cwd=here) -except ImportError: - build_obj = None +import reftestcommandline # set up logging handler a la automation.py.in for compatability import logging @@ -132,14 +126,63 @@ class ReftestThread(threading.Thread): if summaryHeadRegex.search(line) is None: yield line +class ReftestResolver(object): + def defaultManifest(self, suite): + return {"reftest": "reftest.list", + "crashtest": "crashtests.list", + "jstestbrowser": "jstests.list"}[suite] + + def findManifest(self, suite, test_file): + """Return a tuple of (manifest-path, filter-string) for running test_file. + + test_file is a path to a test or a manifest file + """ + if not os.path.isabs(test_file): + test_file = self.absManifestPath(test_file) + + if os.path.isdir(test_file): + return os.path.join(test_file, self.defaultManifest(suite)), None + + if test_file.endswith('.list'): + return test_file, None + + return (self.findManifest(suite, os.path.dirname(test_file))[0], + r".*(?:/|\\)%s$" % os.path.basename(test_file)) + + def absManifestPath(self, path): + return os.path.abspath(path) + + def manifestURL(self, options, path): + return "file://%s" % path + + def resolveManifests(self, options, tests): + suite = options.suite + manifests = {} + for testPath in tests: + manifest, filter_str = self.findManifest(suite, testPath) + manifest = self.manifestURL(options, manifest) + if manifest not in manifests: + manifests[manifest] = set() + if filter_str is not None: + manifests[manifest].add(filter_str) + + for key in manifests.iterkeys(): + if os.path.split(key)[1] != self.defaultManifest(suite): + print >> sys.stderr, "Invalid manifest for suite %s, %s" %(options.suite, key) + sys.exit(1) + manifests[key] = sorted(list(manifests[key])) + + return manifests class RefTest(object): oldcwd = os.getcwd() + resolver_cls = ReftestResolver def __init__(self): self.update_mozinfo() self.lastTestSeen = 'reftest' self.haveDumpedScreen = False + self.resolver = self.resolver_cls() def update_mozinfo(self): """walk up directories to find mozinfo.json update the info""" @@ -158,30 +201,15 @@ class RefTest(object): "Get an absolute path relative to self.oldcwd." return os.path.normpath(os.path.join(self.oldcwd, os.path.expanduser(path))) - def getManifestPath(self, path): - "Get the path of the manifest, and for remote testing this function is subclassed to point to remote manifest" - path = self.getFullPath(path) - if os.path.isdir(path): - defaultManifestPath = os.path.join(path, 'reftest.list') - if os.path.exists(defaultManifestPath): - path = defaultManifestPath - else: - defaultManifestPath = os.path.join(path, 'crashtests.list') - if os.path.exists(defaultManifestPath): - path = defaultManifestPath - return path + def createReftestProfile(self, options, manifests, server='localhost', port=0, + profile_to_clone=None): + """Sets up a profile for reftest. - def makeJSString(self, s): - return '"%s"' % re.sub(r'([\\"])', r'\\\1', s) - - def createReftestProfile(self, options, manifest, server='localhost', port=0, - special_powers=True, profile_to_clone=None): - """ - Sets up a profile for reftest. - 'manifest' is the path to the reftest.list file we want to test with. This is used in - the remote subclass in remotereftest.py so we can write it to a preference for the - bootstrap extension. - """ + :param options: Object containing command line options + :param manifests: Dictionary of the form {manifest_path: [filters]} + :param server: Server name to use for http tests + :param profile_to_clone: Path to a profile to use as the basis for the + test profile""" locations = mozprofile.permissions.ServerLocations() locations.add_host(server, scheme='http', port=port) @@ -200,12 +228,10 @@ class RefTest(object): prefs['reftest.logFile'] = options.logFile if options.ignoreWindowSize: prefs['reftest.ignoreWindowSize'] = True - if options.filter: - prefs['reftest.filter'] = options.filter if options.shuffle: prefs['reftest.shuffle'] = True prefs['reftest.focusFilterMode'] = options.focusFilterMode - prefs['reftest.uri'] = "file://%s" % os.path.abspath(manifest) + prefs['reftest.manifests'] = json.dumps(manifests) # Ensure that telemetry is disabled, so we don't connect to the telemetry # server in the middle of the tests. @@ -250,13 +276,10 @@ class RefTest(object): thispref[1].strip()) # install the reftest extension bits into the profile - addons = [] - addons.append(os.path.join(SCRIPT_DIRECTORY, "reftest")) + addons = [options.reftestExtensionPath] - # I would prefer to use "--install-extension reftest/specialpowers", but that requires tight coordination with - # release engineering and landing on multiple branches at once. - if special_powers and (manifest.endswith('crashtests.list') or manifest.endswith('jstests.list')): - addons.append(os.path.join(SCRIPT_DIRECTORY, 'specialpowers')) + if options.specialPowersExtensionPath is not None: + addons.append(options.specialPowersExtensionPath) # SpecialPowers requires insecure automation-only features that we # put behind a pref. prefs['security.turn_off_all_security_so_that_viruses_can_take_over_this_computer'] = True @@ -337,7 +360,7 @@ class RefTest(object): if profileDir: shutil.rmtree(profileDir, True) - def runTests(self, testPath, options, cmdlineArgs=None): + def runTests(self, tests, options, cmdlineArgs=None): # Despite our efforts to clean up servers started by this script, in practice # we still see infrequent cases where a process is orphaned and interferes # with future tests, typically because the old server is keeping the port in use. @@ -346,8 +369,12 @@ class RefTest(object): self.killNamedOrphans('ssltunnel') self.killNamedOrphans('xpcshell') - if not options.runTestsInParallel: - return self.runSerialTests(testPath, options, cmdlineArgs) + manifests = self.resolver.resolveManifests(options, tests) + if options.filter: + manifests[""] = options.filter + + if not hasattr(options, "runTestsInParallel") or not options.runTestsInParallel: + return self.runSerialTests(manifests, options, cmdlineArgs) cpuCount = multiprocessing.cpu_count() @@ -378,7 +405,6 @@ class RefTest(object): jobArgs.remove("--run-tests-in-parallel") except: pass - jobArgs.insert(-1, "--no-run-tests-in-parallel") jobArgs[0:0] = [sys.executable, "-u"] threads = [ReftestThread(args) for args in perProcessArgs[1:]] @@ -601,7 +627,7 @@ class RefTest(object): status = 1 return status - def runSerialTests(self, testPath, options, cmdlineArgs=None): + def runSerialTests(self, manifests, options, cmdlineArgs=None): debuggerInfo = None if options.debugger: debuggerInfo = mozdebug.get_debugger_info(options.debugger, options.debuggerArgs, @@ -609,10 +635,9 @@ class RefTest(object): profileDir = None try: - reftestlist = self.getManifestPath(testPath) if cmdlineArgs == None: cmdlineArgs = [] - profile = self.createReftestProfile(options, reftestlist) + profile = self.createReftestProfile(options, manifests) profileDir = profile.profile # name makes more sense # browser environment @@ -660,209 +685,26 @@ class RefTest(object): continue -class ReftestOptions(OptionParser): - - def __init__(self): - OptionParser.__init__(self) - defaults = {} - self.add_option("--xre-path", - action="store", type="string", dest="xrePath", - # individual scripts will set a sane default - default=None, - help="absolute path to directory containing XRE (probably xulrunner)") - self.add_option("--symbols-path", - action="store", type="string", dest="symbolsPath", - default=None, - help="absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols") - self.add_option("--debugger", - action="store", dest="debugger", - help="use the given debugger to launch the application") - self.add_option("--debugger-args", - action="store", dest="debuggerArgs", - help="pass the given args to the debugger _before_ " - "the application on the command line") - self.add_option("--debugger-interactive", - action="store_true", dest="debuggerInteractive", - help="prevents the test harness from redirecting " - "stdout and stderr for interactive debuggers") - self.add_option("--appname", - action="store", type="string", dest="app", - help="absolute path to application, overriding default") - # Certain paths do not make sense when we're cross compiling Fennec. This - # logic is cribbed from the example in - # python/mozbuild/mozbuild/mach_commands.py. - defaults['app'] = build_obj.get_binary_path() if \ - build_obj and build_obj.substs['MOZ_BUILD_APP'] != 'mobile/android' else None - - self.add_option("--extra-profile-file", - action="append", dest="extraProfileFiles", - default=[], - help="copy specified files/dirs to testing profile") - self.add_option("--timeout", - action="store", dest="timeout", type="int", - default=5 * 60, # 5 minutes per bug 479518 - help="reftest will timeout in specified number of seconds. [default %default s].") - self.add_option("--leak-threshold", - action="store", type="int", dest="defaultLeakThreshold", - default=0, - help="fail if the number of bytes leaked in default " - "processes through refcounted objects (or bytes " - "in classes with MOZ_COUNT_CTOR and MOZ_COUNT_DTOR) " - "is greater than the given number") - self.add_option("--utility-path", - action="store", type="string", dest="utilityPath", - help="absolute path to directory containing utility " - "programs (xpcshell, ssltunnel, certutil)") - defaults["utilityPath"] = build_obj.bindir if \ - build_obj and build_obj.substs['MOZ_BUILD_APP'] != 'mobile/android' else None - - self.add_option("--total-chunks", - type="int", dest="totalChunks", - help="how many chunks to split the tests up into") - defaults["totalChunks"] = None - - self.add_option("--this-chunk", - type="int", dest="thisChunk", - help="which chunk to run between 1 and --total-chunks") - defaults["thisChunk"] = None - - self.add_option("--log-file", - action="store", type="string", dest="logFile", - default=None, - help="file to log output to in addition to stdout") - defaults["logFile"] = None - - self.add_option("--skip-slow-tests", - dest="skipSlowTests", action="store_true", - help="skip tests marked as slow when running") - defaults["skipSlowTests"] = False - - self.add_option("--ignore-window-size", - dest="ignoreWindowSize", action="store_true", - help="ignore the window size, which may cause spurious failures and passes") - defaults["ignoreWindowSize"] = False - - self.add_option("--install-extension", - action="append", dest="extensionsToInstall", - help="install the specified extension in the testing profile. " - "The extension file's name should be .xpi where is " - "the extension's id as indicated in its install.rdf. " - "An optional path can be specified too.") - defaults["extensionsToInstall"] = [] - - self.add_option("--run-tests-in-parallel", - action="store_true", dest="runTestsInParallel", - help="run tests in parallel if possible") - self.add_option("--no-run-tests-in-parallel", - action="store_false", dest="runTestsInParallel", - help="do not run tests in parallel") - defaults["runTestsInParallel"] = False - - self.add_option("--setenv", - action="append", type="string", - dest="environment", metavar="NAME=VALUE", - help="sets the given variable in the application's " - "environment") - defaults["environment"] = [] - - self.add_option("--filter", - action="store", type="string", dest="filter", - help="specifies a regular expression (as could be passed to the JS " - "RegExp constructor) to test against URLs in the reftest manifest; " - "only test items that have a matching test URL will be run.") - defaults["filter"] = None - - self.add_option("--shuffle", - action="store_true", dest="shuffle", - help="run reftests in random order") - defaults["shuffle"] = False - - self.add_option("--focus-filter-mode", - action="store", type="string", dest="focusFilterMode", - help="filters tests to run by whether they require focus. " - "Valid values are `all', `needs-focus', or `non-needs-focus'. " - "Defaults to `all'.") - defaults["focusFilterMode"] = "all" - - self.add_option("--e10s", - action="store_true", - dest="e10s", - help="enables content processes") - defaults["e10s"] = False - - self.add_option("--setpref", - action="append", type="string", - default=[], - dest="extraPrefs", metavar="PREF=VALUE", - help="defines an extra user preference") - - self.set_defaults(**defaults) - - def verifyCommonOptions(self, options, reftest): - if options.totalChunks is not None and options.thisChunk is None: - self.error("thisChunk must be specified when totalChunks is specified") - - if options.totalChunks: - if not 1 <= options.thisChunk <= options.totalChunks: - self.error("thisChunk must be between 1 and totalChunks") - - if options.logFile: - options.logFile = reftest.getFullPath(options.logFile) - - if options.xrePath is not None: - if not os.access(options.xrePath, os.F_OK): - self.error("--xre-path '%s' not found" % options.xrePath) - if not os.path.isdir(options.xrePath): - self.error("--xre-path '%s' is not a directory" % - options.xrePath) - options.xrePath = reftest.getFullPath(options.xrePath) - - if options.runTestsInParallel: - if options.logFile is not None: - self.error("cannot specify logfile with parallel tests") - if options.totalChunks is not None and options.thisChunk is None: - self.error("cannot specify thisChunk or totalChunks with parallel tests") - if options.focusFilterMode != "all": - self.error("cannot specify focusFilterMode with parallel tests") - if options.debugger is not None: - self.error("cannot specify a debugger with parallel tests") - - options.leakThresholds = { - "default": options.defaultLeakThreshold, - "tab": 5000, # See dependencies of bug 1051230. - } - - return options +def run(**kwargs): + # Mach gives us kwargs; this is a way to turn them back into an + # options object + parser = reftestcommandline.DesktopArgumentsParser() + reftest = RefTest() + parser.set_defaults(**kwargs) + options = parser.parse_args(kwargs["tests"]) + parser.validate(options, reftest) + return reftest.runTests(options.tests, options) def main(): - parser = ReftestOptions() + parser = reftestcommandline.DesktopArgumentsParser() reftest = RefTest() - options, args = parser.parse_args() - if len(args) != 1: - print >>sys.stderr, "No reftest.list specified." - sys.exit(1) + options = parser.parse_args() + parser.validate(options, reftest) - options = parser.verifyCommonOptions(options, reftest) - if options.app is None: - parser.error("could not find the application path, --appname must be specified") + sys.exit(reftest.runTests(options.tests, options)) - options.app = reftest.getFullPath(options.app) - if not os.path.exists(options.app): - print """Error: Path %(app)s doesn't exist. -Are you executing $objdir/_tests/reftest/runreftest.py?""" \ - % {"app": options.app} - sys.exit(1) - - if options.xrePath is None: - options.xrePath = os.path.dirname(options.app) - - if options.symbolsPath and len(urlparse(options.symbolsPath).scheme) < 2: - options.symbolsPath = reftest.getFullPath(options.symbolsPath) - options.utilityPath = reftest.getFullPath(options.utilityPath) - - sys.exit(reftest.runTests(args[0], options)) if __name__ == "__main__": main() diff --git a/layout/tools/reftest/runreftestb2g.py b/layout/tools/reftest/runreftestb2g.py index 085a246ac00c..c0a9257e93ef 100644 --- a/layout/tools/reftest/runreftestb2g.py +++ b/layout/tools/reftest/runreftestb2g.py @@ -10,207 +10,18 @@ import traceback # We need to know our current directory so that we can serve our test files from it. here = os.path.abspath(os.path.dirname(__file__)) +if here not in sys.path: + sys.path.insert(0, here) from automation import Automation from b2gautomation import B2GRemoteAutomation from b2g_desktop import run_desktop_reftests +from remotereftest import RemoteReftestResolver, ReftestServer from runreftest import RefTest -from runreftest import ReftestOptions -from remotereftest import ReftestServer +import reftestcommandline from mozdevice import DeviceManagerADB, DMError from marionette import Marionette -import moznetwork - -class B2GOptions(ReftestOptions): - - def __init__(self, **kwargs): - defaults = {} - ReftestOptions.__init__(self) - # This is only used for procName in run_remote_reftests. - defaults["app"] = Automation.DEFAULT_APP - - self.add_option("--browser-arg", action="store", - type = "string", dest = "browser_arg", - help = "Optional command-line arg to pass to the browser") - defaults["browser_arg"] = None - - self.add_option("--b2gpath", action="store", - type = "string", dest = "b2gPath", - help = "path to B2G repo or qemu dir") - defaults["b2gPath"] = None - - self.add_option("--marionette", action="store", - type = "string", dest = "marionette", - help = "host:port to use when connecting to Marionette") - defaults["marionette"] = None - - self.add_option("--emulator", action="store", - type="string", dest = "emulator", - help = "Architecture of emulator to use: x86 or arm") - defaults["emulator"] = None - self.add_option("--emulator-res", action="store", - type="string", dest = "emulator_res", - help = "Emulator resolution of the format 'x'") - defaults["emulator_res"] = None - - self.add_option("--no-window", action="store_true", - dest = "noWindow", - help = "Pass --no-window to the emulator") - defaults["noWindow"] = False - - self.add_option("--adbpath", action="store", - type = "string", dest = "adb_path", - help = "path to adb") - defaults["adb_path"] = "adb" - - self.add_option("--deviceIP", action="store", - type = "string", dest = "deviceIP", - help = "ip address of remote device to test") - defaults["deviceIP"] = None - - self.add_option("--devicePort", action="store", - type = "string", dest = "devicePort", - help = "port of remote device to test") - defaults["devicePort"] = 20701 - - self.add_option("--remote-logfile", action="store", - type = "string", dest = "remoteLogFile", - help = "Name of log file on the device relative to the device root. PLEASE ONLY USE A FILENAME.") - defaults["remoteLogFile"] = None - - self.add_option("--remote-webserver", action = "store", - type = "string", dest = "remoteWebServer", - help = "ip address where the remote web server is hosted at") - defaults["remoteWebServer"] = None - - self.add_option("--http-port", action = "store", - type = "string", dest = "httpPort", - help = "ip address where the remote web server is hosted at") - defaults["httpPort"] = None - - self.add_option("--ssl-port", action = "store", - type = "string", dest = "sslPort", - help = "ip address where the remote web server is hosted at") - defaults["sslPort"] = None - - self.add_option("--pidfile", action = "store", - type = "string", dest = "pidFile", - help = "name of the pidfile to generate") - defaults["pidFile"] = "" - self.add_option("--gecko-path", action="store", - type="string", dest="geckoPath", - help="the path to a gecko distribution that should " - "be installed on the emulator prior to test") - defaults["geckoPath"] = None - self.add_option("--logdir", action="store", - type="string", dest="logdir", - help="directory to store log files") - defaults["logdir"] = None - self.add_option('--busybox', action='store', - type='string', dest='busybox', - help="Path to busybox binary to install on device") - defaults['busybox'] = None - self.add_option("--httpd-path", action = "store", - type = "string", dest = "httpdPath", - help = "path to the httpd.js file") - defaults["httpdPath"] = None - self.add_option("--profile", action="store", - type="string", dest="profile", - help="for desktop testing, the path to the " - "gaia profile to use") - defaults["profile"] = None - self.add_option("--desktop", action="store_true", - dest="desktop", - help="Run the tests on a B2G desktop build") - defaults["desktop"] = False - self.add_option("--mulet", action="store_true", - dest="mulet", - help="Run the tests on a B2G desktop build") - defaults["mulet"] = False - self.add_option("--enable-oop", action="store_true", - dest="oop", - help="Run the tests out of process") - defaults["oop"] = False - defaults["remoteTestRoot"] = None - defaults["logFile"] = "reftest.log" - defaults["autorun"] = True - defaults["closeWhenDone"] = True - defaults["testPath"] = "" - defaults["runTestsInParallel"] = False - - self.set_defaults(**defaults) - - def verifyRemoteOptions(self, options, auto): - if options.runTestsInParallel: - self.error("Cannot run parallel tests here") - - if not options.remoteTestRoot: - options.remoteTestRoot = auto._devicemanager.deviceRoot + "/reftest" - - options.remoteProfile = options.remoteTestRoot + "/profile" - - productRoot = options.remoteTestRoot + "/" + auto._product - if options.utilityPath is None: - options.utilityPath = productRoot + "/bin" - - if options.remoteWebServer == None: - if os.name != "nt": - options.remoteWebServer = moznetwork.get_ip() - else: - print "ERROR: you must specify a --remote-webserver=\n" - return None - - options.webServer = options.remoteWebServer - - if not options.httpPort: - options.httpPort = auto.DEFAULT_HTTP_PORT - - if not options.sslPort: - options.sslPort = auto.DEFAULT_SSL_PORT - - if options.geckoPath and not options.emulator: - self.error("You must specify --emulator if you specify --gecko-path") - - if options.logdir and not options.emulator: - self.error("You must specify --emulator if you specify --logdir") - - #if not options.emulator and not options.deviceIP: - # print "ERROR: you must provide a device IP" - # return None - - if options.remoteLogFile == None: - options.remoteLogFile = "reftest.log" - - options.localLogName = options.remoteLogFile - options.remoteLogFile = options.remoteTestRoot + '/' + options.remoteLogFile - - # Ensure that the options.logfile (which the base class uses) is set to - # the remote setting when running remote. Also, if the user set the - # log file name there, use that instead of reusing the remotelogfile as above. - if (options.logFile): - # If the user specified a local logfile name use that - options.localLogName = options.logFile - options.logFile = options.remoteLogFile - - # Only reset the xrePath if it wasn't provided - if options.xrePath == None: - options.xrePath = options.utilityPath - options.xrePath = os.path.abspath(options.xrePath) - - if options.pidFile != "": - f = open(options.pidFile, 'w') - f.write("%s" % os.getpid()) - f.close() - - # httpd-path is specified by standard makefile targets and may be specified - # on the command line to select a particular version of httpd.js. If not - # specified, try to select the one from from the xre bundle, as required in bug 882932. - if not options.httpdPath: - options.httpdPath = os.path.join(options.xrePath, "components") - - return options - class ProfileConfigParser(ConfigParser.RawConfigParser): """Subclass of RawConfigParser that outputs .ini files in the exact @@ -243,6 +54,7 @@ class B2GRemoteReftest(RefTest): localProfile = None remoteApp = '' profile = None + resolver_cls = RemoteReftestResolver def __init__(self, automation, devicemanager, options, scriptDir): RefTest.__init__(self) @@ -418,10 +230,9 @@ class B2GRemoteReftest(RefTest): pass - def createReftestProfile(self, options, reftestlist): - profile = RefTest.createReftestProfile(self, options, reftestlist, - server=options.remoteWebServer, - special_powers=False) + def createReftestProfile(self, options, manifests): + profile = RefTest.createReftestProfile(self, options, manifests, + server=options.remoteWebServer) profileDir = profile.profile prefs = {} @@ -437,7 +248,7 @@ class B2GRemoteReftest(RefTest): prefs["network.dns.localDomains"] = "app://test-container.gaiamobile.org" prefs["reftest.browser.iframe.enabled"] = False prefs["reftest.remote"] = True - prefs["reftest.uri"] = "%s" % reftestlist + # Set a future policy version to avoid the telemetry prompt. prefs["toolkit.telemetry.prompted"] = 999 prefs["toolkit.telemetry.notifiedOptOut"] = 999 @@ -495,9 +306,6 @@ class B2GRemoteReftest(RefTest): print "Automation Error: Failed to copy extra files to device" raise - def getManifestPath(self, path): - return path - def environment(self, **kwargs): return self.automation.environment(**kwargs) @@ -516,7 +324,7 @@ class B2GRemoteReftest(RefTest): return status -def run_remote_reftests(parser, options, args): +def run_remote_reftests(parser, options): auto = B2GRemoteAutomation(None, "fennec", context_chrome=True) # create our Marionette instance @@ -559,11 +367,7 @@ def run_remote_reftests(parser, options, args): dm = DeviceManagerADB(**kwargs) auto.setDeviceManager(dm) - options = parser.verifyRemoteOptions(options, auto) - - if (options == None): - print "ERROR: Invalid options specified, use --help for a list of valid options" - sys.exit(1) + parser.validate_remote(options, auto) # TODO fix exception if not options.ignoreWindowSize: @@ -580,7 +384,7 @@ def run_remote_reftests(parser, options, args): auto.logFinish = "REFTEST TEST-START | Shutdown" reftest = B2GRemoteReftest(auto, dm, options, here) - options = parser.verifyCommonOptions(options, reftest) + parser.validate(options, reftest) logParent = os.path.dirname(options.remoteLogFile) dm.mkDir(logParent); @@ -590,16 +394,6 @@ def run_remote_reftests(parser, options, args): # Hack in a symbolic link for jsreftest os.system("ln -s %s %s" % (os.path.join('..', 'jsreftest'), os.path.join(here, 'jsreftest'))) - # Dynamically build the reftest URL if possible, beware that args[0] should exist 'inside' the webroot - manifest = args[0] - if os.path.exists(os.path.join(here, args[0])): - manifest = "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, args[0]) - elif os.path.exists(args[0]): - manifestPath = os.path.abspath(args[0]).split(here)[1].strip('/') - manifest = "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, manifestPath) - else: - print "ERROR: Could not find test manifest '%s'" % manifest - return 1 # Start the webserver retVal = 1 @@ -611,11 +405,7 @@ def run_remote_reftests(parser, options, args): if (dm.processExist(procName)): dm.killProcess(procName) - cmdlineArgs = ["-reftest", manifest] - if getattr(options, 'bootstrap', False): - cmdlineArgs = [] - - retVal = reftest.runTests(manifest, options, cmdlineArgs) + retVal = reftest.runTests(options.tests, options) except: print "Automation Error: Exception caught while running tests" traceback.print_exc() @@ -629,13 +419,21 @@ def run_remote_reftests(parser, options, args): reftest.stopWebServer(options) return retVal -def main(args=sys.argv[1:]): - parser = B2GOptions() - options, args = parser.parse_args(args) +def run_remote(**kwargs): + # Tests need to be served from a subdirectory of the server. Symlink + # topsrcdir here to get around this. + parser = reftestcommandline.B2GArgumentParser() + parser.set_defaults(**kwargs) + options = parser.parse_args(kwargs["tests"]) + return run_remote_reftests(parser, options) + +def main(): + parser = reftestcommandline.B2GArgumentParser() + options = parser.parse_args() if options.desktop or options.mulet: - return run_desktop_reftests(parser, options, args) - return run_remote_reftests(parser, options, args) + return run_desktop_reftests(parser, options) + return run_remote_reftests(parser, options) if __name__ == "__main__": diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk index 1e99d2056919..98c7b76e8a04 100644 --- a/testing/testsuite-targets.mk +++ b/testing/testsuite-targets.mk @@ -174,7 +174,7 @@ REMOTE_REFTEST = rm -f ./$@.log && $(PYTHON) _tests/reftest/remotereftest.py \ --dm_trans=$(DM_TRANS) --ignore-window-size \ --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \ --httpd-path=_tests/modules \ - $(SYMBOLS_PATH) $(EXTRA_TEST_ARGS) '$(1)' | tee ./$@.log + $(SYMBOLS_PATH) $(EXTRA_TEST_ARGS) $(1) | tee ./$@.log RUN_REFTEST_B2G = rm -f ./$@.log && $(PYTHON) _tests/reftest/runreftestb2g.py \ --remote-webserver=10.0.2.2 --b2gpath=${B2G_PATH} --adbpath=${ADB_PATH} \ @@ -209,7 +209,7 @@ reftest-remote: echo 'please prepare your host with the environment variable TEST_DEVICE'; \ else \ ln -s $(abspath $(topsrcdir)) _tests/reftest/tests; \ - $(call REMOTE_REFTEST,tests/$(TEST_PATH)); \ + $(call REMOTE_REFTEST,'tests/$(TEST_PATH)'); \ $(CHECK_TEST_ERROR); \ fi From dd1db6f1da1a311454ebb515e266b544d2d676e9 Mon Sep 17 00:00:00 2001 From: James Graham Date: Tue, 8 Sep 2015 15:30:08 +0100 Subject: [PATCH 003/131] Bug 1193223 - Add reftest support to mach test, r=chmanchester --- layout/tools/reftest/mach_commands.py | 15 +++++++++++++++ testing/mach_commands.py | 7 +++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/layout/tools/reftest/mach_commands.py b/layout/tools/reftest/mach_commands.py index 7237e05bfdf0..d5a91700490a 100644 --- a/layout/tools/reftest/mach_commands.py +++ b/layout/tools/reftest/mach_commands.py @@ -215,6 +215,19 @@ class ReftestRunner(MozbuildObject): return rv + +def process_test_objects(kwargs): + """|mach test| works by providing a test_objects argument, from + which the test path must be extracted and converted into a normal + reftest tests argument.""" + + if "test_objects" in kwargs: + if kwargs["tests"] is None: + kwargs["tests"] = [] + kwargs["tests"].extend(item["path"] for item in kwargs["test_objects"]) + del kwargs["test_objects"] + + @CommandProvider class MachCommands(MachCommandBase): @Command('reftest', @@ -263,6 +276,7 @@ class MachCommands(MachCommandBase): return self._run_reftest(**kwargs) def _run_reftest(self, **kwargs): + process_test_objects(kwargs) reftest = self._spawn(ReftestRunner) return reftest.run_desktop_test(**kwargs) @@ -307,6 +321,7 @@ class B2GCommands(MachCommandBase): return self._run_reftest(**kwargs) def _run_reftest(self, **kwargs): + process_test_objects(kwargs) if self.device_name: if self.device_name.startswith('emulator'): emulator = 'arm' diff --git a/testing/mach_commands.py b/testing/mach_commands.py index 9134d9d20626..1b443d94c3db 100644 --- a/testing/mach_commands.py +++ b/testing/mach_commands.py @@ -96,7 +96,7 @@ TEST_SUITES = { 'reftest': { 'aliases': ('RR', 'rr', 'Rr'), 'mach_command': 'reftest', - 'kwargs': {'test_file': None}, + 'kwargs': {'tests': None}, }, 'reftest-ipc': { 'aliases': ('Ripc',), @@ -139,7 +139,10 @@ TEST_FLAVORS = { 'mach_command': 'mochitest', 'kwargs': {'flavor': 'mochitest', 'test_paths': []}, }, - 'reftest': { }, + 'reftest': { + 'mach_command': 'reftest', + 'kwargs': {'tests': []} + }, 'steeplechase': { }, 'web-platform-tests': { 'mach_command': 'web-platform-tests', From 2cdcadf2953a16e3c9b2aa04fb98529a15438ad8 Mon Sep 17 00:00:00 2001 From: James Graham Date: Mon, 20 Jul 2015 17:03:02 +0100 Subject: [PATCH 004/131] Bug 1198257 - Better support for providing a directory name and discovering reftests under that directory, r=jmaher --- layout/tools/reftest/reftest.js | 50 +++++++++++++++++++---------- layout/tools/reftest/runreftest.py | 51 ++++++++++++++++++++++-------- 2 files changed, 71 insertions(+), 30 deletions(-) diff --git a/layout/tools/reftest/reftest.js b/layout/tools/reftest/reftest.js index ca61a086b013..b8dd5a030816 100644 --- a/layout/tools/reftest/reftest.js +++ b/layout/tools/reftest/reftest.js @@ -69,6 +69,7 @@ var gCanvas1, gCanvas2; // RecordResult. var gCurrentCanvas = null; var gURLs; +var gManifestsLoaded = {}; // Map from URI spec to the number of times it remains to be used var gURIUseCounts; // Map from URI spec to the canvas rendered for that URI @@ -489,11 +490,14 @@ function StartTests() try { var globalFilter = manifests.hasOwnProperty("") ? new RegExp(manifests[""]) : null; var manifestURLs = Object.keys(manifests); - manifestURLs.sort(); + + // Ensure we read manifests from higher up the directory tree first so that we + // process includes before reading the included manifest again + manifestURLs.sort(function(a,b) {return a.length - b.length}) manifestURLs.forEach(function(manifestURL) { gDumpLog("Readings manifest" + manifestURL + "\n"); - var pathFilters = manifests[manifestURL].map(function(x) {return new RegExp(x)}); - ReadTopManifest(manifestURL, [globalFilter, pathFilters]); + var filter = manifests[manifestURL] ? new RegExp(manifests[manifestURL]) : null; + ReadTopManifest(manifestURL, [globalFilter, filter, false]); }); BuildUseCounts(); @@ -747,22 +751,25 @@ function AddPrefSettings(aWhere, aPrefName, aPrefValExpression, aSandbox, aTestP return true; } -function ReadTopManifest(aFileURL, aFilters) +function ReadTopManifest(aFileURL, aFilter) { var url = gIOService.newURI(aFileURL, null, null); if (!url) throw "Expected a file or http URL for the manifest."; - ReadManifest(url, EXPECTED_PASS, aFilters); + ReadManifest(url, EXPECTED_PASS, aFilter); } -function AddTestItem(aTest, aFilters) +function AddTestItem(aTest, aFilter) { - if (!aFilters) - aFilters = [null, []]; + if (!aFilter) + aFilter = [null, [], false]; - if ((aFilters[0] && !aFilters[0].test(aTest.url1.spec)) || - (aFilters[1].length > 0 && - !aFilters[1].some(function(filter) {return filter.test(aTest.url1.spec)}))) + globalFilter = aFilter[0]; + manifestFilter = aFilter[1]; + invertManifest = aFilter[2]; + if ((globalFilter && !globalFilter.test(aTest.url1.spec)) || + (manifestFilter && + !(invertManifest ^ manifestFilter.test(aTest.url1.spec)))) return; if (gFocusFilterMode == FOCUS_FILTER_NEEDS_FOCUS_TESTS && !aTest.needsFocus) @@ -775,8 +782,19 @@ function AddTestItem(aTest, aFilters) // Note: If you materially change the reftest manifest parsing, // please keep the parser in print-manifest-dirs.py in sync. -function ReadManifest(aURL, inherited_status, aFilters) +function ReadManifest(aURL, inherited_status, aFilter) { + // Ensure each manifest is only read once. This assumes that manifests that are + // included with an unusual inherited_status or filters will be read via their + // include before they are read directly in the case of a duplicate + if (gManifestsLoaded.hasOwnProperty(aURL.spec)) { + if (gManifestsLoaded[aURL.spec] === null) + return; + else + aFilter = [aFilter[0], aFilter[1], true]; + } + gManifestsLoaded[aURL.spec] = aFilter[1]; + var secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID] .getService(CI.nsIScriptSecurityManager); @@ -992,7 +1010,7 @@ function ReadManifest(aURL, inherited_status, aFilters) var incURI = gIOService.newURI(items[1], null, listURL); secMan.checkLoadURIWithPrincipal(principal, incURI, CI.nsIScriptSecurityManager.DISALLOW_SCRIPT); - ReadManifest(incURI, expected_status, aFilters); + ReadManifest(incURI, expected_status, aFilter); } else if (items[0] == TYPE_LOAD) { if (items.length != 2) throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to load"; @@ -1022,7 +1040,7 @@ function ReadManifest(aURL, inherited_status, aFilters) fuzzyMaxPixels: fuzzy_max_pixels, url1: testURI, url2: null, - chaosMode: chaosMode }, aFilters); + chaosMode: chaosMode }, aFilter); } else if (items[0] == TYPE_SCRIPT) { if (items.length != 2) throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to script"; @@ -1049,7 +1067,7 @@ function ReadManifest(aURL, inherited_status, aFilters) fuzzyMaxPixels: fuzzy_max_pixels, url1: testURI, url2: null, - chaosMode: chaosMode }, aFilters); + chaosMode: chaosMode }, aFilter); } else if (items[0] == TYPE_REFTEST_EQUAL || items[0] == TYPE_REFTEST_NOTEQUAL) { if (items.length != 3) throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to " + items[0]; @@ -1079,7 +1097,7 @@ function ReadManifest(aURL, inherited_status, aFilters) fuzzyMaxPixels: fuzzy_max_pixels, url1: testURI, url2: refURI, - chaosMode: chaosMode }, aFilters); + chaosMode: chaosMode }, aFilter); } else { throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": unknown test type " + items[0]; } diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py index 353a745c4d04..8853b283b46d 100644 --- a/layout/tools/reftest/runreftest.py +++ b/layout/tools/reftest/runreftest.py @@ -132,25 +132,47 @@ class ReftestResolver(object): "crashtest": "crashtests.list", "jstestbrowser": "jstests.list"}[suite] - def findManifest(self, suite, test_file): + def directoryManifest(self, suite, path): + return os.path.join(path, self.defaultManifest(suite)) + + def findManifest(self, suite, test_file, subdirs=True): """Return a tuple of (manifest-path, filter-string) for running test_file. test_file is a path to a test or a manifest file """ + rv = [] + default_manifest = self.defaultManifest(suite) if not os.path.isabs(test_file): test_file = self.absManifestPath(test_file) if os.path.isdir(test_file): - return os.path.join(test_file, self.defaultManifest(suite)), None + for dirpath, dirnames, filenames in os.walk(test_file): + if default_manifest in filenames: + rv.append((os.path.join(dirpath, default_manifest), None)) + # We keep recursing into subdirectories which means that in the case + # of include directives we get the same manifest multiple times. + # However reftest.js will only read each manifest once - if test_file.endswith('.list'): - return test_file, None + elif test_file.endswith('.list'): + if os.path.exists(test_file): + rv = [(test_file, None)] + else: + dirname, pathname = os.path.split(test_file) + found = True + while not os.path.exists(os.path.join(dirname, default_manifest)): + dirname, suffix = os.path.split(dirname) + pathname = os.path.join(suffix, pathname) + if os.path.dirname(dirname) == dirname: + found = False + break + if found: + rv = [(os.path.join(dirname, default_manifest), + r".*(?:/|\\)%s$" % pathname)] - return (self.findManifest(suite, os.path.dirname(test_file))[0], - r".*(?:/|\\)%s$" % os.path.basename(test_file)) + return rv def absManifestPath(self, path): - return os.path.abspath(path) + return os.path.normpath(os.path.abspath(path)) def manifestURL(self, options, path): return "file://%s" % path @@ -159,19 +181,20 @@ class ReftestResolver(object): suite = options.suite manifests = {} for testPath in tests: - manifest, filter_str = self.findManifest(suite, testPath) - manifest = self.manifestURL(options, manifest) - if manifest not in manifests: - manifests[manifest] = set() - if filter_str is not None: + for manifest, filter_str in self.findManifest(suite, testPath): + manifest = self.manifestURL(options, manifest) + if manifest not in manifests: + manifests[manifest] = set() manifests[manifest].add(filter_str) for key in manifests.iterkeys(): if os.path.split(key)[1] != self.defaultManifest(suite): print >> sys.stderr, "Invalid manifest for suite %s, %s" %(options.suite, key) sys.exit(1) - manifests[key] = sorted(list(manifests[key])) - + if None in manifests[key]: + manifests[key] = None + else: + manifests[key] = "|".join(list(manifests[key])) return manifests class RefTest(object): From e34ca60662965b7acaeb782e5293acdb50a9d9fa Mon Sep 17 00:00:00 2001 From: James Graham Date: Tue, 18 Aug 2015 17:42:03 +0100 Subject: [PATCH 005/131] Bug 1193224 - Remove vestigial --tests-root-dir option from xpcshell tests, r=ahal --- testing/xpcshell/mach_commands.py | 2 -- testing/xpcshell/runxpcshelltests.py | 19 +++++-------------- testing/xpcshell/selftest.py | 1 - 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/testing/xpcshell/mach_commands.py b/testing/xpcshell/mach_commands.py index 7683598147da..ed5084d140a4 100644 --- a/testing/xpcshell/mach_commands.py +++ b/testing/xpcshell/mach_commands.py @@ -162,7 +162,6 @@ class XPCShellRunner(MozbuildObject): 'logfiles': False, 'sequential': sequential, 'shuffle': shuffle, - 'testsRootDir': tests_dir, 'testingModulesDir': modules_dir, 'profileName': 'firefox', 'verbose': verbose or single_test, @@ -388,7 +387,6 @@ class B2GXPCShellRunner(MozbuildObject): options.objdir = self.topobjdir options.symbolsPath = os.path.join(self.distdir, 'crashreporter-symbols'), options.testingModulesDir = os.path.join(self.tests_dir, 'modules') - options.testsRootDir = self.xpcshell_dir options.testPath = test_path options.use_device_libs = True diff --git a/testing/xpcshell/runxpcshelltests.py b/testing/xpcshell/runxpcshelltests.py index 3c527ad64a08..763934527a3f 100755 --- a/testing/xpcshell/runxpcshelltests.py +++ b/testing/xpcshell/runxpcshelltests.py @@ -100,7 +100,7 @@ def markGotSIGINT(signum, stackFrame): class XPCShellTestThread(Thread): def __init__(self, test_object, event, cleanup_dir_list, retry=True, - tests_root_dir=None, app_dir_key=None, interactive=False, + app_dir_key=None, interactive=False, verbose=False, pStdout=None, pStderr=None, keep_going=False, log=None, **kwargs): Thread.__init__(self) @@ -130,7 +130,6 @@ class XPCShellTestThread(Thread): self.failureManifest = kwargs.get('failureManifest') self.stack_fixer_function = kwargs.get('stack_fixer_function') - self.tests_root_dir = tests_root_dir self.app_dir_key = app_dir_key self.interactive = interactive self.verbose = verbose @@ -1044,13 +1043,13 @@ class XPCShellTests(object): return '%s:%s' % (os.path.basename(test_object['ancestor-manifest']), path) return path - def runTests(self, xpcshell, xrePath=None, appPath=None, symbolsPath=None, + def runTests(self, xpcshell=None, xrePath=None, appPath=None, symbolsPath=None, manifest=None, testdirs=None, testPath=None, mobileArgs=None, interactive=False, verbose=False, keepGoing=False, logfiles=True, thisChunk=1, totalChunks=1, debugger=None, debuggerArgs=None, debuggerInteractive=False, profileName=None, mozInfo=None, sequential=False, shuffle=False, - testsRootDir=None, testingModulesDir=None, pluginsPath=None, + testingModulesDir=None, pluginsPath=None, testClass=XPCShellTestThread, failureManifest=None, log=None, stream=None, jsDebugger=False, jsDebuggerPort=0, test_tags=None, dump_tests=None, utility_path=None, **otherOptions): @@ -1083,8 +1082,6 @@ class XPCShellTests(object): directory if running only a subset of tests. |mozInfo|, if set, specifies specifies build configuration information, either as a filename containing JSON, or a dict. |shuffle|, if True, execute tests in random order. - |testsRootDir|, absolute path to root directory of all tests. This is used - by xUnit generation to determine the package name of the tests. |testingModulesDir|, if provided, specifies where JS modules reside. xpcshell will register a resource handler mapping this path. |otherOptions| may be present for the convenience of subclasses @@ -1279,13 +1276,10 @@ class XPCShellTests(object): if self.singleFile and not path.endswith(self.singleFile): continue - if self.testPath and path.find(self.testPath) == -1: - continue - self.testCount += 1 test = testClass(test_object, self.event, self.cleanup_dir_list, - tests_root_dir=testsRootDir, app_dir_key=appDirKey, + app_dir_key=appDirKey, interactive=interactive, verbose=verbose or test_object.get("verbose") == "true", pStdout=pStdout, pStderr=pStderr, @@ -1377,7 +1371,7 @@ class XPCShellTests(object): self.log.info("Retrying tests that failed when run in parallel.") for test_object in self.try_again_list: test = testClass(test_object, self.event, self.cleanup_dir_list, - retry=False, tests_root_dir=testsRootDir, + retry=False, app_dir_key=appDirKey, interactive=interactive, verbose=verbose, pStdout=pStdout, pStderr=pStderr, keep_going=keepGoing, log=self.log, mobileArgs=mobileArgs, @@ -1464,9 +1458,6 @@ class XPCShellOptions(OptionParser): self.add_option("--test-path", type="string", dest="testPath", default=None, help="single path and/or test filename to test") - self.add_option("--tests-root-dir", - type="string", dest="testsRootDir", default=None, - help="absolute path to directory where all tests are located. this is typically $(objdir)/_tests") self.add_option("--testing-modules-dir", dest="testingModulesDir", default=None, help="Directory where testing modules are located.") diff --git a/testing/xpcshell/selftest.py b/testing/xpcshell/selftest.py index 5ed4fe6cf220..854d32689759 100644 --- a/testing/xpcshell/selftest.py +++ b/testing/xpcshell/selftest.py @@ -422,7 +422,6 @@ tail = manifest=self.manifest, mozInfo=mozinfo.info, shuffle=shuffle, - testsRootDir=self.tempdir, verbose=verbose, sequential=True, utility_path=self.utility_path), From c6da3f49155e2199b899c1effe248e992410ee92 Mon Sep 17 00:00:00 2001 From: James Graham Date: Thu, 27 Aug 2015 13:05:50 +0100 Subject: [PATCH 006/131] Bug 1193257 - Make xpcshell harness command line arguments path filters for tests, r=ahal --- .../configs/unittests/linux_unittest.py | 12 +- testing/xpcshell/Makefile.in | 1 + testing/xpcshell/mach_commands.py | 388 ++++++------------ testing/xpcshell/remotexpcshelltests.py | 144 ++----- testing/xpcshell/runtestsb2g.py | 111 ++--- testing/xpcshell/runxpcshelltests.py | 228 +++------- testing/xpcshell/xpcshellcommandline.py | 202 +++++++++ 7 files changed, 467 insertions(+), 619 deletions(-) create mode 100644 testing/xpcshell/xpcshellcommandline.py diff --git a/testing/mozharness/configs/unittests/linux_unittest.py b/testing/mozharness/configs/unittests/linux_unittest.py index 65a9ba371346..618c934c470b 100644 --- a/testing/mozharness/configs/unittests/linux_unittest.py +++ b/testing/mozharness/configs/unittests/linux_unittest.py @@ -220,11 +220,13 @@ config = { 'tests/reftest/tests/testing/crashtest/crashtests.list']}, }, "all_xpcshell_suites": { - "xpcshell": ["--manifest=tests/xpcshell/tests/all-test-dirs.list", - "%(abs_app_dir)s/" + XPCSHELL_NAME], - "xpcshell-addons": ["--manifest=tests/xpcshell/tests/all-test-dirs.list", - "--tag=addons", - "%(abs_app_dir)s/" + XPCSHELL_NAME] + "xpcshell": {'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, + "--manifest=tests/xpcshell/tests/all-test-dirs.list"], + 'tests': []}, + "xpcshell-addons": {'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, + "--manifest=tests/xpcshell/tests/all-test-dirs.list", + "--tag=addons"], + 'tests': []} }, "all_cppunittest_suites": { "cppunittest": ['tests/cppunittest'] diff --git a/testing/xpcshell/Makefile.in b/testing/xpcshell/Makefile.in index ff1fa16729e4..5a9d0b567650 100644 --- a/testing/xpcshell/Makefile.in +++ b/testing/xpcshell/Makefile.in @@ -10,6 +10,7 @@ TEST_HARNESS_FILES := \ runxpcshelltests.py \ remotexpcshelltests.py \ runtestsb2g.py \ + xpcshellcommandline.py \ head.js \ node-spdy \ moz-spdy \ diff --git a/testing/xpcshell/mach_commands.py b/testing/xpcshell/mach_commands.py index ed5084d140a4..c2168c40209f 100644 --- a/testing/xpcshell/mach_commands.py +++ b/testing/xpcshell/mach_commands.py @@ -25,8 +25,7 @@ from mach.decorators import ( Command, ) -_parser = argparse.ArgumentParser() -structured.commandline.add_logging_group(_parser) +from xpcshellcommandline import parser_desktop, parser_remote, parser_b2g ADB_NOT_FOUND = ''' The %s command requires the adb binary to be on your path. @@ -40,6 +39,7 @@ BUSYBOX_URLS = { 'x86': 'http://www.busybox.net/downloads/binaries/latest/busybox-i686' } +here = os.path.abspath(os.path.dirname(__file__)) if sys.version_info[0] < 3: unicode_type = unicode @@ -55,20 +55,9 @@ class InvalidTestPathError(Exception): class XPCShellRunner(MozbuildObject): """Run xpcshell tests.""" def run_suite(self, **kwargs): - from manifestparser import TestManifest - manifest = TestManifest(manifests=[os.path.join(self.topobjdir, - '_tests', 'xpcshell', 'xpcshell.ini')]) + return self._run_xpcshell_harness(**kwargs) - return self._run_xpcshell_harness(manifest=manifest, **kwargs) - - def run_test(self, test_paths, interactive=False, - keep_going=False, sequential=False, shuffle=False, - debugger=None, debuggerArgs=None, debuggerInteractive=None, - jsDebugger=False, jsDebuggerPort=None, - rerun_failures=False, test_objects=None, verbose=False, - log=None, test_tags=None, dump_tests=None, - # ignore parameters from other platforms' options - **kwargs): + def run_test(self, **kwargs): """Runs an individual xpcshell test.""" from mozbuild.testing import TestResolver from manifestparser import TestManifest @@ -82,65 +71,15 @@ class XPCShellRunner(MozbuildObject): if os.path.isdir(src_build_path): sys.path.append(src_build_path) - if test_paths == 'all': - self.run_suite(interactive=interactive, - keep_going=keep_going, shuffle=shuffle, sequential=sequential, - debugger=debugger, debuggerArgs=debuggerArgs, - debuggerInteractive=debuggerInteractive, - jsDebugger=jsDebugger, jsDebuggerPort=jsDebuggerPort, - rerun_failures=rerun_failures, - verbose=verbose, log=log, test_tags=test_tags, dump_tests=dump_tests) - return - elif test_paths: - test_paths = [self._wrap_path_argument(p).relpath() for p in test_paths] + self.run_suite(**kwargs) - if test_objects: - tests = test_objects - else: - resolver = self._spawn(TestResolver) - tests = list(resolver.resolve_tests(paths=test_paths, - flavor='xpcshell')) - - if not tests: - raise InvalidTestPathError('We could not find an xpcshell test ' - 'for the passed test path. Please select a path that is ' - 'a test file or is a directory containing xpcshell tests.') - - # Dynamically write out a manifest holding all the discovered tests. - manifest = TestManifest() - manifest.tests.extend(tests) - - args = { - 'interactive': interactive, - 'keep_going': keep_going, - 'shuffle': shuffle, - 'sequential': sequential, - 'debugger': debugger, - 'debuggerArgs': debuggerArgs, - 'debuggerInteractive': debuggerInteractive, - 'jsDebugger': jsDebugger, - 'jsDebuggerPort': jsDebuggerPort, - 'rerun_failures': rerun_failures, - 'manifest': manifest, - 'verbose': verbose, - 'log': log, - 'test_tags': test_tags, - 'dump_tests': dump_tests, - } - - return self._run_xpcshell_harness(**args) - - def _run_xpcshell_harness(self, manifest, - test_path=None, shuffle=False, interactive=False, - keep_going=False, sequential=False, - debugger=None, debuggerArgs=None, debuggerInteractive=None, - jsDebugger=False, jsDebuggerPort=None, - rerun_failures=False, verbose=False, log=None, test_tags=None, - dump_tests=None): + def _run_xpcshell_harness(self, **kwargs): # Obtain a reference to the xpcshell test runner. import runxpcshelltests + log = kwargs.pop("log") + xpcshell = runxpcshelltests.XPCShellTests(log=log) self.log_manager.enable_unstructured() @@ -148,59 +87,41 @@ class XPCShellRunner(MozbuildObject): modules_dir = os.path.join(self.topobjdir, '_tests', 'modules') # We want output from the test to be written immediately if we are only # running a single test. - single_test = (test_path is not None or + single_test = (kwargs["testPaths"] is not None or (manifest and len(manifest.test_paths())==1)) - sequential = sequential or single_test + sequential = kwargs["sequential"] or single_test - args = { - 'manifest': manifest, - 'xpcshell': self.get_binary_path('xpcshell'), - 'mozInfo': os.path.join(self.topobjdir, 'mozinfo.json'), - 'symbolsPath': os.path.join(self.distdir, 'crashreporter-symbols'), - 'interactive': interactive, - 'keepGoing': keep_going, - 'logfiles': False, - 'sequential': sequential, - 'shuffle': shuffle, - 'testingModulesDir': modules_dir, - 'profileName': 'firefox', - 'verbose': verbose or single_test, - 'xunitFilename': os.path.join(self.statedir, 'xpchsell.xunit.xml'), - 'xunitName': 'xpcshell', - 'pluginsPath': os.path.join(self.distdir, 'plugins'), - 'debugger': debugger, - 'debuggerArgs': debuggerArgs, - 'debuggerInteractive': debuggerInteractive, - 'jsDebugger': jsDebugger, - 'jsDebuggerPort': jsDebuggerPort, - 'test_tags': test_tags, - 'dump_tests': dump_tests, - 'utility_path': self.bindir, - } + if kwargs["xpcshell"] is None: + kwargs["xpcshell"] = self.get_binary_path('xpcshell') - if test_path is not None: - args['testPath'] = test_path + if kwargs["mozInfo"] is None: + kwargs["mozInfo"] = os.path.join(self.topobjdir, 'mozinfo.json') - # A failure manifest is written by default. If --rerun-failures is - # specified and a prior failure manifest is found, the prior manifest - # will be run. A new failure manifest is always written over any - # prior failure manifest. - failure_manifest_path = os.path.join(self.statedir, 'xpcshell.failures.ini') - rerun_manifest_path = os.path.join(self.statedir, 'xpcshell.rerun.ini') - if os.path.exists(failure_manifest_path) and rerun_failures: - shutil.move(failure_manifest_path, rerun_manifest_path) - args['manifest'] = rerun_manifest_path - elif os.path.exists(failure_manifest_path): - os.remove(failure_manifest_path) - elif rerun_failures: - print("No failures were found to re-run.") - return 0 - args['failureManifest'] = failure_manifest_path + if kwargs["symbolsPath"] is None: + kwargs["symbolsPath"] = os.path.join(self.distdir, 'crashreporter-symbols') + + if kwargs["logfiles"] is None: + kwargs["logfiles"] = False + + if kwargs["profileName"] is None: + kwargs["profileName"] = "firefox" + + if kwargs["pluginsPath"] is None: + kwargs['pluginsPath'] = os.path.join(self.distdir, 'plugins') + + if kwargs["utility_path"] is None: + kwargs['utility_path'] = self.bindir + + if kwargs["manifest"] is None: + kwargs["manifest"] = os.path.join(tests_dir, "xpcshell.ini") + + if kwargs["failure_manifest"] is None: + kwargs["failure_manifest"] = os.path.join(self.statedir, 'xpcshell.failures.ini') # Python through 2.7.2 has issues with unicode in some of the # arguments. Work around that. filtered_args = {} - for k, v in args.items(): + for k, v in kwargs.iteritems(): if isinstance(v, unicode_type): v = v.encode('utf-8') @@ -236,12 +157,7 @@ class AndroidXPCShellRunner(MozbuildObject): return dm """Run Android xpcshell tests.""" - def run_test(self, - test_paths, keep_going, - devicemanager, ip, port, remote_test_root, no_setup, local_apk, - test_objects=None, log=None, - # ignore parameters from other platforms' options - **kwargs): + def run_test(self, **kwargs): # TODO Bug 794506 remove once mach integrates with virtualenv. build_path = os.path.join(self.topobjdir, 'build') if build_path not in sys.path: @@ -249,60 +165,53 @@ class AndroidXPCShellRunner(MozbuildObject): import remotexpcshelltests - dm = self.get_devicemanager(devicemanager, ip, port, remote_test_root) + dm = self.get_devicemanager(kwargs["dm_trans"], kwargs["deviceIP"], kwargs["devicePort"], + kwargs["remoteTestRoot"]) - options = remotexpcshelltests.RemoteXPCShellOptions() - options.shuffle = False - options.sequential = True - options.interactive = False - options.debugger = None - options.debuggerArgs = None - options.setup = not no_setup - options.keepGoing = keep_going - options.objdir = self.topobjdir - options.localLib = os.path.join(self.topobjdir, 'dist/fennec') - options.localBin = os.path.join(self.topobjdir, 'dist/bin') - options.testingModulesDir = os.path.join(self.topobjdir, '_tests/modules') - options.mozInfo = os.path.join(self.topobjdir, 'mozinfo.json') - options.manifest = os.path.join(self.topobjdir, '_tests/xpcshell/xpcshell.ini') - options.symbolsPath = os.path.join(self.distdir, 'crashreporter-symbols') - if local_apk: - options.localAPK = local_apk - else: - for file in os.listdir(os.path.join(options.objdir, "dist")): - if file.endswith(".apk") and file.startswith("fennec"): - options.localAPK = os.path.join(options.objdir, "dist") - options.localAPK = os.path.join(options.localAPK, file) - print ("using APK: " + options.localAPK) + log = kwargs.pop("log") + self.log_manager.enable_unstructured() + + if kwargs["xpcshell"] is None: + kwargs["xpcshell"] = "xpcshell" + + if not kwargs["objdir"]: + kwargs["objdir"] = self.topobjdir + + if not kwargs["localLib"]: + kwargs["localLib"] = os.path.join(self.topobjdir, 'dist/fennec') + + if not kwargs["localBin"]: + kwargs["localBin"] = os.path.join(self.topobjdir, 'dist/bin') + + if not kwargs["testingModulesDir"]: + kwargs["testingModulesDir"] = os.path.join(self.topobjdir, '_tests/modules') + + if not kwargs["mozInfo"]: + kwargs["mozInfo"] = os.path.join(self.topobjdir, 'mozinfo.json') + + if not kwargs["manifest"]: + kwargs["manifest"] = os.path.join(self.topobjdir, '_tests/xpcshell/xpcshell.ini') + + if not kwargs["symbolsPath"]: + kwargs["symbolsPath"] = os.path.join(self.distdir, 'crashreporter-symbols') + + if not kwargs["localAPK"]: + for file_name in os.listdir(os.path.join(kwargs["objdir"], "dist")): + if file_name.endswith(".apk") and file_name.startswith("fennec"): + kwargs["localAPK"] = os.path.join(kwargs["objdir"], "dist", file_name) + print ("using APK: %s" % kwargs["localAPK"]) break else: raise Exception("You must specify an APK") - if test_paths == 'all': - testdirs = [] - options.testPath = None - options.verbose = False - elif test_objects: - if len(test_objects) > 1: - print('Warning: only the first test will be used.') - testdirs = test_objects[0]['dir_relpath'] - options.testPath = test_objects[0]['path'] - options.verbose = True - else: - if len(test_paths) > 1: - print('Warning: only the first test path argument will be used.') - testdirs = test_paths[0] - options.testPath = test_paths[0] - options.verbose = True + options = argparse.Namespace(**kwargs) + xpcshell = remotexpcshelltests.XPCShellRemote(dm, options, log) - xpcshell = remotexpcshelltests.XPCShellRemote(dm, options, testdirs, log) - - result = xpcshell.runTests(xpcshell='xpcshell', - testClass=remotexpcshelltests.RemoteXPCShellTestThread, - testdirs=testdirs, - mobileArgs=xpcshell.mobileArgs, - **options.__dict__) + result = xpcshell.runTests(testClass=remotexpcshelltests.RemoteXPCShellTestThread, + mobileArgs=xpcshell.mobileArgs, + **vars(options)) + self.log_manager.disable_unstructured() return int(not result) @@ -349,56 +258,66 @@ class B2GXPCShellRunner(MozbuildObject): f.write(data.read()) return busybox_path - def run_test(self, test_paths, b2g_home=None, busybox=None, device_name=None, - test_objects=None, log=None, - # ignore parameters from other platforms' options - **kwargs): + def run_test(self, **kwargs): try: import which which.which('adb') except which.WhichError: # TODO Find adb automatically if it isn't on the path - print(ADB_NOT_FOUND % ('mochitest-remote', b2g_home)) + print(ADB_NOT_FOUND % ('mochitest-remote', kwargs["b2g_home"])) sys.exit(1) - test_path = None - if test_objects: - if len(test_objects) > 1: - print('Warning: Only the first test will be used.') - - test_path = self._wrap_path_argument(test_objects[0]['path']) - elif test_paths: - if len(test_paths) > 1: - print('Warning: Only the first test path will be used.') - - test_path = self._wrap_path_argument(test_paths[0]).relpath() - import runtestsb2g - parser = runtestsb2g.B2GOptions() - options, args = parser.parse_args([]) - options.b2g_path = b2g_home - options.busybox = busybox or os.environ.get('BUSYBOX') - options.localLib = self.bin_dir - options.localBin = self.bin_dir - options.logdir = self.xpcshell_dir - options.manifest = os.path.join(self.xpcshell_dir, 'xpcshell.ini') - options.mozInfo = os.path.join(self.topobjdir, 'mozinfo.json') - options.objdir = self.topobjdir - options.symbolsPath = os.path.join(self.distdir, 'crashreporter-symbols'), - options.testingModulesDir = os.path.join(self.tests_dir, 'modules') - options.testPath = test_path - options.use_device_libs = True + log = kwargs.pop("log") + self.log_manager.enable_unstructured() - options.emulator = 'arm' - if device_name.startswith('emulator'): - if 'x86' in device_name: - options.emulator = 'x86' + if kwargs["xpcshell"] is None: + kwargs["xpcshell"] = "xpcshell" + if kwargs["b2g_path"] is None: + kwargs["b2g_path"] = kwargs["b2g_home"] + if kwargs["busybox"] is None: + kwargs["busybox"] = os.environ.get('BUSYBOX') + if kwargs["busybox"] is None: + kwargs["busybox"] = self._download_busybox(kwargs["b2g_home"], kwargs["emulator"]) - if not options.busybox: - options.busybox = self._download_busybox(b2g_home, options.emulator) + if kwargs["localLib"] is None: + kwargs["localLib"] = self.bin_dir + if kwargs["localBin"] is None: + kwargs["localBin"] = self.bin_dir + if kwargs["logdir"] is None: + kwargs["logdir"] = self.xpcshell_dir + if kwargs["manifest"] is None: + kwargs["manifest"] = os.path.join(self.xpcshell_dir, 'xpcshell.ini') + if kwargs["mozInfo"] is None: + kwargs["mozInfo"] = os.path.join(self.topobjdir, 'mozinfo.json') + if kwargs["objdir"] is None: + kwargs["objdir"] = self.topobjdir + if kwargs["symbolsPath"] is None: + kwargs["symbolsPath"] = os.path.join(self.distdir, 'crashreporter-symbols') + if kwargs["testingModulesDir"] is None: + kwargs["testingModulesDir"] = os.path.join(self.tests_dir, 'modules') + if kwargs["use_device_libs"] is None: + kwargs["use_device_libs"] = True - return runtestsb2g.run_remote_xpcshell(parser, options, args, log) + if kwargs["device_name"].startswith('emulator') and 'x86' in kwargs["device_name"]: + kwargs["emulator"] = 'x86' + + parser = parser_b2g() + options = argparse.Namespace(**kwargs) + rv = runtestsb2g.run_remote_xpcshell(parser, options, log) + + self.log_manager.disable_unstructured() + return rv + +def get_parser(): + build_obj = MozbuildObject.from_environment(cwd=here) + if conditions.is_android(build_obj): + return parser_remote() + elif conditions.is_b2g(build_obj): + return parser_b2g() + else: + return parser_desktop() @CommandProvider class MachCommands(MachCommandBase): @@ -409,61 +328,10 @@ class MachCommands(MachCommandBase): setattr(self, attr, getattr(context, attr, None)) @Command('xpcshell-test', category='testing', - description='Run XPCOM Shell tests (API direct unit testing)', - conditions=[lambda *args: True], - parser=_parser) - @CommandArgument('test_paths', default='all', nargs='*', metavar='TEST', - help='Test to run. Can be specified as a single JS file, a directory, ' - 'or omitted. If omitted, the entire test suite is executed.') - @CommandArgument('--verbose', '-v', action='store_true', - help='Provide full output from each test process.') - @CommandArgument("--debugger", default=None, metavar='DEBUGGER', - help = "Run xpcshell under the given debugger.") - @CommandArgument("--debugger-args", default=None, metavar='ARGS', type=str, - dest = "debuggerArgs", - help = "pass the given args to the debugger _before_ " - "the application on the command line") - @CommandArgument("--debugger-interactive", action = "store_true", - dest = "debuggerInteractive", - help = "prevents the test harness from redirecting " - "stdout and stderr for interactive debuggers") - @CommandArgument("--jsdebugger", dest="jsDebugger", action="store_true", - help="Waits for a devtools JS debugger to connect before " - "starting the test.") - @CommandArgument("--jsdebugger-port", dest="jsDebuggerPort", - type=int, default=6000, - help="The port to listen on for a debugger connection if " - "--jsdebugger is specified (default=6000).") - @CommandArgument('--interactive', '-i', action='store_true', - help='Open an xpcshell prompt before running tests.') - @CommandArgument('--keep-going', '-k', action='store_true', - help='Continue running tests after a SIGINT is received.') - @CommandArgument('--sequential', action='store_true', - help='Run the tests sequentially.') - @CommandArgument('--shuffle', '-s', action='store_true', - help='Randomize the execution order of tests.') - @CommandArgument('--rerun-failures', action='store_true', - help='Reruns failures from last time.') - @CommandArgument('--tag', action='append', dest='test_tags', - help='Filter out tests that don\'t have the given tag. Can be used ' - 'multiple times in which case the test must contain at least one ' - 'of the given tags.') - @CommandArgument('--dump-tests', default=None, type=str, dest='dump_tests', - help='Specify path to a filename to dump all the tests that will be run') - @CommandArgument('--devicemanager', default='adb', type=str, - help='(Android) Type of devicemanager to use for communication: adb or sut') - @CommandArgument('--ip', type=str, default=None, - help='(Android) IP address of device') - @CommandArgument('--port', type=int, default=20701, - help='(Android) Port of device') - @CommandArgument('--remote_test_root', type=str, default=None, - help='(Android) Remote test root such as /mnt/sdcard or /data/local') - @CommandArgument('--no-setup', action='store_true', - help='(Android) Do not copy files to device') - @CommandArgument('--local-apk', type=str, default=None, - help='(Android) Use specified Fennec APK') - @CommandArgument('--busybox', type=str, default=None, - help='(B2G) Path to busybox binary (speeds up installation of tests).') + description='Run XPCOM Shell tests (API direct unit testing)', + conditions=[lambda *args: True], + parser=get_parser) + def run_xpcshell_test(self, **params): from mozbuild.controller.building import BuildDriver diff --git a/testing/xpcshell/remotexpcshelltests.py b/testing/xpcshell/remotexpcshelltests.py index b4775726f4f2..f4009ba7abfa 100644 --- a/testing/xpcshell/remotexpcshelltests.py +++ b/testing/xpcshell/remotexpcshelltests.py @@ -16,6 +16,8 @@ import mozdevice import mozfile import mozinfo +from xpcshellcommandline import parser_remote + here = os.path.dirname(os.path.abspath(__file__)) def remoteJoin(path1, path2): @@ -105,7 +107,7 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread): return (list(sanitize_list(test['head'], 'head')), list(sanitize_list(test['tail'], 'tail'))) - def buildXpcsCmd(self, testdir): + def buildXpcsCmd(self): # change base class' paths to remote paths and use base class to build command self.xpcshell = remoteJoin(self.remoteBinDir, "xpcw") self.headJSPath = remoteJoin(self.remoteScriptsDir, 'head.js') @@ -113,7 +115,7 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread): self.httpdManifest = remoteJoin(self.remoteComponentsDir, 'httpd.manifest') self.testingModulesDir = self.remoteModulesDir self.testharnessdir = self.remoteScriptsDir - xpcshell.XPCShellTestThread.buildXpcsCmd(self, testdir) + xpcshell.XPCShellTestThread.buildXpcsCmd(self) # remove "-g -a " and add "--greomni " del(self.xpcsCmd[1:5]) if self.options.localAPK: @@ -216,7 +218,7 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread): # via devicemanager. class XPCShellRemote(xpcshell.XPCShellTests, object): - def __init__(self, devmgr, options, args, log): + def __init__(self, devmgr, options, log): xpcshell.XPCShellTests.__init__(self, log) # Add Android version (SDK level) to mozinfo so that manifest entries @@ -517,8 +519,8 @@ class XPCShellRemote(xpcshell.XPCShellTests, object): self.device.removeDir(self.remoteMinidumpDir) self.device.mkDir(self.remoteMinidumpDir) - def buildTestList(self, test_tags=None): - xpcshell.XPCShellTests.buildTestList(self, test_tags=test_tags) + def buildTestList(self, test_tags=None, test_paths=None): + xpcshell.XPCShellTests.buildTestList(self, test_tags=test_tags, test_paths=test_paths) uniqueTestPaths = set([]) for test in self.alltests: uniqueTestPaths.add(test['here']) @@ -527,90 +529,37 @@ class XPCShellRemote(xpcshell.XPCShellTests, object): remoteScriptDir = remoteJoin(self.remoteScriptsDir, abbrevTestDir) self.pathMapping.append(PathMapping(testdir, remoteScriptDir)) -class RemoteXPCShellOptions(xpcshell.XPCShellOptions): - - def __init__(self): - xpcshell.XPCShellOptions.__init__(self) - defaults = {} - - self.add_option("--deviceIP", action="store", - type = "string", dest = "deviceIP", - help = "ip address of remote device to test") - defaults["deviceIP"] = None - - self.add_option("--devicePort", action="store", - type = "string", dest = "devicePort", - help = "port of remote device to test") - defaults["devicePort"] = 20701 - - self.add_option("--dm_trans", action="store", - type = "string", dest = "dm_trans", - help = "the transport to use to communicate with device: [adb|sut]; default=sut") - defaults["dm_trans"] = "sut" - - self.add_option("--objdir", action="store", - type = "string", dest = "objdir", - help = "local objdir, containing xpcshell binaries") - defaults["objdir"] = None - - self.add_option("--apk", action="store", - type = "string", dest = "localAPK", - help = "local path to Fennec APK") - defaults["localAPK"] = None - - self.add_option("--noSetup", action="store_false", - dest = "setup", - help = "do not copy any files to device (to be used only if device is already setup)") - defaults["setup"] = True - - self.add_option("--local-lib-dir", action="store", - type = "string", dest = "localLib", - help = "local path to library directory") - defaults["localLib"] = None - - self.add_option("--local-bin-dir", action="store", - type = "string", dest = "localBin", - help = "local path to bin directory") - defaults["localBin"] = None - - self.add_option("--remoteTestRoot", action = "store", - type = "string", dest = "remoteTestRoot", - help = "remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)") - defaults["remoteTestRoot"] = None - - self.set_defaults(**defaults) - - def verifyRemoteOptions(self, options): - if options.localLib is None: - if options.localAPK and options.objdir: - for path in ['dist/fennec', 'fennec/lib']: - options.localLib = os.path.join(options.objdir, path) - if os.path.isdir(options.localLib): - break - else: - self.error("Couldn't find local library dir, specify --local-lib-dir") - elif options.objdir: - options.localLib = os.path.join(options.objdir, 'dist/bin') - elif os.path.isfile(os.path.join(here, '..', 'bin', 'xpcshell')): - # assume tests are being run from a tests.zip - options.localLib = os.path.abspath(os.path.join(here, '..', 'bin')) +def verifyRemoteOptions(parser, options): + if options.localLib is None: + if options.localAPK and options.objdir: + for path in ['dist/fennec', 'fennec/lib']: + options.localLib = os.path.join(options.objdir, path) + if os.path.isdir(options.localLib): + break else: - self.error("Couldn't find local library dir, specify --local-lib-dir") + parser.error("Couldn't find local library dir, specify --local-lib-dir") + elif options.objdir: + options.localLib = os.path.join(options.objdir, 'dist/bin') + elif os.path.isfile(os.path.join(here, '..', 'bin', 'xpcshell')): + # assume tests are being run from a tests.zip + options.localLib = os.path.abspath(os.path.join(here, '..', 'bin')) + else: + parser.error("Couldn't find local library dir, specify --local-lib-dir") - if options.localBin is None: - if options.objdir: - for path in ['dist/bin', 'bin']: - options.localBin = os.path.join(options.objdir, path) - if os.path.isdir(options.localBin): - break - else: - self.error("Couldn't find local binary dir, specify --local-bin-dir") - elif os.path.isfile(os.path.join(here, '..', 'bin', 'xpcshell')): - # assume tests are being run from a tests.zip - options.localBin = os.path.abspath(os.path.join(here, '..', 'bin')) + if options.localBin is None: + if options.objdir: + for path in ['dist/bin', 'bin']: + options.localBin = os.path.join(options.objdir, path) + if os.path.isdir(options.localBin): + break else: - self.error("Couldn't find local binary dir, specify --local-bin-dir") - return options + parser.error("Couldn't find local binary dir, specify --local-bin-dir") + elif os.path.isfile(os.path.join(here, '..', 'bin', 'xpcshell')): + # assume tests are being run from a tests.zip + options.localBin = os.path.abspath(os.path.join(here, '..', 'bin')) + else: + parser.error("Couldn't find local binary dir, specify --local-bin-dir") + return options class PathMapping: @@ -619,14 +568,13 @@ class PathMapping: self.remote = remoteDir def main(): - if sys.version_info < (2,7): print >>sys.stderr, "Error: You must use python version 2.7 or newer but less than 3.0" sys.exit(1) - parser = RemoteXPCShellOptions() + parser = parser_remote() commandline.add_logging_group(parser) - options, args = parser.parse_args() + options = parser.parse_args() if not options.localAPK: for file in os.listdir(os.path.join(options.objdir, "dist")): if (file.endswith(".apk") and file.startswith("fennec")): @@ -638,16 +586,11 @@ def main(): print >>sys.stderr, "Error: please specify an APK" sys.exit(1) - options = parser.verifyRemoteOptions(options) + options = verifyRemoteOptions(parser, options) log = commandline.setup_logging("Remote XPCShell", options, {"tbpl": sys.stdout}) - if len(args) < 1 and options.manifest is None: - print >>sys.stderr, """Usage: %s - or: %s --manifest=test.manifest """ % (sys.argv[0], sys.argv[0]) - sys.exit(1) - if options.dm_trans == "adb": if options.deviceIP: dm = mozdevice.DroidADB(options.deviceIP, options.devicePort, packageName=None, deviceRoot=options.remoteTestRoot) @@ -663,16 +606,17 @@ def main(): print >>sys.stderr, "Error: You must specify a test filename in interactive mode!" sys.exit(1) - xpcsh = XPCShellRemote(dm, options, args, log) + if options.xpcshell is None: + options.xpcshell = "xpcshell" + + xpcsh = XPCShellRemote(dm, options, log) # we don't run concurrent tests on mobile options.sequential = True - if not xpcsh.runTests(xpcshell='xpcshell', - testClass=RemoteXPCShellTestThread, - testdirs=args[0:], + if not xpcsh.runTests(testClass=RemoteXPCShellTestThread, mobileArgs=xpcsh.mobileArgs, - **options.__dict__): + **vars(options)): sys.exit(1) diff --git a/testing/xpcshell/runtestsb2g.py b/testing/xpcshell/runtestsb2g.py index 21b1325f13a2..5ea7697118f8 100644 --- a/testing/xpcshell/runtestsb2g.py +++ b/testing/xpcshell/runtestsb2g.py @@ -9,14 +9,15 @@ import os sys.path.insert(0, os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))) import traceback -from remotexpcshelltests import RemoteXPCShellTestThread, XPCShellRemote, RemoteXPCShellOptions +import remotexpcshelltests +from remotexpcshelltests import RemoteXPCShellTestThread, XPCShellRemote from mozdevice import devicemanagerADB, DMError from mozlog import commandline DEVICE_TEST_ROOT = '/data/local/tests' - from marionette import Marionette +from xpcshellcommandline import parser_b2g class B2GXPCShellTestThread(RemoteXPCShellTestThread): # Overridden @@ -75,87 +76,19 @@ class B2GXPCShellRemote(XPCShellRemote): self.env['LD_LIBRARY_PATH'] = '/system/b2g' self.options.use_device_libs = True -class B2GOptions(RemoteXPCShellOptions): +def verifyRemoteOptions(parser, options): + if options.b2g_path is None: + parser.error("Need to specify a --b2gpath") - def __init__(self): - RemoteXPCShellOptions.__init__(self) - defaults = {} + if options.geckoPath and not options.emulator: + parser.error("You must specify --emulator if you specify --gecko-path") - self.add_option('--b2gpath', action='store', - type='string', dest='b2g_path', - help="Path to B2G repo or qemu dir") - defaults['b2g_path'] = None + if options.logdir and not options.emulator: + parser.error("You must specify --emulator if you specify --logdir") + return remotexpcshelltests.verifyRemoteOptions(parser, options) - self.add_option('--emupath', action='store', - type='string', dest='emu_path', - help="Path to emulator folder (if different " - "from b2gpath") - - self.add_option('--no-clean', action='store_false', - dest='clean', - help="Do not clean TESTROOT. Saves [lots of] time") - defaults['clean'] = True - - defaults['emu_path'] = None - - self.add_option('--emulator', action='store', - type='string', dest='emulator', - help="Architecture of emulator to use: x86 or arm") - defaults['emulator'] = None - - self.add_option('--no-window', action='store_true', - dest='no_window', - help="Pass --no-window to the emulator") - defaults['no_window'] = False - - self.add_option('--adbpath', action='store', - type='string', dest='adb_path', - help="Path to adb") - defaults['adb_path'] = 'adb' - - self.add_option('--address', action='store', - type='string', dest='address', - help="host:port of running Gecko instance to connect to") - defaults['address'] = None - - self.add_option('--use-device-libs', action='store_true', - dest='use_device_libs', - help="Don't push .so's") - defaults['use_device_libs'] = False - self.add_option("--gecko-path", action="store", - type="string", dest="geckoPath", - help="the path to a gecko distribution that should " - "be installed on the emulator prior to test") - defaults["geckoPath"] = None - self.add_option("--logdir", action="store", - type="string", dest="logdir", - help="directory to store log files") - defaults["logdir"] = None - self.add_option('--busybox', action='store', - type='string', dest='busybox', - help="Path to busybox binary to install on device") - defaults['busybox'] = None - - defaults["remoteTestRoot"] = DEVICE_TEST_ROOT - defaults['dm_trans'] = 'adb' - defaults['debugger'] = None - defaults['debuggerArgs'] = None - - self.set_defaults(**defaults) - - def verifyRemoteOptions(self, options): - if options.b2g_path is None: - self.error("Need to specify a --b2gpath") - - if options.geckoPath and not options.emulator: - self.error("You must specify --emulator if you specify --gecko-path") - - if options.logdir and not options.emulator: - self.error("You must specify --emulator if you specify --logdir") - return RemoteXPCShellOptions.verifyRemoteOptions(self, options) - -def run_remote_xpcshell(parser, options, args, log): - options = parser.verifyRemoteOptions(options) +def run_remote_xpcshell(parser, options, log): + options = verifyRemoteOptions(parser, options) # Create the Marionette instance kwargs = {} @@ -195,16 +128,18 @@ def run_remote_xpcshell(parser, options, args, log): if not options.remoteTestRoot: options.remoteTestRoot = dm.deviceRoot - xpcsh = B2GXPCShellRemote(dm, options, args, log) + xpcsh = B2GXPCShellRemote(dm, options, log) # we don't run concurrent tests on mobile options.sequential = True + if options.xpcshell is None: + options.xpcshell = "xpcshell" + try: - if not xpcsh.runTests(xpcshell='xpcshell', testdirs=args[0:], - testClass=B2GXPCShellTestThread, - mobileArgs=xpcsh.mobileArgs, - **options.__dict__): + if not xpcsh.runTests(testClass=B2GXPCShellTestThread, + mobileArgs=xpcsh.mobileArgs, + **vars(options)): sys.exit(1) except: print "Automation Error: Exception caught while running tests" @@ -212,13 +147,13 @@ def run_remote_xpcshell(parser, options, args, log): sys.exit(1) def main(): - parser = B2GOptions() + parser = parser_b2g() commandline.add_logging_group(parser) - options, args = parser.parse_args() + options = parser.parse_args() log = commandline.setup_logging("Remote XPCShell", options, {"tbpl": sys.stdout}) - run_remote_xpcshell(parser, options, args, log) + run_remote_xpcshell(parser, options, log) # You usually run this like : # python runtestsb2g.py --emulator arm --b2gpath $B2GPATH --manifest $MANIFEST [--xre-path $MOZ_HOST_BIN diff --git a/testing/xpcshell/runxpcshelltests.py b/testing/xpcshell/runxpcshelltests.py index 763934527a3f..b4e38e67780b 100755 --- a/testing/xpcshell/runxpcshelltests.py +++ b/testing/xpcshell/runxpcshelltests.py @@ -23,7 +23,7 @@ import traceback from collections import deque, namedtuple from distutils import dir_util from multiprocessing import cpu_count -from optparse import OptionParser +from argparse import ArgumentParser from subprocess import Popen, PIPE, STDOUT from tempfile import mkdtemp, gettempdir from threading import ( @@ -40,6 +40,9 @@ except Exception: HAVE_PSUTIL = False from automation import Automation +from xpcshellcommandline import parser_desktop + +SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__))) HARNESS_TIMEOUT = 5 * 60 @@ -62,7 +65,7 @@ if os.path.isdir(mozbase): sys.path.append(os.path.join(mozbase, package)) from manifestparser import TestManifest -from manifestparser.filters import chunk_by_slice, tags +from manifestparser.filters import chunk_by_slice, tags, pathprefix from mozlog import commandline import mozcrash import mozinfo @@ -412,7 +415,7 @@ class XPCShellTestThread(Thread): return (list(sanitize_list(headlist, 'head')), list(sanitize_list(taillist, 'tail'))) - def buildXpcsCmd(self, testdir): + def buildXpcsCmd(self): """ Load the root head.js file as the first file in our test path, before other head, test, and tail files. On a remote system, we overload this to add additional command line arguments, so this gets overloaded. @@ -614,7 +617,7 @@ class XPCShellTestThread(Thread): self.tempDir = self.setupTempDir() self.mozInfoJSPath = self.setupMozinfoJS() - self.buildXpcsCmd(test_dir) + self.buildXpcsCmd() head_files, tail_files = self.getHeadAndTailFiles(self.test_object) cmdH = self.buildCmdHead(head_files, tail_files, self.xpcsCmd) @@ -767,30 +770,50 @@ class XPCShellTests(object): self.harness_timeout = HARNESS_TIMEOUT self.nodeProc = {} - def buildTestList(self, test_tags=None): + def getTestManifest(self, manifest): + if isinstance(manifest, TestManifest): + return manifest + elif manifest is not None: + manifest = os.path.normpath(os.path.abspath(manifest)) + if os.path.isfile(manifest): + return TestManifest([manifest], strict=True) + else: + ini_path = os.path.join(manifest, "xpcshell.ini") + else: + ini_path = os.path.join(SCRIPT_DIR, "tests", "xpcshell.ini") + + if os.path.exists(ini_path): + return TestManifest([ini_path], strict=True) + else: + print >> sys.stderr, ("Failed to find manifest at %s; use --manifest " + "to set path explicitly." % (ini_path,)) + sys.exit(1) + + def buildTestList(self, test_tags=None, test_paths=None): """ read the xpcshell.ini manifest and set self.alltests to be an array of test objects. if we are chunking tests, it will be done here as well """ - if isinstance(self.manifest, TestManifest): - mp = self.manifest - else: - mp = TestManifest(strict=True) - if self.manifest is None: - for testdir in self.testdirs: - if testdir: - mp.read(os.path.join(testdir, 'xpcshell.ini')) - else: - mp.read(self.manifest) - self.buildTestPath() + if test_paths is None: + test_paths = [] + + if len(test_paths) == 1 and test_paths[0].endswith(".js"): + self.singleFile = os.path.basename(test_paths[0]) + else: + self.singleFile = None + + mp = self.getTestManifest(self.manifest) filters = [] if test_tags: filters.append(tags(test_tags)) + if test_paths: + filters.append(pathprefix(test_paths)) + if self.singleFile is None and self.totalChunks > 1: filters.append(chunk_by_slice(self.thisChunk, self.totalChunks)) try: @@ -917,31 +940,6 @@ class XPCShellTests(object): pStderr = STDOUT return pStdout, pStderr - def buildTestPath(self): - """ - If we specifiy a testpath, set the self.testPath variable to be the given directory or file. - - |testPath| will be the optional path only, or |None|. - |singleFile| will be the optional test only, or |None|. - """ - self.singleFile = None - if self.testPath is not None: - if self.testPath.endswith('.js'): - # Split into path and file. - if self.testPath.find('/') == -1: - # Test only. - self.singleFile = self.testPath - else: - # Both path and test. - # Reuse |testPath| temporarily. - self.testPath = self.testPath.rsplit('/', 1) - self.singleFile = self.testPath[1] - self.testPath = self.testPath[0] - else: - # Path only. - # Simply remove optional ending separator. - self.testPath = self.testPath.rstrip("/") - def verifyDirPath(self, dirname): """ Simple wrapper to get the absolute path for a given directory name. @@ -1044,7 +1042,7 @@ class XPCShellTests(object): return path def runTests(self, xpcshell=None, xrePath=None, appPath=None, symbolsPath=None, - manifest=None, testdirs=None, testPath=None, mobileArgs=None, + manifest=None, testPaths=None, mobileArgs=None, interactive=False, verbose=False, keepGoing=False, logfiles=True, thisChunk=1, totalChunks=1, debugger=None, debuggerArgs=None, debuggerInteractive=False, @@ -1052,7 +1050,8 @@ class XPCShellTests(object): testingModulesDir=None, pluginsPath=None, testClass=XPCShellTestThread, failureManifest=None, log=None, stream=None, jsDebugger=False, jsDebuggerPort=0, - test_tags=None, dump_tests=None, utility_path=None, **otherOptions): + test_tags=None, dump_tests=None, utility_path=None, + rerun_failures=False, failure_manifest=None, **otherOptions): """Run xpcshell tests. |xpcshell|, is the xpcshell executable to use to run the tests. @@ -1062,9 +1061,8 @@ class XPCShellTests(object): breakpad symbols for processing crashes in tests. |manifest|, if provided, is a file containing a list of test directories to run. - |testdirs|, if provided, is a list of absolute paths of test directories. - No-manifest only option. - |testPath|, if provided, indicates a single path and/or test to run. + |testPaths|, if provided, is a list of paths to files or directories containing + tests to run. |pluginsPath|, if provided, custom plugins directory to be returned from the xpcshell dir svc provider for NS_APP_PLUGINS_DIR_LIST. |interactive|, if set to True, indicates to provide an xpcshell prompt @@ -1089,9 +1087,6 @@ class XPCShellTests(object): global gotSIGINT - if testdirs is None: - testdirs = [] - # Try to guess modules directory. # This somewhat grotesque hack allows the buildbot machines to find the # modules directory without having to configure the buildbot hosts. This @@ -1104,6 +1099,16 @@ class XPCShellTests(object): if os.path.isdir(possible): testingModulesDir = possible + if rerun_failures: + if os.path.exists(failure_manifest): + rerun_manifest = os.path.join(os.path.dirname(failure_manifest), "rerun.ini") + shutil.copyfile(failure_manifest, rerun_manifest) + os.remove(failure_manifest) + manifest = rerun_manifest + else: + print >> sys.stderr, "No failures were found to re-run." + sys.exit(1) + if testingModulesDir: # The resource loader expects native paths. Depending on how we were # invoked, a UNIX style path may sneak in on Windows. We try to @@ -1132,8 +1137,6 @@ class XPCShellTests(object): self.appPath = appPath self.symbolsPath = symbolsPath self.manifest = manifest - self.testdirs = testdirs - self.testPath = testPath self.dump_tests = dump_tests self.interactive = interactive self.verbose = verbose @@ -1146,11 +1149,7 @@ class XPCShellTests(object): self.testingModulesDir = testingModulesDir self.pluginsPath = pluginsPath self.sequential = sequential - - if not testdirs and not manifest: - # nothing to test! - self.log.error("Error: No test dirs or test manifest specified!") - return False + self.failure_manifest = failure_manifest self.testCount = 0 self.passCount = 0 @@ -1203,7 +1202,7 @@ class XPCShellTests(object): pStdout, pStderr = self.getPipes() - self.buildTestList(test_tags) + self.buildTestList(test_tags, testPaths) if self.singleFile: self.sequential = True @@ -1231,7 +1230,7 @@ class XPCShellTests(object): 'logfiles': self.logfiles, 'xpcshell': self.xpcshell, 'xpcsRunArgs': self.xpcsRunArgs, - 'failureManifest': failureManifest, + 'failureManifest': self.failure_manifest, 'harness_timeout': self.harness_timeout, 'stack_fixer_function': self.stack_fixer_function, } @@ -1424,119 +1423,16 @@ class XPCShellTests(object): self.log.suite_end() return self.failCount == 0 -class XPCShellOptions(OptionParser): - def __init__(self): - """Process command line arguments and call runTests() to do the real work.""" - OptionParser.__init__(self) - self.add_option("--app-path", - type="string", dest="appPath", default=None, - help="application directory (as opposed to XRE directory)") - self.add_option("--interactive", - action="store_true", dest="interactive", default=False, - help="don't automatically run tests, drop to an xpcshell prompt") - self.add_option("--verbose", - action="store_true", dest="verbose", default=False, - help="always print stdout and stderr from tests") - self.add_option("--keep-going", - action="store_true", dest="keepGoing", default=False, - help="continue running tests after test killed with control-C (SIGINT)") - self.add_option("--logfiles", - action="store_true", dest="logfiles", default=True, - help="create log files (default, only used to override --no-logfiles)") - self.add_option("--dump-tests", - type="string", dest="dump_tests", default=None, - help="Specify path to a filename to dump all the tests that will be run") - self.add_option("--manifest", - type="string", dest="manifest", default=None, - help="Manifest of test directories to use") - self.add_option("--no-logfiles", - action="store_false", dest="logfiles", - help="don't create log files") - self.add_option("--sequential", - action="store_true", dest="sequential", default=False, - help="Run all tests sequentially") - self.add_option("--test-path", - type="string", dest="testPath", default=None, - help="single path and/or test filename to test") - self.add_option("--testing-modules-dir", - dest="testingModulesDir", default=None, - help="Directory where testing modules are located.") - self.add_option("--test-plugin-path", - type="string", dest="pluginsPath", default=None, - help="Path to the location of a plugins directory containing the test plugin or plugins required for tests. " - "By default xpcshell's dir svc provider returns gre/plugins. Use test-plugin-path to add a directory " - "to return for NS_APP_PLUGINS_DIR_LIST when queried.") - self.add_option("--total-chunks", - type = "int", dest = "totalChunks", default=1, - help = "how many chunks to split the tests up into") - self.add_option("--this-chunk", - type = "int", dest = "thisChunk", default=1, - help = "which chunk to run between 1 and --total-chunks") - self.add_option("--profile-name", - type = "string", dest="profileName", default=None, - help="name of application profile being tested") - self.add_option("--build-info-json", - type = "string", dest="mozInfo", default=None, - help="path to a mozinfo.json including information about the build configuration. defaults to looking for mozinfo.json next to the script.") - self.add_option("--shuffle", - action="store_true", dest="shuffle", default=False, - help="Execute tests in random order") - self.add_option("--failure-manifest", dest="failureManifest", - action="store", - help="path to file where failure manifest will be written.") - self.add_option("--xre-path", - action = "store", type = "string", dest = "xrePath", - # individual scripts will set a sane default - default = None, - help = "absolute path to directory containing XRE (probably xulrunner)") - self.add_option("--symbols-path", - action = "store", type = "string", dest = "symbolsPath", - default = None, - help = "absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols") - self.add_option("--debugger", - action = "store", dest = "debugger", - help = "use the given debugger to launch the application") - self.add_option("--debugger-args", - action = "store", dest = "debuggerArgs", - help = "pass the given args to the debugger _before_ " - "the application on the command line") - self.add_option("--debugger-interactive", - action = "store_true", dest = "debuggerInteractive", - help = "prevents the test harness from redirecting " - "stdout and stderr for interactive debuggers") - self.add_option("--jsdebugger", dest="jsDebugger", action="store_true", - help="Waits for a devtools JS debugger to connect before " - "starting the test.") - self.add_option("--jsdebugger-port", type="int", dest="jsDebuggerPort", - default=6000, - help="The port to listen on for a debugger connection if " - "--jsdebugger is specified.") - self.add_option("--tag", - action="append", dest="test_tags", - default=None, - help="filter out tests that don't have the given tag. Can be " - "used multiple times in which case the test must contain " - "at least one of the given tags.") - self.add_option("--utility-path", - action="store", dest="utility_path", - default=None, - help="Path to a directory containing utility programs, such " - "as stack fixer scripts.") def main(): - parser = XPCShellOptions() + parser = parser_desktop() commandline.add_logging_group(parser) - options, args = parser.parse_args() - + options = parser.parse_args() log = commandline.setup_logging("XPCShell", options, {"tbpl": sys.stdout}) - if len(args) < 2 and options.manifest is None or \ - (len(args) < 1 and options.manifest is not None): - print >>sys.stderr, """Usage: %s - or: %s --manifest=test.manifest """ % (sys.argv[0], - sys.argv[0]) - sys.exit(1) + if options.xpcshell is None: + print >> sys.stderr, """Must provide path to xpcshell using --xpcshell""" xpcsh = XPCShellTests(log) @@ -1544,7 +1440,7 @@ def main(): print >>sys.stderr, "Error: You must specify a test filename in interactive mode!" sys.exit(1) - if not xpcsh.runTests(args[0], testdirs=args[1:], **options.__dict__): + if not xpcsh.runTests(**vars(options)): sys.exit(1) if __name__ == '__main__': diff --git a/testing/xpcshell/xpcshellcommandline.py b/testing/xpcshell/xpcshellcommandline.py new file mode 100644 index 000000000000..7152ec9ac524 --- /dev/null +++ b/testing/xpcshell/xpcshellcommandline.py @@ -0,0 +1,202 @@ +import argparse + +def add_common_arguments(parser): + parser.add_argument("--app-path", + type=unicode, dest="appPath", default=None, + help="application directory (as opposed to XRE directory)") + parser.add_argument("--interactive", + action="store_true", dest="interactive", default=False, + help="don't automatically run tests, drop to an xpcshell prompt") + parser.add_argument("--verbose", + action="store_true", dest="verbose", default=False, + help="always print stdout and stderr from tests") + parser.add_argument("--keep-going", + action="store_true", dest="keepGoing", default=False, + help="continue running tests after test killed with control-C (SIGINT)") + parser.add_argument("--logfiles", + action="store_true", dest="logfiles", default=True, + help="create log files (default, only used to override --no-logfiles)") + parser.add_argument("--dump-tests", type=str, dest="dump_tests", default=None, + help="Specify path to a filename to dump all the tests that will be run") + parser.add_argument("--manifest", + type=unicode, dest="manifest", default=None, + help="Manifest of test directories to use") + parser.add_argument("--no-logfiles", + action="store_false", dest="logfiles", + help="don't create log files") + parser.add_argument("--sequential", + action="store_true", dest="sequential", default=False, + help="Run all tests sequentially") + parser.add_argument("--testing-modules-dir", + dest="testingModulesDir", default=None, + help="Directory where testing modules are located.") + parser.add_argument("--test-plugin-path", + type=str, dest="pluginsPath", default=None, + help="Path to the location of a plugins directory containing the test plugin or plugins required for tests. " + "By default xpcshell's dir svc provider returns gre/plugins. Use test-plugin-path to add a directory " + "to return for NS_APP_PLUGINS_DIR_LIST when queried.") + parser.add_argument("--total-chunks", + type=int, dest="totalChunks", default=1, + help="how many chunks to split the tests up into") + parser.add_argument("--this-chunk", + type=int, dest="thisChunk", default=1, + help="which chunk to run between 1 and --total-chunks") + parser.add_argument("--profile-name", + type=str, dest="profileName", default=None, + help="name of application profile being tested") + parser.add_argument("--build-info-json", + type=str, dest="mozInfo", default=None, + help="path to a mozinfo.json including information about the build configuration. defaults to looking for mozinfo.json next to the script.") + parser.add_argument("--shuffle", + action="store_true", dest="shuffle", default=False, + help="Execute tests in random order") + parser.add_argument("--xre-path", + action="store", type=str, dest="xrePath", + # individual scripts will set a sane default + default=None, + help="absolute path to directory containing XRE (probably xulrunner)") + parser.add_argument("--symbols-path", + action="store", type=str, dest="symbolsPath", + default=None, + help="absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols") + parser.add_argument("--debugger", + action="store", dest="debugger", + help="use the given debugger to launch the application") + parser.add_argument("--debugger-args", + action="store", dest="debuggerArgs", + help="pass the given args to the debugger _before_ " + "the application on the command line") + parser.add_argument("--debugger-interactive", + action="store_true", dest="debuggerInteractive", + help="prevents the test harness from redirecting " + "stdout and stderr for interactive debuggers") + parser.add_argument("--jsdebugger", dest="jsDebugger", action="store_true", + help="Waits for a devtools JS debugger to connect before " + "starting the test.") + parser.add_argument("--jsdebugger-port", type=int, dest="jsDebuggerPort", + default=6000, + help="The port to listen on for a debugger connection if " + "--jsdebugger is specified.") + parser.add_argument("--tag", + action="append", dest="test_tags", + default=None, + help="filter out tests that don't have the given tag. Can be " + "used multiple times in which case the test must contain " + "at least one of the given tags.") + parser.add_argument("--utility-path", + action="store", dest="utility_path", + default=None, + help="Path to a directory containing utility programs, such " + "as stack fixer scripts.") + parser.add_argument("--xpcshell", + action="store", dest="xpcshell", + default=None, + help="Path to xpcshell binary") + # This argument can be just present, or the path to a manifest file. The + # just-present case is usually used for mach which can provide a default + # path to the failure file from the previous run + parser.add_argument("--rerun-failures", + action="store_true", + help="Rerun failures from the previous run, if any") + parser.add_argument("--failure-manifest", + action="store", + help="Path to a manifest file from which to rerun failures " + "(with --rerun-failure) or in which to record failed tests") + parser.add_argument("testPaths", nargs="*", default=None, + help="Paths of tests to run.") + +def add_remote_arguments(parser): + parser.add_argument("--deviceIP", action="store", type=str, dest="deviceIP", + help="ip address of remote device to test") + + parser.add_argument("--devicePort", action="store", type=str, dest="devicePort", + default=20701, help="port of remote device to test") + + parser.add_argument("--dm_trans", action="store", type=str, dest="dm_trans", + choices=["adb", "sut"], default="sut", + help="the transport to use to communicate with device: [adb|sut]; default=sut") + + parser.add_argument("--objdir", action="store", type=str, dest="objdir", + help="local objdir, containing xpcshell binaries") + + + parser.add_argument("--apk", action="store", type=str, dest="localAPK", + help="local path to Fennec APK") + + + parser.add_argument("--noSetup", action="store_false", dest="setup", default=True, + help="do not copy any files to device (to be used only if device is already setup)") + + parser.add_argument("--local-lib-dir", action="store", type=str, dest="localLib", + help="local path to library directory") + + parser.add_argument("--local-bin-dir", action="store", type=str, dest="localBin", + help="local path to bin directory") + + parser.add_argument("--remoteTestRoot", action="store", type=str, dest="remoteTestRoot", + help="remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)") + +def add_b2g_arguments(parser): + parser.add_argument('--b2gpath', action='store', type=str, dest='b2g_path', + help="Path to B2G repo or qemu dir") + + parser.add_argument('--emupath', action='store', type=str, dest='emu_path', + help="Path to emulator folder (if different " + "from b2gpath") + + parser.add_argument('--no-clean', action='store_false', dest='clean', default=True, + help="Do not clean TESTROOT. Saves [lots of] time") + + parser.add_argument('--emulator', action='store', type=str, dest='emulator', + default="arm", choices=["x86", "arm"], + help="Architecture of emulator to use: x86 or arm") + + parser.add_argument('--no-window', action='store_true', dest='no_window', default=False, + help="Pass --no-window to the emulator") + + parser.add_argument('--adbpath', action='store', type=str, dest='adb_path', + default="adb", help="Path to adb") + + parser.add_argument('--address', action='store', type=str, dest='address', + help="host:port of running Gecko instance to connect to") + + parser.add_argument('--use-device-libs', action='store_true', dest='use_device_libs', + default=None, help="Don't push .so's") + + parser.add_argument("--gecko-path", action="store", type=str, dest="geckoPath", + help="the path to a gecko distribution that should " + "be installed on the emulator prior to test") + + parser.add_argument("--logdir", action="store", type=str, dest="logdir", + help="directory to store log files") + + parser.add_argument('--busybox', action='store', type=str, dest='busybox', + help="Path to busybox binary to install on device") + + parser.set_defaults(remoteTestRoot="/data/local/tests", + dm_trans="adb") + +def parser_desktop(): + parser = argparse.ArgumentParser() + add_common_arguments(parser) + return parser + +def parser_remote(): + parser = argparse.ArgumentParser() + common = parser.add_argument_group("Common Options") + add_common_arguments(common) + remote = parser.add_argument_group("Remote Options") + add_remote_arguments(remote) + + return parser + +def parser_b2g(): + parser = argparse.ArgumentParser() + common = parser.add_argument_group("Common Options") + add_common_arguments(common) + remote = parser.add_argument_group("Remote Options") + add_remote_arguments(remote) + b2g = parser.add_argument_group("B2G Options") + add_b2g_arguments(b2g) + + return parser From 35f8a79f6fa8973968f79d1e8c02e59c5ae4f976 Mon Sep 17 00:00:00 2001 From: James Graham Date: Tue, 1 Sep 2015 12:48:41 +0100 Subject: [PATCH 007/131] Bug 1194166 - Update unittest mozconfigs for all platforms, r=chmanchester,jlund --- .../configs/android/android_panda_releng.py | 11 +- .../mozharness/configs/android/androidarm.py | 57 +++---- .../configs/android/androidarm_4_3.py | 153 +++++++----------- .../mozharness/configs/android/androidx86.py | 36 +++-- .../configs/b2g/emulator_automation_config.py | 7 +- .../configs/unittests/linux_unittest.py | 92 +++++++---- .../configs/unittests/mac_unittest.py | 51 ++++-- .../configs/unittests/win_unittest.py | 66 +++++--- .../scripts/android_emulator_unittest.py | 9 ++ .../scripts/androidx86_emulator_unittest.py | 5 + .../scripts/b2g_desktop_unittest.py | 7 +- .../scripts/b2g_emulator_unittest.py | 8 +- .../mozharness/scripts/desktop_unittest.py | 4 +- 13 files changed, 283 insertions(+), 223 deletions(-) diff --git a/testing/mozharness/configs/android/android_panda_releng.py b/testing/mozharness/configs/android/android_panda_releng.py index 99428c5b33de..8b1e0e5a3cbd 100644 --- a/testing/mozharness/configs/android/android_panda_releng.py +++ b/testing/mozharness/configs/android/android_panda_releng.py @@ -97,8 +97,9 @@ config = { "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", "--symbols-path=%(symbols_path)s", - "reftest/tests/testing/crashtest/crashtests.list" + "--suite=crashtest", ], + "tests": ["reftest/tests/testing/crashtest/crashtests.list",], "run_filename": "remotereftest.py", "testsdir": "reftest" }, @@ -128,11 +129,12 @@ config = { "--ignore-window-size", "--bootstrap", "--extra-profile-file=jsreftest/tests/user.js", - "jsreftest/tests/jstests.list", "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", - "--symbols-path=%(symbols_path)s" + "--symbols-path=%(symbols_path)s", + "--suite=jstestbrowser", ], + "tests": ["jsreftest/tests/jstests.list",], "run_filename": "remotereftest.py", "testsdir": "reftest" }, @@ -166,8 +168,9 @@ config = { "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", "--symbols-path=%(symbols_path)s", - "reftest/tests/layout/reftests/reftest.list" + "--suite=reftest", ], + "tests": ["reftest/tests/layout/reftests/reftest.list"], "run_filename": "remotereftest.py", "testsdir": "reftest" }, diff --git a/testing/mozharness/configs/android/androidarm.py b/testing/mozharness/configs/android/androidarm.py index ad57e5d4a94c..3e3ff8fa5ecc 100644 --- a/testing/mozharness/configs/android/androidarm.py +++ b/testing/mozharness/configs/android/androidarm.py @@ -140,8 +140,9 @@ config = { "%(modules_dir)s", "--symbols-path=%(symbols_path)s", "--total-chunks=16", - "tests/layout/reftests/reftest.list", + "--suite=reftest", ], + "tests": ["tests/layout/reftests/reftest.list"], }, "crashtest": { "run_filename": "remotereftest.py", @@ -161,8 +162,9 @@ config = { "%(modules_dir)s", "--symbols-path=%(symbols_path)s", "--total-chunks=2", - "tests/testing/crashtest/crashtests.list", + "--suite=crashtest", ], + "tests": ["tests/testing/crashtest/crashtests.list"], }, "jsreftest": { "run_filename": "remotereftest.py", @@ -181,10 +183,11 @@ config = { "--httpd-path", "%(modules_dir)s", "--symbols-path=%(symbols_path)s", - "../jsreftest/tests/jstests.list", "--total-chunks=6", "--extra-profile-file=jsreftest/tests/user.js", + "--suite=jstestbrowser", ], + "tests": ["../jsreftest/tests/jstests.list"], }, "xpcshell": { "run_filename": "remotexpcshelltests.py", @@ -315,83 +318,67 @@ config = { }, "reftest-1": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=1", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=1"], }, "reftest-2": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=2", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=2"], }, "reftest-3": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=3", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=3"], }, "reftest-4": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=4", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=4"], }, "reftest-5": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=5", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=5"], }, "reftest-6": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=6", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=6"], }, "reftest-7": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=7", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=7"], }, "reftest-8": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=8", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=8"], }, "reftest-9": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=9", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=9"], }, "reftest-10": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=10", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=10"], }, "reftest-11": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=11", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=11"], }, "reftest-12": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=12", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=12"], }, "reftest-13": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=13", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=13"], }, "reftest-14": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=14", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=14"], }, "reftest-15": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=15", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=15"], }, "reftest-16": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=16", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=16", "--this-chunk=16"], }, "crashtest-1": { "category": "crashtest", diff --git a/testing/mozharness/configs/android/androidarm_4_3.py b/testing/mozharness/configs/android/androidarm_4_3.py index bb0879f1acf4..ec5261829ea1 100644 --- a/testing/mozharness/configs/android/androidarm_4_3.py +++ b/testing/mozharness/configs/android/androidarm_4_3.py @@ -138,8 +138,9 @@ config = { "--httpd-path", "%(modules_dir)s", "--symbols-path=%(symbols_path)s", "--total-chunks=16", - "tests/layout/reftests/reftest.list", + "--suite=reftest", ], + "tests": ["tests/layout/reftests/reftest.list",], }, "crashtest": { "run_filename": "remotereftest.py", @@ -158,8 +159,9 @@ config = { "%(modules_dir)s", "--symbols-path=%(symbols_path)s", "--total-chunks=2", - "tests/testing/crashtest/crashtests.list", + "--suite=crashtest", ], + "tests": ["tests/testing/crashtest/crashtests.list",], }, "jsreftest": { "run_filename": "remotereftest.py", @@ -173,10 +175,11 @@ config = { "--utility-path=%(utility_path)s", "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", "--httpd-path", "%(modules_dir)s", "--symbols-path=%(symbols_path)s", - "../jsreftest/tests/jstests.list", "--total-chunks=6", "--extra-profile-file=jsreftest/tests/user.js", + "--suite=jstestbrowser", ], + "tests": ["../jsreftest/tests/jstests.list",], }, "xpcshell": { "run_filename": "remotexpcshelltests.py", @@ -375,243 +378,195 @@ config = { }, "reftest-1": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=1", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=1"], }, "reftest-2": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=2", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=2"], }, "reftest-3": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=3", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=3"], }, "reftest-4": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=4", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=4"], }, "reftest-5": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=5", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=5"], }, "reftest-6": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=6", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=6"], }, "reftest-7": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=7", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=7"], }, "reftest-8": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=8", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=8"], }, "reftest-9": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=9", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=9"], }, "reftest-10": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=10", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=10"], }, "reftest-11": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=11", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=11"], }, "reftest-12": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=12", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=12"], }, "reftest-13": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=13", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=13"], }, "reftest-14": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=14", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=14"], }, "reftest-15": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=15", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=15"], }, "reftest-16": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=16", - "tests/layout/reftests/reftest.list"] + "extra_args": ["--total-chunks=48", "--this-chunk=16"], }, "reftest-17": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=17", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=17"], }, "reftest-18": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=18", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=18"], }, "reftest-19": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=19", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=19"], }, "reftest-20": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=20", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=20"], }, "reftest-21": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=21", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=21"], }, "reftest-22": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=22", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=22"], }, "reftest-23": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=23", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=23"], }, "reftest-24": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=24", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=24"], }, "reftest-25": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=25", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=25"], }, "reftest-26": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=26", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=26"], }, "reftest-27": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=27", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=27"], }, "reftest-28": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=28", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=28"], }, "reftest-29": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=29", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=29"], }, "reftest-30": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=30", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=30"], }, "reftest-31": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=31", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=31"], }, "reftest-32": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=32", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=32"], }, "reftest-33": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=33", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=33"], }, "reftest-34": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=34", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=34"], }, "reftest-35": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=35", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=35"], }, "reftest-36": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=36", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=36"], }, "reftest-37": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=37", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=37"], }, "reftest-38": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=38", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=38"], }, "reftest-39": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=39", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=39"], }, "reftest-40": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=40", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=40"], }, "reftest-41": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=41", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=41"], }, "reftest-42": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=42", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=42"], }, "reftest-43": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=43", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=43"], }, "reftest-44": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=44", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=44"], }, "reftest-45": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=45", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=45"], }, "reftest-46": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=46", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=46"], }, "reftest-47": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=47", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=47"], }, "reftest-48": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=48", - "tests/layout/reftests/reftest.list"] + "extra args": ["--total-chunks=48", "--this-chunk=48"], }, "crashtest-1": { "category": "crashtest", diff --git a/testing/mozharness/configs/android/androidx86.py b/testing/mozharness/configs/android/androidx86.py index 8fffd93f094b..e69fd484d9f5 100644 --- a/testing/mozharness/configs/android/androidx86.py +++ b/testing/mozharness/configs/android/androidx86.py @@ -135,8 +135,11 @@ config = { "test_suite_definitions": { "jsreftest": { "category": "reftest", - "extra_args": ["../jsreftest/tests/jstests.list", - "--extra-profile-file=jsreftest/tests/user.js"] + "tests": ["../jsreftest/tests/jstests.list"], + "extra_args": [ + "--suite=jstestbrowser", + "--extra-profile-file=jsreftest/tests/user.js" + ] }, "mochitest-1": { "category": "mochitest", @@ -152,22 +155,33 @@ config = { }, "reftest-1": { "category": "reftest", - "extra_args": ["--total-chunks=3", "--this-chunk=1", - "tests/layout/reftests/reftest.list"] + "extra_args": [ + "--suite=reftest", + "--total-chunks=3", + "--this-chunk=1", + ], + "tests": ["tests/layout/reftests/reftest.list"], }, "reftest-2": { - "category": "reftest", - "extra_args": ["--total-chunks=3", "--this-chunk=2", - "tests/layout/reftests/reftest.list"] + "extra_args": [ + "--suite=reftest", + "--total-chunks=3", + "--this-chunk=2", + ], + "tests": ["tests/layout/reftests/reftest.list"], }, "reftest-3": { - "category": "reftest", - "extra_args": ["--total-chunks=3", "--this-chunk=3", - "tests/layout/reftests/reftest.list"] + "extra_args": [ + "--suite=reftest", + "--total-chunks=3", + "--this-chunk=3", + ], + "tests": ["tests/layout/reftests/reftest.list"], }, "crashtest": { "category": "reftest", - "extra_args": ["tests/testing/crashtest/crashtests.list"] + "extra_args": ["--suite=crashtest"], + "tests": ["tests/testing/crashtest/crashtests.list"] }, "xpcshell": { "category": "xpcshell", diff --git a/testing/mozharness/configs/b2g/emulator_automation_config.py b/testing/mozharness/configs/b2g/emulator_automation_config.py index 6a2451649b27..03a39952c029 100644 --- a/testing/mozharness/configs/b2g/emulator_automation_config.py +++ b/testing/mozharness/configs/b2g/emulator_automation_config.py @@ -74,8 +74,9 @@ config = { "--busybox=%(busybox)s", "--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s", - "tests/testing/crashtest/crashtests.list" + "--suite=crashtest", ], + "tests": ["tests/testing/crashtest/crashtests.list",], "run_filename": "runreftestb2g.py", "testsdir": "reftest" }, @@ -94,8 +95,8 @@ config = { "--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s", "--extra-profile-file=jsreftest/tests/user.js", - "jsreftest/tests/jstests.list" ], + "tests": ["jsreftest/tests/jstests.list",], "run_filename": "remotereftest.py", "testsdir": "reftest" }, @@ -161,8 +162,8 @@ config = { "--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s", "--enable-oop", - "tests/layout/reftests/reftest.list" ], + "tests": ["tests/layout/reftests/reftest.list",], "run_filename": "runreftestsb2g.py", "testsdir": "reftest" }, diff --git a/testing/mozharness/configs/unittests/linux_unittest.py b/testing/mozharness/configs/unittests/linux_unittest.py index 618c934c470b..f3ffba7c9486 100644 --- a/testing/mozharness/configs/unittests/linux_unittest.py +++ b/testing/mozharness/configs/unittests/linux_unittest.py @@ -2,14 +2,14 @@ import os import platform # OS Specifics -ABS_WORK_DIR = os.path.join(os.getcwd(), 'build') +ABS_WORK_DIR = os.path.join(os.getcwd(), "build") BINARY_PATH = os.path.join(ABS_WORK_DIR, "firefox", "firefox-bin") INSTALLER_PATH = os.path.join(ABS_WORK_DIR, "installer.tar.bz2") XPCSHELL_NAME = "xpcshell" -EXE_SUFFIX = '' +EXE_SUFFIX = "" DISABLE_SCREEN_SAVER = True ADJUST_MOUSE_AND_SCREEN = False -if platform.architecture()[0] == '64bit': +if platform.architecture()[0] == "64bit": TOOLTOOL_MANIFEST_PATH = "config/tooltool-manifests/linux64/releng.manifest" MINIDUMP_STACKWALK_PATH = "linux64-minidump_stackwalk" else: @@ -20,9 +20,9 @@ else: config = { "buildbot_json_path": "buildprops.json", "exes": { - 'python': '/tools/buildbot/bin/python', - 'virtualenv': ['/tools/buildbot/bin/python', '/tools/misc-python/virtualenv.py'], - 'tooltool.py': "/tools/tooltool.py", + "python": "/tools/buildbot/bin/python", + "virtualenv": ["/tools/buildbot/bin/python", "/tools/misc-python/virtualenv.py"], + "tooltool.py": "/tools/tooltool.py", }, "find_links": [ "http://pypi.pvt.build.mozilla.org/pub", @@ -199,37 +199,63 @@ config = { }, # local reftest suites "all_reftest_suites": { - "reftest": ["tests/reftest/tests/layout/reftests/reftest.list"], - "crashtest": ["tests/reftest/tests/testing/crashtest/crashtests.list"], - "jsreftest": ["--extra-profile-file=tests/jsreftest/tests/user.js", "tests/jsreftest/tests/jstests.list"], - "reftest-ipc": {'env': {'MOZ_OMTC_ENABLED': '1', - 'MOZ_DISABLE_CONTEXT_SHARING_GLX': '1'}, - 'options': ['--setpref=browser.tabs.remote=true', - '--setpref=browser.tabs.remote.autostart=true', - '--setpref=layers.offmainthreadcomposition.testing.enabled=true', - '--setpref=layers.async-pan-zoom.enabled=true', - 'tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list']}, - "reftest-no-accel": ['--setpref=layers.acceleration.force-enabled=disabled', - 'tests/reftest/tests/layout/reftests/reftest.list'], - "crashtest-ipc": {'env': {'MOZ_OMTC_ENABLED': '1', - 'MOZ_DISABLE_CONTEXT_SHARING_GLX': '1'}, - 'options': ['--setpref=browser.tabs.remote=true', - '--setpref=browser.tabs.remote.autostart=true', - '--setpref=layers.offmainthreadcomposition.testing.enabled=true', - '--setpref=layers.async-pan-zoom.enabled=true', - 'tests/reftest/tests/testing/crashtest/crashtests.list']}, + "reftest": { + "options": ["--suite=reftest"], + "tests": ["tests/reftest/tests/layout/reftests/reftest.list"] + }, + "crashtest": { + "options": ["--suite=crashtest"], + "tests": ["tests/reftest/tests/testing/crashtest/crashtests.list"] + }, + "jsreftest": { + "options":["--extra-profile-file=tests/jsreftest/tests/user.js", + "--suite=jstestbrowser"], + "tests": ["tests/jsreftest/tests/jstests.list"] + }, + "reftest-ipc": { + "env": { + "MOZ_OMTC_ENABLED": "1", + "MOZ_DISABLE_CONTEXT_SHARING_GLX": "1" + }, + "options": ["--suite=reftest", + "--setpref=browser.tabs.remote=true", + "--setpref=browser.tabs.remote.autostart=true", + "--setpref=layers.offmainthreadcomposition.testing.enabled=true", + "--setpref=layers.async-pan-zoom.enabled=true"], + "tests": ["tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list"] + }, + "reftest-no-accel": { + "options": ["--suite=reftest", + "--setpref=layers.acceleration.force-enabled=disabled"], + "tests": ["tests/reftest/tests/layout/reftests/reftest.list"]}, + "crashtest-ipc": { + "env": { + "MOZ_OMTC_ENABLED": "1", + "MOZ_DISABLE_CONTEXT_SHARING_GLX": "1" + }, + "options": ["--suite=crashtest", + "--setpref=browser.tabs.remote=true", + "--setpref=browser.tabs.remote.autostart=true", + "--setpref=layers.offmainthreadcomposition.testing.enabled=true", + "--setpref=layers.async-pan-zoom.enabled=true"], + "tests": ["tests/reftest/tests/testing/crashtest/crashtests.list"] + }, }, "all_xpcshell_suites": { - "xpcshell": {'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, - "--manifest=tests/xpcshell/tests/all-test-dirs.list"], - 'tests': []}, - "xpcshell-addons": {'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, - "--manifest=tests/xpcshell/tests/all-test-dirs.list", - "--tag=addons"], - 'tests': []} + "xpcshell": { + "options": ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, + "--manifest=tests/xpcshell/tests/all-test-dirs.list"], + "tests": [] + }, + "xpcshell-addons": { + "options": ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, + "--tag=addons", + "--manifest=tests/xpcshell/tests/all-test-dirs.list"], + "tests": [] + }, }, "all_cppunittest_suites": { - "cppunittest": ['tests/cppunittest'] + "cppunittest": ["tests/cppunittest"] }, "all_gtest_suites": { "gtest": [] diff --git a/testing/mozharness/configs/unittests/mac_unittest.py b/testing/mozharness/configs/unittests/mac_unittest.py index 000eec5f8a49..b98bcdae465e 100644 --- a/testing/mozharness/configs/unittests/mac_unittest.py +++ b/testing/mozharness/configs/unittests/mac_unittest.py @@ -166,24 +166,45 @@ config = { }, # local reftest suites "all_reftest_suites": { - "reftest": ["tests/reftest/tests/layout/reftests/reftest.list"], - "crashtest": ["tests/reftest/tests/testing/crashtest/crashtests.list"], - "jsreftest": ["--extra-profile-file=tests/jsreftest/tests/user.js", "tests/jsreftest/tests/jstests.list"], - "reftest-ipc": ['--setpref=browser.tabs.remote=true', + "reftest": { + 'options': ["--suite=reftest"], + 'tests': ["tests/reftest/tests/layout/reftests/reftest.list"] + }, + "crashtest": { + 'options': ["--suite=crashtest"], + 'tests': ["tests/reftest/tests/testing/crashtest/crashtests.list"] + }, + "jsreftest": { + 'options':["--extra-profile-file=tests/jsreftest/tests/user.js"], + 'tests': ["tests/jsreftest/tests/jstests.list"] + }, + "reftest-ipc": { + 'options': ['--suite=reftest', + '--setpref=browser.tabs.remote=true', '--setpref=browser.tabs.remote.autostart=true', - '--setpref=layers.async-pan-zoom.enabled=true', - 'tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list'], - "crashtest-ipc": ['--setpref=browser.tabs.remote=true', - '--setpref=browser.tabs.remote.autostart=true', - '--setpref=layers.async-pan-zoom.enabled=true', - 'tests/reftest/tests/testing/crashtest/crashtests.list'], + '--setpref=layers.async-pan-zoom.enabled=true'], + 'tests': ['tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list'] + }, + "crashtest-ipc": { + 'options': ['--suite=crashtest', + '--setpref=browser.tabs.remote=true', + '--setpref=browser.tabs.remote.autostart=true', + '--setpref=layers.async-pan-zoom.enabled=true'], + 'tests': ['tests/reftest/tests/testing/crashtest/crashtests.list'] + }, }, "all_xpcshell_suites": { - "xpcshell": ["--manifest=tests/xpcshell/tests/all-test-dirs.list", - "%(abs_app_dir)s/" + XPCSHELL_NAME], - "xpcshell-addons": ["--manifest=tests/xpcshell/tests/all-test-dirs.list", - "--tag=addons", - "%(abs_app_dir)s/" + XPCSHELL_NAME] + "xpcshell": { + 'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, + "--manifest=tests/xpcshell/tests/all-test-dirs.list"], + 'tests': [] + }, + "xpcshell-addons": { + 'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, + "--tag=addons", + "--manifest=tests/xpcshell/tests/all-test-dirs.list"], + 'tests': [] + }, }, "all_cppunittest_suites": { "cppunittest": ['tests/cppunittest'] diff --git a/testing/mozharness/configs/unittests/win_unittest.py b/testing/mozharness/configs/unittests/win_unittest.py index 5ad41e844180..2908a18ffa19 100644 --- a/testing/mozharness/configs/unittests/win_unittest.py +++ b/testing/mozharness/configs/unittests/win_unittest.py @@ -176,28 +176,56 @@ config = { }, # local reftest suites "all_reftest_suites": { - "reftest": ["tests/reftest/tests/layout/reftests/reftest.list"], - "crashtest": ["tests/reftest/tests/testing/crashtest/crashtests.list"], - "jsreftest": ["--extra-profile-file=tests/jsreftest/tests/user.js", "tests/jsreftest/tests/jstests.list"], - "reftest-ipc": ['--setpref=browser.tabs.remote=true', + "reftest": { + 'options': ["--suite=reftest"], + 'tests': ["tests/reftest/tests/layout/reftests/reftest.list"] + }, + "crashtest": { + 'options': ["--suite=crashtest"], + 'tests': ["tests/reftest/tests/testing/crashtest/crashtests.list"] + }, + "jsreftest": { + 'options':["--extra-profile-file=tests/jsreftest/tests/user.js"], + 'tests': ["tests/jsreftest/tests/jstests.list"] + }, + "reftest-ipc": { + 'options': ['--suite=reftest', + '--setpref=browser.tabs.remote=true', '--setpref=browser.tabs.remote.autostart=true', - '--setpref=layers.async-pan-zoom.enabled=true', - 'tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list'], - "reftest-no-accel": ["--setpref=gfx.direct2d.disabled=true", "--setpref=layers.acceleration.disabled=true", - "tests/reftest/tests/layout/reftests/reftest.list"], - "reftest-omtc": ["--setpref=layers.offmainthreadcomposition.enabled=true", - "tests/reftest/tests/layout/reftests/reftest.list"], - "crashtest-ipc": ['--setpref=browser.tabs.remote=true', - '--setpref=browser.tabs.remote.autostart=true', - '--setpref=layers.async-pan-zoom.enabled=true', - 'tests/reftest/tests/testing/crashtest/crashtests.list'], + '--setpref=layers.async-pan-zoom.enabled=true'], + 'tests': ['tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list'] + }, + "reftest-no-accel": { + "options": ["--suite=reftest", + "--setpref=gfx.direct2d.disabled=true", + "--setpref=layers.acceleration.disabled=true"], + "tests": ["tests/reftest/tests/layout/reftests/reftest.list"] + }, + "reftest-omtc": { + "options": ["--suite=reftest", + "--setpref=layers.offmainthreadcomposition.enabled=true"], + "tests": ["tests/reftest/tests/layout/reftests/reftest.list"] + }, + "crashtest-ipc": { + "options": ["--suite=crashtest", + '--setpref=browser.tabs.remote=true', + '--setpref=browser.tabs.remote.autostart=true', + '--setpref=layers.async-pan-zoom.enabled=true'], + "tests": ['tests/reftest/tests/testing/crashtest/crashtests.list'], + }, }, "all_xpcshell_suites": { - "xpcshell": ["--manifest=tests/xpcshell/tests/all-test-dirs.list", - "%(abs_app_dir)s/" + XPCSHELL_NAME], - "xpcshell-addons": ["--manifest=tests/xpcshell/tests/all-test-dirs.list", - "--tag=addons", - "%(abs_app_dir)s/" + XPCSHELL_NAME] + "xpcshell": { + 'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, + "--manifest=tests/xpcshell/tests/all-test-dirs.list"], + 'tests': [] + }, + "xpcshell-addons": { + 'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, + "--tag=addons", + "--manifest=tests/xpcshell/tests/all-test-dirs.list"], + 'tests': [] + }, }, "all_cppunittest_suites": { "cppunittest": ['tests/cppunittest'] diff --git a/testing/mozharness/scripts/android_emulator_unittest.py b/testing/mozharness/scripts/android_emulator_unittest.py index e46a59da8c77..739e3d6f4514 100644 --- a/testing/mozharness/scripts/android_emulator_unittest.py +++ b/testing/mozharness/scripts/android_emulator_unittest.py @@ -483,6 +483,15 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin continue cmd.append(arg) + tests = None + if "tests" in self.test_suite_definitions[self.test_suite]: + tests = self.test_suite_definitions[self.test_suite]["tests"] + elif "tests" in self.config["suite_definitions"][suite_category]: + tests = self.config["suite_definitions"][suite_category]["tests"] + + if tests: + cmd.extend(tests) + return cmd def _tooltool_fetch(self, url): diff --git a/testing/mozharness/scripts/androidx86_emulator_unittest.py b/testing/mozharness/scripts/androidx86_emulator_unittest.py index 1d43de694435..c84ebb520966 100644 --- a/testing/mozharness/scripts/androidx86_emulator_unittest.py +++ b/testing/mozharness/scripts/androidx86_emulator_unittest.py @@ -452,6 +452,11 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin continue cmd.append(arg) + if "tests" in self.suite_definitions[suite_name]: + cmd.extend(self.suite_definitions[suite_name]["tests"]) + elif "tests" in self.tree_config["suite_definitions"][suite_category]: + cmd.extend(self.tree_config["suite_definitions"][suite_category]["tests"]) + return cmd def preflight_run_tests(self): diff --git a/testing/mozharness/scripts/b2g_desktop_unittest.py b/testing/mozharness/scripts/b2g_desktop_unittest.py index 24a44db03f1c..f6040a1ab837 100755 --- a/testing/mozharness/scripts/b2g_desktop_unittest.py +++ b/testing/mozharness/scripts/b2g_desktop_unittest.py @@ -154,7 +154,7 @@ class B2GDesktopTest(BlobUploadMixin, TestingMixin, MercurialScript): } if suite not in self.config["suite_definitions"]: - self.fatal("'%s' not defined in the config!" % suite), + self.fatal("'%s' not defined in the config!" % suite) options = self.config["suite_definitions"][suite]["options"] if options: @@ -162,6 +162,11 @@ class B2GDesktopTest(BlobUploadMixin, TestingMixin, MercurialScript): option = option % str_format_values if not option.endswith('None'): cmd.append(option) + + tests = self.config["suite_definitions"][suite].get("tests") + if tests: + cmd.extend(tests) + return cmd def download_and_extract(self): diff --git a/testing/mozharness/scripts/b2g_emulator_unittest.py b/testing/mozharness/scripts/b2g_emulator_unittest.py index 781551970210..9b78ddb53d47 100755 --- a/testing/mozharness/scripts/b2g_emulator_unittest.py +++ b/testing/mozharness/scripts/b2g_emulator_unittest.py @@ -281,6 +281,11 @@ class B2GEmulatorTest(TestingMixin, VCSMixin, BaseScript, BlobUploadMixin): option = option % str_format_values if not option.endswith('None'): cmd.append(option) + + tests = self.config["suite_definitions"][suite].get("tests", []) + if tests: + cmd.extend(tests) + return cmd def _query_adb(self): @@ -336,9 +341,10 @@ class B2GEmulatorTest(TestingMixin, VCSMixin, BaseScript, BlobUploadMixin): self.fatal("Don't know how to run --test-suite '%s'!" % suite) cmd = self._query_abs_base_cmd(suite) - cwd = dirs['abs_%s_dir' % suite] cmd = self.append_harness_extra_args(cmd) + cwd = dirs['abs_%s_dir' % suite] + # TODO we probably have to move some of the code in # scripts/desktop_unittest.py and scripts/marionette.py to # mozharness.mozilla.testing.unittest so we can share it. diff --git a/testing/mozharness/scripts/desktop_unittest.py b/testing/mozharness/scripts/desktop_unittest.py index f9b41c05050a..3c74b3c8ecfb 100755 --- a/testing/mozharness/scripts/desktop_unittest.py +++ b/testing/mozharness/scripts/desktop_unittest.py @@ -588,8 +588,8 @@ class DesktopUnittest(TestingMixin, MercurialScript, BlobUploadMixin, MozbaseMix options_list = [] env = {} if isinstance(suites[suite], dict): - options_list = suites[suite]['options'] - env = copy.deepcopy(suites[suite]['env']) + options_list = suites[suite]['options'] + suites[suite].get("tests", []) + env = copy.deepcopy(suites[suite].get('env', {})) else: options_list = suites[suite] From 065c095a00d4f14dc44be9e6253636c965959603 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 11 Sep 2015 12:31:59 +0100 Subject: [PATCH 008/131] Bug 1200098 - Update graphite2 library to release 1.3.2 from upstream. r=jdaggett --- gfx/graphite2/README.mozilla | 2 +- gfx/graphite2/include/graphite2/Font.h | 2 +- gfx/graphite2/include/graphite2/Segment.h | 3 +- gfx/graphite2/src/Bidi.cpp | 2 +- gfx/graphite2/src/CMakeLists.txt | 12 +-- gfx/graphite2/src/CmapCache.cpp | 14 +-- gfx/graphite2/src/Code.cpp | 85 ++++++++++----- gfx/graphite2/src/Collider.cpp | 7 +- gfx/graphite2/src/Decompressor.cpp | 121 +++++++++++----------- gfx/graphite2/src/Face.cpp | 36 +++++-- gfx/graphite2/src/FeatureMap.cpp | 7 +- gfx/graphite2/src/FileFace.cpp | 2 +- gfx/graphite2/src/GlyphCache.cpp | 21 ++-- gfx/graphite2/src/Justifier.cpp | 18 +++- gfx/graphite2/src/Pass.cpp | 99 +++++++++++------- gfx/graphite2/src/SegCache.cpp | 4 +- gfx/graphite2/src/Segment.cpp | 107 ++++++++++++++++--- gfx/graphite2/src/Silf.cpp | 60 ++++++----- gfx/graphite2/src/Slot.cpp | 36 +++---- gfx/graphite2/src/Sparse.cpp | 2 +- gfx/graphite2/src/TtfUtil.cpp | 33 ++++-- gfx/graphite2/src/call_machine.cpp | 5 +- gfx/graphite2/src/direct_machine.cpp | 4 +- gfx/graphite2/src/files.mk | 5 +- gfx/graphite2/src/gr_segment.cpp | 2 +- gfx/graphite2/src/inc/Code.h | 64 ++++-------- gfx/graphite2/src/inc/Collider.h | 49 ++++++--- gfx/graphite2/src/inc/Compression.h | 120 +++++++++++++++++++++ gfx/graphite2/src/inc/Decompressor.h | 66 +++++------- gfx/graphite2/src/inc/Face.h | 8 +- gfx/graphite2/src/inc/FeatureMap.h | 12 ++- gfx/graphite2/src/inc/GlyphCache.h | 23 ++-- gfx/graphite2/src/inc/Intervals.h | 3 + gfx/graphite2/src/inc/List.h | 1 + gfx/graphite2/src/inc/Main.h | 6 +- gfx/graphite2/src/inc/Pass.h | 11 +- gfx/graphite2/src/inc/Rule.h | 25 +++-- gfx/graphite2/src/inc/SegCache.h | 2 +- gfx/graphite2/src/inc/Segment.h | 38 ++++--- gfx/graphite2/src/inc/Silf.h | 3 +- gfx/graphite2/src/inc/Slot.h | 11 +- gfx/graphite2/src/inc/Sparse.h | 6 +- gfx/graphite2/src/inc/TtfUtil.h | 4 +- gfx/graphite2/src/inc/opcodes.h | 19 ++-- 44 files changed, 749 insertions(+), 411 deletions(-) create mode 100644 gfx/graphite2/src/inc/Compression.h diff --git a/gfx/graphite2/README.mozilla b/gfx/graphite2/README.mozilla index f41cde99c434..da3630660ff9 100644 --- a/gfx/graphite2/README.mozilla +++ b/gfx/graphite2/README.mozilla @@ -1,6 +1,6 @@ This directory contains the Graphite2 library from http://hg.palaso.org/graphitedev -Current version derived from upstream changeset e6539b6769cf +Current version derived from upstream changeset 0f9edca71849 See gfx/graphite2/moz-gr-update.sh for update procedure. diff --git a/gfx/graphite2/include/graphite2/Font.h b/gfx/graphite2/include/graphite2/Font.h index fcbfc9d682cd..ec84bf5cd642 100644 --- a/gfx/graphite2/include/graphite2/Font.h +++ b/gfx/graphite2/include/graphite2/Font.h @@ -30,7 +30,7 @@ #define GR2_VERSION_MAJOR 1 #define GR2_VERSION_MINOR 3 -#define GR2_VERSION_BUGFIX 0 +#define GR2_VERSION_BUGFIX 2 #ifdef __cplusplus extern "C" diff --git a/gfx/graphite2/include/graphite2/Segment.h b/gfx/graphite2/include/graphite2/Segment.h index afcff7492a8c..0c3c49a3acf1 100644 --- a/gfx/graphite2/include/graphite2/Segment.h +++ b/gfx/graphite2/include/graphite2/Segment.h @@ -170,7 +170,8 @@ enum gr_bidirtl { /// Underlying paragraph direction is RTL gr_rtl = 1, /// Set this to not run the bidi pass internally, even if the font asks for it. - /// This presumes that the segment is in a single direction. + /// This presumes that the segment is in a single direction. Most of the time + /// this bit should be set unless you know you are passing full paragraphs of text. gr_nobidi = 2, /// Disable auto mirroring for rtl text gr_nomirror = 4 diff --git a/gfx/graphite2/src/Bidi.cpp b/gfx/graphite2/src/Bidi.cpp index e26db2531c30..48ec2ebfcd5a 100644 --- a/gfx/graphite2/src/Bidi.cpp +++ b/gfx/graphite2/src/Bidi.cpp @@ -747,7 +747,7 @@ void resolveWhitespace(int baseLevel, Slot *s) for ( ; s; s = s->prev()) { int8 cls = s->getBidiClass(); - if (cls == WS || cls & WSflag) + if (cls == WS || (cls & WSflag)) s->setBidiLevel(baseLevel); else if (cls != BN) break; diff --git a/gfx/graphite2/src/CMakeLists.txt b/gfx/graphite2/src/CMakeLists.txt index 336dd8cc7966..9983e0197056 100644 --- a/gfx/graphite2/src/CMakeLists.txt +++ b/gfx/graphite2/src/CMakeLists.txt @@ -74,7 +74,6 @@ add_library(graphite2 SHARED gr_logging.cpp gr_segment.cpp gr_slot.cpp - Bidi.cpp CachedFace.cpp CmapCache.cpp Code.cpp @@ -107,17 +106,14 @@ set_target_properties(graphite2 PROPERTIES PUBLIC_HEADER "${GRAPHITE_HEADERS}" LT_VERSION_REVISION ${GRAPHITE_API_REVISION} LT_VERSION_AGE ${GRAPHITE_API_AGE}) -if (${CMAKE_BUILD_TYPE} STREQUAL "ClangASN") - set(GRAPHITE_LINK_FLAGS "-fsanitize=address") -else (${CMAKE_BUILD_TYPE} STREQUAL "ClangASN") - set(GRAPHITE_LINK_FLAGS "") -endif (${CMAKE_BUILD_TYPE} STREQUAL "ClangASN") - if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set_target_properties(graphite2 PROPERTIES - COMPILE_FLAGS "-Wall -Wextra -Wno-unknown-pragmas -Wendif-labels -Wshadow -Wctor-dtor-privacy -Wnon-virtual-dtor -fno-rtti -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector -Wdouble-promotion" + COMPILE_FLAGS "-Wall -Wextra -Wno-unknown-pragmas -Wendif-labels -Wshadow -Wctor-dtor-privacy -Wnon-virtual-dtor -fno-rtti -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector" LINK_FLAGS "-nodefaultlibs ${GRAPHITE_LINK_FLAGS}" LINKER_LANGUAGE C) + if (CMAKE_COMPILER_IS_GNUCXX) + add_definitions(-Wdouble-promotion) + endif (CMAKE_COMPILER_IS_GNUCXX) if (${CMAKE_CXX_COMPILER} MATCHES ".*mingw.*") target_link_libraries(graphite2 kernel32 msvcr90 mingw32 gcc user32) else (${CMAKE_CXX_COMPILER} MATCHES ".*mingw.*") diff --git a/gfx/graphite2/src/CmapCache.cpp b/gfx/graphite2/src/CmapCache.cpp index a184e97095c7..a945ef234436 100644 --- a/gfx/graphite2/src/CmapCache.cpp +++ b/gfx/graphite2/src/CmapCache.cpp @@ -38,11 +38,11 @@ const void * bmp_subtable(const Face::Table & cmap) { const void * stbl; if (!cmap.size()) return 0; - if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size())) - || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size())) - || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size())) - || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size())) - || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()))) + if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()), cmap.size()) + || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()), cmap.size()) + || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()), cmap.size()) + || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()), cmap.size()) + || TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()), cmap.size())) return stbl; return 0; } @@ -51,8 +51,8 @@ const void * smp_subtable(const Face::Table & cmap) { const void * stbl; if (!cmap.size()) return 0; - if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size())) - || TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()))) + if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()), cmap.size()) + || TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()), cmap.size())) return stbl; return 0; } diff --git a/gfx/graphite2/src/Code.cpp b/gfx/graphite2/src/Code.cpp index ed32b724c2ea..0e4960f3a592 100644 --- a/gfx/graphite2/src/Code.cpp +++ b/gfx/graphite2/src/Code.cpp @@ -77,7 +77,6 @@ struct context } // end namespace -byte * Machine::Code::local_memory = 0; class Machine::Code::decoder { @@ -90,7 +89,8 @@ public: byte max_ref; analysis() : slotref(0), max_ref(0) {}; - void set_ref(int index) throw(); + void set_ref(int index, bool incinsert=false) throw(); + void set_noref(int index) throw(); void set_changed(int index) throw(); }; @@ -146,7 +146,7 @@ inline Machine::Code::decoder::decoder(limits & lims, Code &code, enum passtype Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end, uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face, - enum passtype pt, byte * & _out) + enum passtype pt, byte * * const _out) : _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), _status(loaded), _constraint(is_constraint), _modify(false), _delete(false), _own(_out==0) { @@ -162,11 +162,10 @@ Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte assert(bytecode_end > bytecode_begin); const opcode_t * op_to_fn = Machine::getOpcodeTable(); - // Allocate code and dat target buffers, these sizes are a worst case + // Allocate code and data target buffers, these sizes are a worst case // estimate. Once we know their real sizes the we'll shrink them. - if (_out) _code = reinterpret_cast(_out); - else _code = static_cast(malloc((bytecode_end - bytecode_begin) - * (sizeof(instr)+sizeof(byte)))); + if (_out) _code = reinterpret_cast(*_out); + else _code = static_cast(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin))); _data = reinterpret_cast(_code + (bytecode_end - bytecode_begin)); if (!_code || !_data) { @@ -220,7 +219,7 @@ Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte memmove(_code + (_instr_count+1), _data, _data_size*sizeof(byte)); size_t const total_sz = ((_instr_count+1) + (_data_size + sizeof(instr)-1)/sizeof(instr))*sizeof(instr); if (_out) - _out += total_sz; + *_out += total_sz; else _code = static_cast(realloc(_code, total_sz)); _data = reinterpret_cast(_code + (_instr_count+1)); @@ -418,9 +417,11 @@ opcode Machine::Code::decoder::fetch_opcode(const byte * bc) break; case PUSH_IGLYPH_ATTR :// not implemented ++_stack_depth; + break; case POP_RET : if (--_stack_depth < 0) failure(underfull_stack); + // no break case RET_ZERO : case RET_TRUE : break; @@ -477,14 +478,23 @@ void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8 * arg) case PUT_GLYPH_8BIT_OBS : case PUT_GLYPH : _code._modify = true; - _analysis.set_changed(_analysis.slotref); + _analysis.set_changed(0); + break; + case ATTR_SET : + case ATTR_ADD : + case ATTR_SET_SLOT : + case IATTR_SET_SLOT : + case IATTR_SET : + case IATTR_ADD : + case IATTR_SUB : + _analysis.set_noref(0); break; case NEXT : case COPY_NEXT : if (!_analysis.contexts[_analysis.slotref].flags.inserted) ++_analysis.slotref; _analysis.contexts[_analysis.slotref] = context(_code._instr_count+1); - if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref; + // if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref; break; case INSERT : _analysis.contexts[_analysis.slotref].flags.inserted = true; @@ -493,14 +503,15 @@ void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8 * arg) case PUT_SUBS_8BIT_OBS : // slotref on 1st parameter case PUT_SUBS : _code._modify = true; - _analysis.set_changed(_analysis.slotref); + _analysis.set_changed(0); // no break case PUT_COPY : { - if (arg[0] != 0) { _analysis.set_changed(_analysis.slotref); _code._modify = true; } + if (arg[0] != 0) { _analysis.set_changed(0); _code._modify = true; } if (arg[0] <= 0 && -arg[0] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted) - _analysis.set_ref(_analysis.slotref + arg[0] - _analysis.contexts[_analysis.slotref].flags.inserted); - else if (_analysis.slotref + arg[0] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[0]; + _analysis.set_ref(arg[0], true); + else if (arg[0] > 0) + _analysis.set_ref(arg[0], true); break; } case PUSH_ATT_TO_GATTR_OBS : // slotref on 2nd parameter @@ -513,16 +524,18 @@ void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8 * arg) case PUSH_ISLOT_ATTR : case PUSH_FEAT : if (arg[1] <= 0 && -arg[1] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted) - _analysis.set_ref(_analysis.slotref + arg[1] - _analysis.contexts[_analysis.slotref].flags.inserted); - else if (_analysis.slotref + arg[1] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[1]; + _analysis.set_ref(arg[1], true); + else if (arg[1] > 0) + _analysis.set_ref(arg[1], true); break; case PUSH_ATT_TO_GLYPH_ATTR : if (_code._constraint) return; // no break case PUSH_GLYPH_ATTR : if (arg[2] <= 0 && -arg[2] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted) - _analysis.set_ref(_analysis.slotref + arg[2] - _analysis.contexts[_analysis.slotref].flags.inserted); - else if (_analysis.slotref + arg[2] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[2]; + _analysis.set_ref(arg[2], true); + else if (arg[2] > 0) + _analysis.set_ref(arg[2], true); break; case ASSOC : // slotrefs in varargs break; @@ -604,6 +617,7 @@ void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end *tip = temp_copy; ++code_end; ++tempcount; + _code._delete = true; } _code._instr_count = code_end - code; @@ -619,8 +633,13 @@ bool Machine::Code::decoder::validate_opcode(const opcode opc, const byte * cons return false; } const opcode_t & op = Machine::getOpcodeTable()[opc]; + if (op.param_sz == VARARGS && bc >= _max.bytecode) + { + failure(arguments_exhausted); + return false; + } const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz; - if (bc - 1 + param_sz > _max.bytecode) + if (bc - 1 + param_sz >= _max.bytecode) { failure(arguments_exhausted); return false; @@ -654,16 +673,28 @@ void Machine::Code::failure(const status_t s) throw() { inline -void Machine::Code::decoder::analysis::set_ref(const int index) throw() { - contexts[index].flags.referenced = true; - if (index > max_ref) max_ref = index; +void Machine::Code::decoder::analysis::set_ref(int index, bool incinsert) throw() { + if (incinsert && contexts[slotref].flags.inserted) --index; + if (index + slotref < 0) return; + contexts[index + slotref].flags.referenced = true; + if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref; } inline -void Machine::Code::decoder::analysis::set_changed(const int index) throw() { - contexts[index].flags.changed = true; - if (index > max_ref) max_ref = index; +void Machine::Code::decoder::analysis::set_noref(int index) throw() { + if (contexts[slotref].flags.inserted) --index; + if (index + slotref < 0) return; + if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref; +} + + +inline +void Machine::Code::decoder::analysis::set_changed(int index) throw() { + if (contexts[slotref].flags.inserted) --index; + if (index + slotref < 0) return; + contexts[index + slotref].flags.changed = true; + if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref; } @@ -682,10 +713,12 @@ int32 Machine::Code::run(Machine & m, slotref * & map) const // assert(_own); assert(*this); // Check we are actually runnable - if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context())) + if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context()) + || m.slotMap()[_max_ref + m.slotMap().context()] == 0) { m._status = Machine::slot_offset_out_bounds; return 1; +// return m.run(_code, _data, map); } return m.run(_code, _data, map); diff --git a/gfx/graphite2/src/Collider.cpp b/gfx/graphite2/src/Collider.cpp index b17b9b42f0af..fa8ed0d40a66 100644 --- a/gfx/graphite2/src/Collider.cpp +++ b/gfx/graphite2/src/Collider.cpp @@ -39,7 +39,7 @@ of the License or (at your option) any later version. // Possible rounding error for subbox boundaries: 0.016 = 1/64 = 1/256 * 4 // (values in font range from 0..256) -#define SUBBOX_RND_ERR 0.016 +// #define SUBBOX_RND_ERR 0.016 using namespace graphite2; @@ -543,7 +543,7 @@ bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShif } } bool res = true; - if (cslot && cslot->exclGlyph() > 0 && gc.check(cslot->exclGlyph()) && !isExclusion) + if (cslot->exclGlyph() > 0 && gc.check(cslot->exclGlyph()) && !isExclusion) { // Set up the bogus slot representing the exclusion glyph. Slot *exclSlot = seg->newSlot(); @@ -925,6 +925,8 @@ bool KernCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float bool KernCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, GR_MAYBE_UNUSED json * const dbgout) { int rtl = (dir & 1) * 2 - 1; + if (!seg->getFace()->glyphs().check(slot->gid())) + return false; const Rect &bb = seg->theGlyphBBoxTemporary(slot->gid()); const float sx = slot->origin().x + currShift.x; float x = sx + (rtl > 0 ? bb.tr.x : bb.bl.x); @@ -971,7 +973,6 @@ bool KernCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift // Return the amount to kern by. -// TODO: do we need to make use of marginMin here? Probably not. Position KernCollider::resolve(GR_MAYBE_UNUSED Segment *seg, GR_MAYBE_UNUSED Slot *slot, int dir, float margin, GR_MAYBE_UNUSED json * const dbgout) { diff --git a/gfx/graphite2/src/Decompressor.cpp b/gfx/graphite2/src/Decompressor.cpp index 919678a640b5..ec5dfcdc26f9 100644 --- a/gfx/graphite2/src/Decompressor.cpp +++ b/gfx/graphite2/src/Decompressor.cpp @@ -1,75 +1,75 @@ -/* Copyright (c) 2012, Siyuan Fu - Copyright (c) 2015, SIL International +/* GRAPHITE2 LICENSING + + Copyright 2015, SIL International All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should also have received a copy of the GNU Lesser General Public + License along with this library in the file named "LICENSE". + If not, write to the Free Software Foundation, 51 Franklin Street, + Suite 500, Boston, MA 02110-1335, USA or visit their web page on the + internet at http://www.fsf.org/licenses/lgpl.html. + +Alternatively, the contents of this file may be used under the terms of the +Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public +License, as published by the Free Software Foundation, either version 2 +of the License or (at your option) any later version. */ #include #include "inc/Decompressor.h" -#include "inc/Shrinker.h" +#include "inc/Compression.h" -using namespace shrinker; +using namespace lz4; namespace { -u8 const LONG_DIST = 0x10; -u8 const MATCH_LEN = 0x0f; - -template inline u32 read_literal(u8 const * &s, u8 const * const e, u32 l) { - if (unlikely(l == M)) + if (unlikely(l == 15) && likely(s != e)) { - u8 b = 0; + u8 b = 0; do { l += b = *s++; } while(b==0xff && s != e); } return l; } -bool read_directive(u8 const * &src, u8 const * const end, u32 & literal_len, u32 & match_len, u32 & match_dist) +bool read_sequence(u8 const * &src, u8 const * const end, u8 const * &literal, u32 & literal_len, u32 & match_len, u32 & match_dist) { - u8 const flag = *src++; + u8 const token = *src++; - literal_len = read_literal<7>(src, end, flag >> 5); - match_len = read_literal<15>(src, end, flag & MATCH_LEN); + literal_len = read_literal(src, end, token >> 4); + literal = src; + src += literal_len; - match_dist = *src++; - if (flag & LONG_DIST) - match_dist |= ((*src++) << 8); + if (unlikely(src > end - 2)) + return false; - return match_dist != 0xffff; + match_dist = *src++; + match_dist |= *src++ << 8; + match_len = read_literal(src, end, token & 0xf); + + return true; } } -int shrinker::decompress(void const *in, size_t in_size, void *out, size_t out_size) +int lz4::decompress(void const *in, size_t in_size, void *out, size_t out_size) { + if (out_size <= in_size) + return -1; + u8 const * src = static_cast(in), + * literal = 0, * const src_end = src + in_size; u8 * dst = static_cast(out), @@ -78,24 +78,29 @@ int shrinker::decompress(void const *in, size_t in_size, void *out, size_t out_s u32 literal_len = 0, match_len = 0, match_dist = 0; - - while (read_directive(src, src_end, literal_len, match_len, match_dist)) + + while (read_sequence(src, src_end, literal, literal_len, match_len, match_dist)) { - // Copy in literal - if (unlikely(dst + literal_len + sizeof(unsigned long) > dst_end)) return -1; - dst = memcpy_nooverlap(dst, src, literal_len); - src += literal_len; - + // Copy in literal. At this point the last full sequence must be at + // least MINMATCH + 5 from the end of the output buffer. + if (unlikely(literal + align(literal_len) > src_end + || dst + align(literal_len) > dst_end - MINMATCH+5)) + return -1; + dst = overrun_copy(dst, literal, literal_len); + // Copy, possibly repeating, match from earlier in the // decoded output. - u8 const * const pcpy = dst - match_dist - 1; - if (unlikely(pcpy < static_cast(out) - || dst + match_len + MINMATCH + sizeof(unsigned long) > dst_end)) return -1; - dst = memcpy_(dst, pcpy, match_len + MINMATCH); + u8 const * const pcpy = dst - match_dist; + if (unlikely(pcpy < static_cast(out) + || dst + align(match_len + MINMATCH) > dst_end)) + return -1; + dst = copy(dst, pcpy, match_len + MINMATCH); } - if (unlikely(dst + literal_len > dst_end)) return -1; - dst = memcpy_nooverlap_surpass(dst, src, literal_len); + if (unlikely(literal + literal_len > src_end + || dst + literal_len > dst_end)) + return -1; + dst = fast_copy(dst, literal, literal_len); return dst - (u8*)out; } diff --git a/gfx/graphite2/src/Face.cpp b/gfx/graphite2/src/Face.cpp index 25e1b7130954..e10f09b248f9 100644 --- a/gfx/graphite2/src/Face.cpp +++ b/gfx/graphite2/src/Face.cpp @@ -46,7 +46,7 @@ namespace enum compression { NONE, - SHRINKER + LZ4 }; } @@ -125,7 +125,7 @@ bool Face::readGraphite(const Table & silf) Error e; error_context(EC_READSILF); const byte * p = silf; - if (e.test(!p, E_NOSILF)) return error(e); + if (e.test(!p, E_NOSILF) || e.test(silf.size() < 20, E_BADSIZE)) return error(e); const uint32 version = be::read(p); if (e.test(version < 0x00020000, E_TOOOLD)) return error(e); @@ -173,6 +173,10 @@ bool Face::runGraphite(Segment *seg, const Silf *aSilf) const } #endif +// if ((seg->dir() & 1) != aSilf->dir()) +// seg->reverseSlots(); + if ((seg->dir() & 3) == 3 && aSilf->bidiPass() == 0xFF) + seg->doMirror(aSilf->aMirror()); bool res = aSilf->runGraphite(seg, 0, aSilf->positionPass(), true); if (res) { @@ -185,6 +189,7 @@ bool Face::runGraphite(Segment *seg, const Silf *aSilf) const #if !defined GRAPHITE2_NTRACING if (dbgout) { + seg->positionSlots(0, 0, 0, aSilf->dir()); *dbgout << json::item << json::close // Close up the passes array << "output" << json::array; @@ -233,7 +238,9 @@ uint16 Face::getGlyphMetric(uint16 gid, uint8 metric) const { case kgmetAscent : return m_ascent; case kgmetDescent : return m_descent; - default: return glyphs().glyph(gid)->getMetric(metric); + default: + if (gid > glyphs().numGlyphs()) return 0; + return glyphs().glyph(gid)->getMetric(metric); } } @@ -277,7 +284,6 @@ Face::Table::Table(const Face & face, const Tag n, uint32 version) throw() if (!TtfUtil::CheckTable(n, _p, _sz)) { this->~Table(); // Make sure we release the table buffer even if the table filed it's checks - _p = 0; _sz = 0; return; } @@ -285,6 +291,15 @@ Face::Table::Table(const Face & face, const Tag n, uint32 version) throw() decompress(); } +void Face::Table::releaseBuffers() +{ + if (_compressed) + free(const_cast(_p)); + else if (_p && _f->m_ops.release_table) + (*_f->m_ops.release_table)(_f->m_appFaceHandle, _p); + _p = 0; _sz = 0; +} + Face::Table & Face::Table::operator = (const Table & rhs) throw() { if (_p == rhs._p) return *this; @@ -297,6 +312,8 @@ Face::Table & Face::Table::operator = (const Table & rhs) throw() Error Face::Table::decompress() { Error e; + if (e.test(_sz < 2 * sizeof(uint32) + 3, E_BADSIZE)) + return e; byte * uncompressed_table = 0; size_t uncompressed_size = 0; @@ -308,25 +325,30 @@ Error Face::Table::decompress() switch(compression(hdr >> 27)) { case NONE: return e; - case SHRINKER: + + case LZ4: { uncompressed_size = hdr & 0x07ffffff; uncompressed_table = gralloc(uncompressed_size); + //TODO: Coverty: 1315803: FORWARD_NULL if (!e.test(!uncompressed_table, E_OUTOFMEM)) - e.test(shrinker::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED); + //TODO: Coverty: 1315800: CHECKED_RETURN + e.test(lz4::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED); break; } + default: e.error(E_BADSCHEME); }; // Check the uncompressed version number against the original. if (!e) + //TODO: Coverty: 1315800: CHECKED_RETURN e.test(be::peek(uncompressed_table) != version, E_SHRINKERFAILED); // Tell the provider to release the compressed form since were replacing // it anyway. - this->~Table(); + releaseBuffers(); if (e) { diff --git a/gfx/graphite2/src/FeatureMap.cpp b/gfx/graphite2/src/FeatureMap.cpp index 199ff700cf4c..b8c8405276a2 100644 --- a/gfx/graphite2/src/FeatureMap.cpp +++ b/gfx/graphite2/src/FeatureMap.cpp @@ -131,11 +131,12 @@ bool FeatureMap::readFeats(const Face & face) const uint16 num_settings = be::read(p); if (version >= 0x00020000) be::skip(p); - const byte * const feat_setts = feat_start + be::read(p); + const uint32 settings_offset = be::read(p); const uint16 flags = be::read(p), uiName = be::read(p); - if (feat_setts + num_settings * FEATURE_SETTING_SIZE > feat_end) + if (settings_offset > size_t(feat_end - feat_start) + || settings_offset + num_settings * FEATURE_SETTING_SIZE > size_t(feat_end - feat_start)) { free(defVals); return false; @@ -151,7 +152,7 @@ bool FeatureMap::readFeats(const Face & face) free(defVals); return false; } - maxVal = readFeatureSettings(feat_setts, uiSet, num_settings); + maxVal = readFeatureSettings(feat_start + settings_offset, uiSet, num_settings); defVals[i] = uiSet[0].value(); } else diff --git a/gfx/graphite2/src/FileFace.cpp b/gfx/graphite2/src/FileFace.cpp index 3df67354b1bf..43aff71a719e 100644 --- a/gfx/graphite2/src/FileFace.cpp +++ b/gfx/graphite2/src/FileFace.cpp @@ -83,7 +83,7 @@ const void *FileFace::get_table_fn(const void* appFaceHandle, unsigned int name, if (!TtfUtil::GetTableInfo(name, file_face._header_tbl, file_face._table_dir, tbl_offset, tbl_len)) return 0; - if (tbl_offset + tbl_len > file_face._file_len + if (tbl_offset > file_face._file_len || tbl_len > file_face._file_len - tbl_offset || fseek(file_face._file, tbl_offset, SEEK_SET) != 0) return 0; diff --git a/gfx/graphite2/src/GlyphCache.cpp b/gfx/graphite2/src/GlyphCache.cpp index 59f418a2d80d..d1e2b48fbd70 100644 --- a/gfx/graphite2/src/GlyphCache.cpp +++ b/gfx/graphite2/src/GlyphCache.cpp @@ -62,7 +62,7 @@ namespace // This is strictly a >= operator. A true == operator could be // implemented that test for overlap but it would be more expensive a // test. - bool operator == (const _glat_iterator & rhs) { return _v >= rhs._e; } + bool operator == (const _glat_iterator & rhs) { return _v >= rhs._e - 1; } bool operator != (const _glat_iterator & rhs) { return !operator==(rhs); } value_type operator * () const { @@ -78,7 +78,8 @@ namespace typedef _glat_iterator glat2_iterator; } -const Rect GlyphCache::nullRect = Rect(); +const SlantBox SlantBox::empty = {0,0,0,0}; + class GlyphCache::Loader { @@ -145,7 +146,7 @@ GlyphCache::GlyphCache(const Face & face, const uint32 face_options) } else if (numsubs > 0) { - GlyphBox * boxes = (GlyphBox *)gralloc(_num_glyphs * sizeof(GlyphBox) + (numsubs-1) * 8 * sizeof(float)); + GlyphBox * boxes = (GlyphBox *)gralloc(_num_glyphs * sizeof(GlyphBox) + numsubs * 8 * sizeof(float)); GlyphBox * currbox = boxes; for (uint16 gid = 0; currbox && gid != _num_glyphs; ++gid) @@ -277,19 +278,20 @@ GlyphCache::Loader::Loader(const Face & face, const bool dumb_font) // subtracting the length of the attribids array (numAttribs long if present) // and dividing by either 2 or 4 depending on shor or lonf format _long_fmt = flags & 1; - _num_glyphs_attributes = (m_pGloc.size() + int tmpnumgattrs = (m_pGloc.size() - (p - m_pGloc) - sizeof(uint16)*(flags & 0x2 ? _num_attrs : 0)) / (_long_fmt ? sizeof(uint32) : sizeof(uint16)) - 1; - if (version >= 0x00020000 + if (version >= 0x00020000 || tmpnumgattrs < 0 || tmpnumgattrs > 65535 || _num_attrs == 0 || _num_attrs > 0x3000 // is this hard limit appropriate? - || _num_glyphs_graphics > _num_glyphs_attributes) + || _num_glyphs_graphics > tmpnumgattrs) { _head = Face::Table(); return; } + _num_glyphs_attributes = static_cast(tmpnumgattrs); p = m_pGlat; version = be::read(p); if (version >= 0x00040000) // reject Glat tables that are too new @@ -347,8 +349,12 @@ const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFa void *pGlyph = TtfUtil::GlyfLookup(_glyf, locidx, _glyf.size()); if (pGlyph && TtfUtil::GlyfBox(pGlyph, xMin, yMin, xMax, yMax)) + { + if ((xMin > xMax) || (yMin > yMax)) + return 0; bbox = Rect(Position(static_cast(xMin), static_cast(yMin)), Position(static_cast(xMax), static_cast(yMax))); + } } if (TtfUtil::HorMetrics(glyphid, _hmtx, _hmtx.size(), _hhea, nLsb, nAdvWid)) advance = Position(static_cast(nAdvWid), 0); @@ -398,7 +404,8 @@ const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFa else { if (gloce - glocs < 3*sizeof(uint16) // can a glyph have no attributes? why not? - || gloce - glocs > _num_attrs*3*sizeof(uint16)) + || gloce - glocs > _num_attrs*3*sizeof(uint16) + || glocs > m_pGlat.size() - 2*sizeof(uint16)) return 0; new (&glyph) GlyphFace(bbox, advance, glat2_iterator(m_pGlat + glocs), glat2_iterator(m_pGlat + gloce)); } diff --git a/gfx/graphite2/src/Justifier.cpp b/gfx/graphite2/src/Justifier.cpp index 9f95033255c5..e75d7508f0d6 100644 --- a/gfx/graphite2/src/Justifier.cpp +++ b/gfx/graphite2/src/Justifier.cpp @@ -31,7 +31,7 @@ of the License or (at your option) any later version. #include "inc/CharInfo.h" #include "inc/Slot.h" #include "inc/Main.h" -#include +#include using namespace graphite2; @@ -70,6 +70,13 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS if (width < 0 && !(silf()->flags())) return width; + if ((m_dir & 1) != m_silf->dir() && m_silf->bidiPass() != m_silf->numPasses()) + { + reverseSlots(); + s = pFirst; + pFirst = pLast; + pLast = s; + } if (!pFirst) pFirst = pSlot; while (!pFirst->isBase()) pFirst = pFirst->attachedTo(); if (!pLast) pLast = last(); @@ -170,7 +177,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS } } currWidth += diff - error; - } while (i == 0 && int(abs(error)) > 0 && tWeight); + } while (i == 0 && int(std::abs(error)) > 0 && tWeight); } Slot *oldFirst = m_first; @@ -203,7 +210,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS if (dbgout) { *dbgout << json::item << json::close; // Close up the passes array - positionSlots(NULL, pSlot, pLast); + positionSlots(NULL, pSlot, pLast, m_dir); Slot *lEnd = pLast->nextSibling(); *dbgout << "output" << json::array; for(Slot * t = pSlot; t != lEnd; t = t->next()) @@ -212,7 +219,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS } #endif - res = positionSlots(font, pSlot, pLast); + res = positionSlots(font, pSlot, pLast, m_dir); if (silf()->flags() & 1) { @@ -221,6 +228,9 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS } m_first = oldFirst; m_last = oldLast; + + if ((m_dir & 1) != m_silf->dir() && m_silf->bidiPass() != m_silf->numPasses()) + reverseSlots(); return res.x; } diff --git a/gfx/graphite2/src/Pass.cpp b/gfx/graphite2/src/Pass.cpp index fde290b14fdd..c1764b350b90 100644 --- a/gfx/graphite2/src/Pass.cpp +++ b/gfx/graphite2/src/Pass.cpp @@ -42,6 +42,13 @@ using namespace graphite2; using vm::Machine; typedef Machine::Code Code; +enum KernCollison +{ + None = 0, + CrossSpace = 1, + InWord = 2, + reserved = 3 +}; Pass::Pass() : m_silf(0), @@ -53,16 +60,20 @@ Pass::Pass() m_states(0), m_codes(0), m_progs(0), - m_flags(0), + m_numCollRuns(0), + m_kernColls(0), m_iMaxLoop(0), m_numGlyphs(0), m_numRules(0), m_numStates(0), m_numTransition(0), m_numSuccess(0), + m_successStart(0), m_numColumns(0), m_minPreCtxt(0), - m_maxPreCtxt(0) + m_maxPreCtxt(0), + m_colThreshold(0), + m_isReverseDir(false) { } @@ -88,13 +99,17 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su if (e.test(pass_length < 40, E_BADPASSLENGTH)) return face.error(e); // Read in basic values - m_flags = be::read(p); - if (e.test((m_flags & 15) && pt < PASS_TYPE_POSITIONING, E_BADCOLLISIONPASS)) + const byte flags = be::read(p); + if (e.test((flags & 0x1f) && pt < PASS_TYPE_POSITIONING, E_BADCOLLISIONPASS)) return face.error(e); + m_numCollRuns = flags & 0x7; + m_kernColls = (flags >> 3) & 0x3; + m_isReverseDir = (flags >> 5) & 0x1; m_iMaxLoop = be::read(p); + if (m_iMaxLoop < 1) m_iMaxLoop = 1; be::skip(p,2); // skip maxContext & maxBackup m_numRules = be::read(p); - if (e.test(!m_numRules && !(m_flags & 7), E_BADEMPTYPASS)) return face.error(e); + if (e.test(!m_numRules && m_numCollRuns == 0, E_BADEMPTYPASS)) return face.error(e); be::skip(p); // fsmOffset - not sure why we would want this const byte * const pcCode = pass_start + be::read(p) - subtable_base, * const rcCode = pass_start + be::read(p) - subtable_base, @@ -152,7 +167,7 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su const uint16 * const o_actions = reinterpret_cast(p); be::skip(p, m_numRules + 1); const byte * const states = p; - if (e.test(p + 2 * m_numTransition*m_numColumns >= pass_end, E_BADPASSLENGTH)) return face.error(e); + if (e.test(p + 2u*m_numTransition*m_numColumns >= pass_end, E_BADPASSLENGTH)) return face.error(e); be::skip(p, m_numTransition*m_numColumns); be::skip(p); if (e.test(p != pcCode, E_BADPASSCCODEPTR)) return face.error(e); @@ -212,9 +227,10 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries, // Allocate pools m_rules = new Rule [m_numRules]; m_codes = new Code [m_numRules*2]; - m_progs = static_cast(malloc((ac_end - ac_data + rc_end - rc_data) - *(sizeof(vm::instr)+sizeof(byte)))); - byte * prog_pool_free = m_progs; + const size_t prog_pool_sz = vm::Machine::Code::estimateCodeDataOut(ac_end - ac_data + rc_end - rc_data); + m_progs = gralloc(prog_pool_sz); + byte * prog_pool_free = m_progs, + * prog_pool_end = m_progs + prog_pool_sz; if (e.test(!(m_rules && m_codes && m_progs), E_OUTOFMEM)) return face.error(e); Rule * r = m_rules + m_numRules - 1; @@ -233,10 +249,11 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries, rc_begin = be::peek(o_constraint) ? rc_data + be::peek(o_constraint) : rc_end; if (ac_begin > ac_end || ac_begin > ac_data_end || ac_end > ac_data_end - || rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end) + || rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end + || vm::Machine::Code::estimateCodeDataOut(ac_end - ac_begin + rc_end - rc_begin) > size_t(prog_pool_end - prog_pool_free)) return false; - r->action = new (m_codes+n*2-2) vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face, pt, prog_pool_free); - r->constraint = new (m_codes+n*2-1) vm::Machine::Code(true, rc_begin, rc_end, r->preContext, r->sort, *m_silf, face, pt, prog_pool_free); + r->action = new (m_codes+n*2-2) vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face, pt, &prog_pool_free); + r->constraint = new (m_codes+n*2-1) vm::Machine::Code(true, rc_begin, rc_end, r->preContext, r->sort, *m_silf, face, pt, &prog_pool_free); if (e.test(!r->action || !r->constraint, E_OUTOFMEM) || e.test(r->action->status() != Code::loaded, r->action->status() + E_CODEFAILURE) @@ -245,19 +262,21 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries, return face.error(e); } - // Shrink the program pool - ptrdiff_t const delta = static_cast(realloc(m_progs, prog_pool_free - m_progs)) - m_progs; - if (delta) + byte * moved_progs = static_cast(realloc(m_progs, prog_pool_free - m_progs)); + if (e.test(!moved_progs, E_OUTOFMEM)) return face.error(e); + + if (moved_progs != m_progs) { - m_progs += delta; for (Code * c = m_codes, * const ce = c + m_numRules*2; c != ce; ++c) { - c->externalProgramMoved(delta); + c->externalProgramMoved(moved_progs - m_progs); } + m_progs = moved_progs; } // Load the rule entries map face.error_context((face.error_context() & 0xFFFF00) + EC_APASS); + //TODO: Coverty: 1315804: FORWARD_NULL RuleEntry * re = m_ruleMap = gralloc(num_entries); if (e.test(!re, E_OUTOFMEM)) return face.error(e); for (size_t n = num_entries; n; --n, ++re) @@ -360,10 +379,11 @@ bool Pass::readRanges(const byte * ranges, size_t num_ranges, Error &e) } -bool Pass::runGraphite(vm::Machine & m, FiniteStateMachine & fsm) const +bool Pass::runGraphite(vm::Machine & m, FiniteStateMachine & fsm, bool reverse) const { Slot *s = m.slotMap().segment.first(); if (!s || !testPassConstraint(m)) return true; + if (reverse) m.slotMap().segment.reverseSlots(); if (m_numRules) { Slot *currHigh = s->next(); @@ -387,23 +407,25 @@ bool Pass::runGraphite(vm::Machine & m, FiniteStateMachine & fsm) const } } while (s); } + //TODO: Use enums for flags + const bool collisions = m_numCollRuns || m_kernColls; - if (!(m_flags & 15) || !m.slotMap().segment.hasCollisionInfo()) + if (!collisions || !m.slotMap().segment.hasCollisionInfo()) return true; - if (m_flags & 7) + if (m_numCollRuns) { if (!(m.slotMap().segment.flags() & Segment::SEG_INITCOLLISIONS)) { - m.slotMap().segment.positionSlots(0, 0, 0, true); + m.slotMap().segment.positionSlots(0, 0, 0, m.slotMap().dir(), true); // m.slotMap().segment.flags(m.slotMap().segment.flags() | Segment::SEG_INITCOLLISIONS); } - if (!collisionShift(&m.slotMap().segment, m.slotMap().segment.dir(), fsm.dbgout)) + if (!collisionShift(&m.slotMap().segment, m.slotMap().dir(), fsm.dbgout)) return false; } - if ((m_flags & 24) && !collisionKern(&m.slotMap().segment, m.slotMap().segment.dir(), fsm.dbgout)) + if ((m_kernColls) && !collisionKern(&m.slotMap().segment, m.slotMap().dir(), fsm.dbgout)) return false; - if ((m_flags & 15) && !collisionFinish(&m.slotMap().segment, fsm.dbgout)) + if (collisions && !collisionFinish(&m.slotMap().segment, fsm.dbgout)) return false; return true; } @@ -478,8 +500,8 @@ void Pass::findNDoRule(Slot * & slot, Machine &m, FiniteStateMachine & fsm) cons if (r != re) { const int adv = doAction(r->rule->action, slot, m); - dumpRuleEventOutput(fsm, *r->rule, slot); - if (r->rule->action->deletes()) fsm.slots.collectGarbage(); + dumpRuleEventOutput(fsm, m, *r->rule, slot); + if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot); adjustSlot(adv, slot, fsm.slots); *fsm.dbgout << "cursor" << objectid(dslot(&fsm.slots.segment, slot)) << json::close; // Close RuelEvent object @@ -501,7 +523,7 @@ void Pass::findNDoRule(Slot * & slot, Machine &m, FiniteStateMachine & fsm) cons if (r != re) { const int adv = doAction(r->rule->action, slot, m); - if (r->rule->action->deletes()) fsm.slots.collectGarbage(); + if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot); adjustSlot(adv, slot, fsm.slots); return; } @@ -533,7 +555,7 @@ void Pass::dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEnt } -void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * const last_slot) const +void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, Machine & m, const Rule & r, Slot * const last_slot) const { *fsm.dbgout << json::item << json::flat << json::object << "id" << &r - m_rules @@ -551,7 +573,7 @@ void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, S << json::close // close "input" << "slots" << json::array; const Position rsb_prepos = last_slot ? last_slot->origin() : fsm.slots.segment.advance(); - fsm.slots.segment.positionSlots(0); + fsm.slots.segment.positionSlots(0, 0, 0, m.slotMap().dir()); for(Slot * slot = output_slot(fsm.slots, 0); slot != last_slot; slot = slot->next()) *fsm.dbgout << dslot(&fsm.slots.segment, slot); @@ -607,12 +629,16 @@ bool Pass::testConstraint(const Rule & r, Machine & m) const } -void SlotMap::collectGarbage() +void SlotMap::collectGarbage(Slot * &aSlot) { for(Slot **s = begin(), *const *const se = end() - 1; s != se; ++s) { Slot *& slot = *s; if(slot->isDeleted() || slot->isCopied()) + { + if (slot == aSlot) + aSlot = slot->prev() ? slot->prev() : slot->next(); segment.freeSlot(slot); + } } } @@ -681,7 +707,6 @@ bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const { ShiftCollider shiftcoll(dbgout); // bool isfirst = true; - const uint8 numLoops = m_flags & 7; // number of loops permitted to fix collisions; does not include kerning bool hasCollisions = false; Slot *start = seg->first(); // turn on collision fixing for the first slot Slot *end = NULL; @@ -690,7 +715,7 @@ bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const #if !defined GRAPHITE2_NTRACING if (dbgout) *dbgout << "collisions" << json::array - << json::flat << json::object << "num-loops" << numLoops << json::close; + << json::flat << json::object << "num-loops" << m_numCollRuns << json::close; #endif while (start) @@ -707,7 +732,7 @@ bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const if (start && (c->flags() & (SlotCollision::COLL_FIX | SlotCollision::COLL_KERN)) == SlotCollision::COLL_FIX && !resolveCollisions(seg, s, start, shiftcoll, false, dir, moved, hasCollisions, dbgout)) return false; - if (s != start && c->flags() & SlotCollision::COLL_END) + if (s != start && (c->flags() & SlotCollision::COLL_END)) { end = s->next(); break; @@ -720,7 +745,7 @@ bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const #endif // phase 2 : loop until happy. - for (int i = 0; i < numLoops - 1; ++i) + for (int i = 0; i < m_numCollRuns - 1; ++i) { if (hasCollisions || moved) { @@ -918,7 +943,7 @@ bool Pass::resolveCollisions(Segment *seg, Slot *slotFix, Slot *start, || (rtl ^ ignoreForKern)) // or it comes before(ltr) or after(rtl) && (!isRev // if processing forwards then good to merge otherwise only: || !(cNbor->flags() & SlotCollision::COLL_FIX) // merge in immovable stuff - || (cNbor->flags() & SlotCollision::COLL_KERN && !sameCluster) // ignore other kernable clusters + || ((cNbor->flags() & SlotCollision::COLL_KERN) && !sameCluster) // ignore other kernable clusters || (cNbor->flags() & SlotCollision::COLL_ISCOL)) // test against other collided glyphs && !coll.mergeSlot(seg, nbor, cNbor->shift(), !ignoreForKern, sameCluster, collides, false, dbgout)) return false; @@ -944,7 +969,7 @@ bool Pass::resolveCollisions(Segment *seg, Slot *slotFix, Slot *start, Rect bbox; Position here = slotFix->origin() + shift; float clusterMin = here.x; - slotFix->firstChild()->finalise(seg, NULL, here, bbox, 0, clusterMin, false); + slotFix->firstChild()->finalise(seg, NULL, here, bbox, 0, clusterMin, rtl, false); } } } @@ -1002,7 +1027,7 @@ float Pass::resolveKern(Segment *seg, Slot *slotFix, GR_MAYBE_UNUSED Slot *start SlotCollision *cNbor = seg->collisionInfo(nbor); if (bb.bl.y == 0.f && bb.tr.y == 0.f) { - if ((m_flags & 24) == 16) + if (m_kernColls == InWord) break; // Add space for a space glyph. currSpace += nbor->advance(); diff --git a/gfx/graphite2/src/SegCache.cpp b/gfx/graphite2/src/SegCache.cpp index 446dfbec43f8..b577efa270ac 100644 --- a/gfx/graphite2/src/SegCache.cpp +++ b/gfx/graphite2/src/SegCache.cpp @@ -40,7 +40,7 @@ using namespace graphite2; SegCache::SegCache(const SegCacheStore * store, const Features & feats) : m_prefixLength(ePrefixLength), - m_maxCachedSegLength(eMaxSpliceSize), +// m_maxCachedSegLength(eMaxSpliceSize), m_segmentCount(0), m_features(feats), m_totalAccessCount(0l), m_totalMisses(0l), @@ -84,7 +84,7 @@ SegCacheEntry* SegCache::cache(SegCacheStore * store, const uint16* cmapGlyphs, { uint16 pos = 0; if (!length) return NULL; - assert(length < m_maxCachedSegLength); +// assert(length < m_maxCachedSegLength); SegCachePrefixArray pArray = m_prefixes; while (pos + 1 < m_prefixLength) { diff --git a/gfx/graphite2/src/Segment.cpp b/gfx/graphite2/src/Segment.cpp index f8b2690e8cf5..d24dfe4f723c 100644 --- a/gfx/graphite2/src/Segment.cpp +++ b/gfx/graphite2/src/Segment.cpp @@ -36,7 +36,7 @@ of the License or (at your option) any later version. #include "inc/Slot.h" #include "inc/Main.h" #include "inc/CmapCache.h" -#include "inc/Bidi.h" +//#include "inc/Bidi.h" #include "inc/Collider.h" #include "graphite2/Segment.h" @@ -68,8 +68,10 @@ Segment::~Segment() { for (SlotRope::iterator i = m_slots.begin(); i != m_slots.end(); ++i) free(*i); - for (AttributeRope::iterator j = m_userAttrs.begin(); j != m_userAttrs.end(); ++j) - free(*j); + for (AttributeRope::iterator i = m_userAttrs.begin(); i != m_userAttrs.end(); ++i) + free(*i); + for (JustifyRope::iterator i = m_justifies.begin(); i != m_justifies.end(); ++i) + free(*i); delete[] m_charinfo; } @@ -154,6 +156,12 @@ void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset) aSlot->originate(id); aSlot->before(id); aSlot->after(id); +// uint8 aBidi = m_silf->aBidi(); +// if (aBidi != 0xFF) +// { +// unsigned int bAttr = glyphAttr(gid, aBidi); +// aSlot->setBidiClass((bAttr <= 22) * bAttr); +// } if (m_last) m_last->next(aSlot); aSlot->prev(m_last); m_last = aSlot; @@ -167,6 +175,9 @@ Slot *Segment::newSlot() { if (!m_freeSlots) { + // check that the segment doesn't grow indefinintely + if (m_numGlyphs > m_numCharinfo * MAX_SEG_GROWTH_FACTOR) + return NULL; int numUser = m_silf->numUser(); #if !defined GRAPHITE2_NTRACING if (m_face->logger()) ++numUser; @@ -176,9 +187,8 @@ Slot *Segment::newSlot() if (!newSlots || !newAttrs) return NULL; for (size_t i = 0; i < m_bufSize; i++) { + ::new (newSlots + i) Slot(newAttrs + i * numUser); newSlots[i].next(newSlots + i + 1); - newSlots[i].userAttrs(newAttrs + i * numUser); - newSlots[i].setBidiClass(-1); } newSlots[m_bufSize - 1].next(NULL); newSlots[0].next(NULL); @@ -205,7 +215,7 @@ void Segment::freeSlot(Slot *aSlot) aSlot->removeChild(aSlot->firstChild()); } // reset the slot incase it is reused - ::new (aSlot) Slot; + ::new (aSlot) Slot(aSlot->userAttrs()); memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16)); // Update generation counter for debug #if !defined GRAPHITE2_NTRACING @@ -309,6 +319,61 @@ void Segment::splice(size_t offset, size_t length, Slot * const startSlot, } #endif // GRAPHITE2_NSEGCACHE +// reverse the slots but keep diacritics in their same position after their bases +void Segment::reverseSlots() +{ + m_dir = m_dir ^ 64; // invert the reverse flag + if (m_first == m_last) return; // skip 0 or 1 glyph runs + + Slot *t = 0; + Slot *curr = m_first; + Slot *tlast; + Slot *tfirst; + Slot *out = 0; + + while (curr && getSlotBidiClass(curr) == 16) + curr = curr->next(); + if (!curr) return; + tfirst = curr->prev(); + tlast = curr; + + while (curr) + { + if (getSlotBidiClass(curr) == 16) + { + Slot *d = curr->next(); + while (d && getSlotBidiClass(d) == 16) + d = d->next(); + + d = d ? d->prev() : m_last; + Slot *p = out->next(); // one after the diacritics. out can't be null + if (p) + p->prev(d); + else + tlast = d; + t = d->next(); + d->next(p); + curr->prev(out); + out->next(curr); + } + else // will always fire first time round the loop + { + if (out) + out->prev(curr); + t = curr->next(); + curr->next(out); + out = curr; + } + curr = t; + } + out->prev(tfirst); + if (tfirst) + tfirst->next(out); + else + m_first = out; + m_last = tlast; +} + void Segment::linkClusters(Slot *s, Slot * end) { end = end->next(); @@ -338,7 +403,7 @@ void Segment::linkClusters(Slot *s, Slot * end) } } -Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isFinal) +Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isRtl, bool isFinal) { Position currpos(0., 0.); float clusterMin = 0.; @@ -347,12 +412,12 @@ Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bo if (!iStart) iStart = m_first; if (!iEnd) iEnd = m_last; - if (m_dir & 1) + if (isRtl) { for (Slot * s = iEnd, * const end = iStart->prev(); s && s != end; s = s->prev()) { if (s->isBase()) - currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isFinal); + currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal); } } else @@ -360,7 +425,7 @@ Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bo for (Slot * s = iStart, * const end = iEnd->next(); s && s != end; s = s->next()) { if (s->isBase()) - currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isFinal); + currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal); } } return currpos; @@ -437,12 +502,13 @@ bool Segment::read_text(const Face *face, const Features* pFeats/*must not be NU return true; } +#if 0 Slot *process_bidi(Slot *start, int level, int prelevel, int &nextLevel, int dirover, int isol, int &cisol, int &isolerr, int &embederr, int init, Segment *seg, uint8 aMirror, BracketPairStack &stack); void resolveImplicit(Slot *s, Segment *seg, uint8 aMirror); void resolveWhitespace(int baseLevel, Slot *s); Slot *resolveOrder(Slot * & s, const bool reordered, const int level = 0); -void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror) +void Segment::bidiPass(int paradir, uint8 aMirror) { if (slotCount() == 0) return; @@ -453,11 +519,8 @@ void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror) unsigned int ssize = 0; for (s = first(); s; s = s->next()) { - if (s->getBidiClass() == -1) - { - unsigned int bAttr = glyphAttr(s->gid(), aBidi); - s->setBidiClass((bAttr <= 22) * bAttr); - } + if (getSlotBidiClass(s) < 0) + s->setBidiClass(0); bmask |= (1 << s->getBidiClass()); s->setBidiLevel(baseLevel); if (s->getBidiClass() == 21) @@ -489,6 +552,18 @@ void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror) } } } +#endif + +void Segment::doMirror(uint16 aMirror) +{ + Slot * s; + for (s = m_first; s; s = s->next()) + { + unsigned short g = glyphAttr(s->gid(), aMirror); + if (g && (!(dir() & 4) || !glyphAttr(s->gid(), aMirror + 1))) + s->setGlyph(this, g); + } +} bool Segment::initCollisions() { diff --git a/gfx/graphite2/src/Silf.cpp b/gfx/graphite2/src/Silf.cpp index df7dd1e2ef6e..a5a0efc75b35 100644 --- a/gfx/graphite2/src/Silf.cpp +++ b/gfx/graphite2/src/Silf.cpp @@ -51,6 +51,7 @@ Silf::Silf() throw() m_jPass(0), m_bPass(0), m_flags(0), + m_dir(0), m_aPseudo(0), m_aBreak(0), m_aUser(0), @@ -58,6 +59,7 @@ Silf::Silf() throw() m_aMirror(0), m_aPassBits(0), m_iMaxComp(0), + m_aCollision(0), m_aLig(0), m_numPseudo(0), m_nClass(0), @@ -141,10 +143,10 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face, } if (e.test(p + sizeof(uint16) + sizeof(uint8)*8 >= silf_end, E_BADENDJUSTS)) { releaseBuffers(); return face.error(e); } - m_aLig = be::read(p); - m_aUser = be::read(p); - m_iMaxComp = be::read(p); - be::skip(p); // direction + m_aLig = be::read(p); + m_aUser = be::read(p); + m_iMaxComp = be::read(p); + m_dir = be::read(p) - 1; m_aCollision = be::read(p); be::skip(p,3); be::skip(p, be::read(p)); // don't need critical features yet @@ -198,7 +200,9 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face, const byte * const pass_start = silf_start + be::read(o_passes), * const pass_end = silf_start + be::peek(o_passes); face.error_context((face.error_context() & 0xFF00) + EC_ASILF + (i << 16)); - if (e.test(pass_start > pass_end, E_BADPASSSTART) || e.test(pass_end > silf_end, E_BADPASSEND)) { + if (e.test(pass_start > pass_end, E_BADPASSSTART) + || e.test(pass_start < passes_start, E_BADPASSSTART) + || e.test(pass_end > silf_end, E_BADPASSEND)) { releaseBuffers(); return face.error(e); } @@ -268,6 +272,9 @@ size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version, Error if (max_off == ERROROFFSET) return ERROROFFSET; + if (e.test((int)max_off < m_nLinear + (m_nClass - m_nLinear) * 6, E_CLASSESTOOBIG)) + return ERROROFFSET; + // Check the linear offsets are sane, these must be monotonically increasing. for (const uint32 *o = m_classOffsets, * const o_end = o + m_nLinear; o != o_end; ++o) if (e.test(o[0] > o[1], E_BADCLASSOFFSET)) @@ -283,10 +290,10 @@ size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version, Error for (const uint32 *o = m_classOffsets + m_nLinear, * const o_end = m_classOffsets + m_nClass; o != o_end; ++o) { const uint16 * lookup = m_classData + *o; - if (e.test(*o > max_off - 4, E_HIGHCLASSOFFSET) // LookupClass doesn't stretch over max_off + if (e.test(*o + 4 > max_off, E_HIGHCLASSOFFSET) // LookupClass doesn't stretch over max_off || e.test(lookup[0] == 0 // A LookupClass with no looks is a suspicious thing ... - || lookup[0] > (max_off - *o - 4)/2 // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off] - || lookup[3] != lookup[0] - lookup[1], E_BADCLASSLOOKUPINFO)) // rangeShift: numIDs - searchRange + || lookup[0] * 2 + *o + 4 > max_off // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off] + || lookup[3] + lookup[1] != lookup[0], E_BADCLASSLOOKUPINFO)) // rangeShift: numIDs - searchRange return ERROROFFSET; } @@ -307,7 +314,7 @@ uint16 Silf::findClassIndex(uint16 cid, uint16 gid) const const uint16 * cls = m_classData + m_classOffsets[cid]; if (cid < m_nLinear) // output class being used for input, shouldn't happen { - for (unsigned int i = 0, n = m_classOffsets[cid + 1]; i < n; ++i, ++cls) + for (unsigned int i = 0, n = m_classOffsets[cid + 1] - m_classOffsets[cid]; i < n; ++i, ++cls) if (*cls == gid) return i; return -1; } @@ -348,7 +355,7 @@ uint16 Silf::getClassGlyph(uint16 cid, unsigned int index) const bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi) const { assert(seg != 0); - SlotMap map(*seg); + SlotMap map(*seg, m_dir); FiniteStateMachine fsm(map, seg->getFace()->logger()); vm::Machine m(map); unsigned int initSize = seg->slotCount(); @@ -363,7 +370,7 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi return true; lastPass = m_numPasses; } - if (firstPass <= lbidi && lastPass >= lbidi && dobidi) + if ((firstPass < lbidi || (dobidi && firstPass == lbidi)) && (lastPass >= lbidi || (dobidi && lastPass + 1 == lbidi))) lastPass++; else lbidi = 0xFF; @@ -379,7 +386,7 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi *dbgout << json::item << json::object << "id" << -1 << "slots" << json::array; - seg->positionSlots(0); + seg->positionSlots(0, 0, 0, m_dir); for(Slot * s = seg->first(); s; s = s->next()) *dbgout << dslot(seg, s); *dbgout << json::close @@ -387,22 +394,13 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi << json::close; } #endif - - if (!(seg->dir() & 2)) - seg->bidiPass(m_aBidi, seg->dir() & 1, m_aMirror); - else if (m_aMirror && (seg->dir() & 1)) - { - Slot * s; - for (s = seg->first(); s; s = s->next()) - { - unsigned short g = seg->glyphAttr(s->gid(), m_aMirror); - if (g && (!(seg->dir() & 4) || !seg->glyphAttr(s->gid(), m_aMirror + 1))) - s->setGlyph(seg, g); - } - } + if (seg->currdir() != m_dir) + seg->reverseSlots(); + if (m_aMirror && (seg->dir() & 3) == 3) + seg->doMirror(m_aMirror); --i; + lbidi = lastPass; --lastPass; - lbidi = 0xFF; continue; } @@ -412,7 +410,7 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi *dbgout << json::item << json::object << "id" << i+1 << "slots" << json::array; - seg->positionSlots(0); + seg->positionSlots(0, 0, 0, m_dir); for(Slot * s = seg->first(); s; s = s->next()) *dbgout << dslot(seg, s); *dbgout << json::close; @@ -420,13 +418,13 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi #endif // test whether to reorder, prepare for positioning - if ((i >= 32 || (seg->passBits() & (1 << i)) == 0 || (m_passes[i].flags() & 7)) - && !m_passes[i].runGraphite(m, fsm)) + bool reverse = (lbidi == 0xFF) && (seg->currdir() != ((m_dir & 1) ^ m_passes[i].reverseDir())); + if ((i >= 32 || (seg->passBits() & (1 << i)) == 0 || m_passes[i].collisionLoops()) + && !m_passes[i].runGraphite(m, fsm, reverse)) return false; // only subsitution passes can change segment length, cached subsegments are short for their text if (m.status() != vm::Machine::finished - || (i < m_pPass && (seg->slotCount() > initSize * MAX_SEG_GROWTH_FACTOR - || (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize)))) + || (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize)) return false; } return true; diff --git a/gfx/graphite2/src/Slot.cpp b/gfx/graphite2/src/Slot.cpp index 0c25fa761372..dd2a89bc9cd6 100644 --- a/gfx/graphite2/src/Slot.cpp +++ b/gfx/graphite2/src/Slot.cpp @@ -34,15 +34,14 @@ of the License or (at your option) any later version. using namespace graphite2; -Slot::Slot() : +Slot::Slot(int16 *user_attrs) : m_next(NULL), m_prev(NULL), m_glyphid(0), m_realglyphid(0), m_original(0), m_before(0), m_after(0), m_index(0), m_parent(NULL), m_child(NULL), m_sibling(NULL), m_position(0, 0), m_shift(0, 0), m_advance(0, 0), m_attach(0, 0), m_with(0, 0), m_just(0.), - m_flags(0), m_attLevel(0), m_bidiCls(-1), m_bidiLevel(0), m_justs(NULL) - // Do not set m_userAttr since it is set *before* new is called since this - // is used as a positional new to reset the GrSlot + m_flags(0), m_attLevel(0), m_bidiCls(-1), m_bidiLevel(0), + m_userAttr(user_attrs), m_justs(NULL) { } @@ -86,17 +85,17 @@ void Slot::update(int /*numGrSlots*/, int numCharInfo, Position &relpos) m_position = m_position + relpos; } -Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool isFinal) +Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal) { SlotCollision *coll = NULL; if (attrLevel && m_attLevel > attrLevel) return Position(0, 0); float scale = font ? font->scale() : 1.0f; - Position shift(m_shift.x * ((seg->dir() & 1) * -2 + 1) + m_just, m_shift.y); + Position shift(m_shift.x * (rtl * -2 + 1) + m_just, m_shift.y); float tAdvance = m_advance.x + m_just; if (isFinal && (coll = seg->collisionInfo(this))) { const Position &collshift = coll->offset(); - if (!(coll->flags() & SlotCollision::COLL_KERN) || (seg->dir() & 1)) + if (!(coll->flags() & SlotCollision::COLL_KERN) || rtl) shift = shift + collshift; } const GlyphFace * glyphFace = seg->getFace()->glyphs().glyphSafe(glyph()); @@ -134,13 +133,13 @@ Position Slot::finalise(const Segment *seg, const Font *font, Position & base, R if (m_child && m_child != this && m_child->attachedTo() == this) { - Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, isFinal); + Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, rtl, isFinal); if ((!m_parent || m_advance.x >= 0.5f) && tRes.x > res.x) res = tRes; } if (m_parent && m_sibling && m_sibling != this && m_sibling->attachedTo() == m_parent) { - Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin, isFinal); + Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin, rtl, isFinal); if (tRes.x > res.x) res = tRes; } @@ -154,12 +153,14 @@ Position Slot::finalise(const Segment *seg, const Font *font, Position & base, R return res; } -int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel) +int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel, bool rtl) { Position base; + if (glyph() >= seg->getFace()->glyphs().numGlyphs()) + return 0; Rect bbox = seg->theGlyphBBoxTemporary(glyph()); float clusterMin = 0.; - Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin, false); + Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin, rtl, false); switch (metrics(metric)) { @@ -192,7 +193,6 @@ int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel) int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const { - if (!this) return 0; if (ind == gr_slatUserDefnV1) { ind = gr_slatUserDefn; @@ -220,9 +220,7 @@ int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const case gr_slatAttLevel : return m_attLevel; case gr_slatBreak : return seg->charinfo(m_original)->breakWeight(); case gr_slatCompRef : return 0; - case gr_slatDir : if (m_bidiCls == -1) - const_cast(this)->setBidiClass(int8(seg->glyphAttr(gid(), seg->silf()->aBidi()))); - return m_bidiCls; + case gr_slatDir : return seg->dir() & 1; case gr_slatInsert : return isInsertBefore(); case gr_slatPosX : return int(m_position.x); // but need to calculate it case gr_slatPosY : return int(m_position.y); @@ -272,7 +270,6 @@ int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, const SlotMap & map) { - if (!this) return; if (ind == gr_slatUserDefnV1) { ind = gr_slatUserDefn; @@ -299,7 +296,7 @@ void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, cons if (!other->isChildOf(this) && other->child(this)) { attachTo(other); - if (((seg->dir() & 1) != 0) ^ (idx > subindex)) + if ((map.dir() != 0) ^ (idx > subindex)) m_with = Position(advance(), 0); else // normal match to previous root m_attach = Position(other->advance(), 0); @@ -322,7 +319,7 @@ void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, cons seg->charinfo(m_original)->breakWeight(value); break; case gr_slatCompRef : break; // not sure what to do here - case gr_slatDir : m_bidiCls = int8(value); break; + case gr_slatDir : break; case gr_slatInsert : markInsertBefore(value? true : false); break; @@ -450,6 +447,7 @@ bool Slot::removeSibling(Slot *ap) void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph) { m_glyphid = glyphid; + m_bidiCls = -1; if (!theGlyph) { theGlyph = seg->getFace()->glyphs().glyphSafe(glyphid); @@ -461,6 +459,8 @@ void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph) } } m_realglyphid = theGlyph->attrs()[seg->silf()->aPseudo()]; + if (m_realglyphid > seg->getFace()->glyphs().numGlyphs()) + m_realglyphid = 0; const GlyphFace *aGlyph = theGlyph; if (m_realglyphid) { diff --git a/gfx/graphite2/src/Sparse.cpp b/gfx/graphite2/src/Sparse.cpp index 8730f78644df..aa43113669b7 100644 --- a/gfx/graphite2/src/Sparse.cpp +++ b/gfx/graphite2/src/Sparse.cpp @@ -30,7 +30,7 @@ of the License or (at your option) any later version. using namespace graphite2; -sparse::chunk sparse::empty_chunk = {0,0}; +const sparse::chunk sparse::empty_chunk = {0,0}; sparse::~sparse() throw() { diff --git a/gfx/graphite2/src/TtfUtil.cpp b/gfx/graphite2/src/TtfUtil.cpp index ad0ec965b758..7be8ecdb573e 100644 --- a/gfx/graphite2/src/TtfUtil.cpp +++ b/gfx/graphite2/src/TtfUtil.cpp @@ -62,8 +62,10 @@ Description ***********************************************************************************************/ namespace { +#ifdef ALL_TTFUTILS // max number of components allowed in composite glyphs const int kMaxGlyphComponents = 8; +#endif template inline float fixed_to_float(const T f) { @@ -227,7 +229,7 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize) { using namespace Sfnt; - if (pTable == 0) return false; + if (pTable == 0 || lTableSize < 4) return false; switch(TableId) { @@ -235,6 +237,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize) { const Sfnt::CharacterCodeMap * const pCmap = reinterpret_cast(pTable); + if (lTableSize < sizeof(Sfnt::CharacterCodeMap)) + return false; return be::swap(pCmap->version) == 0; } @@ -242,6 +246,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize) { const Sfnt::FontHeader * const pHead = reinterpret_cast(pTable); + if (lTableSize < sizeof(Sfnt::FontHeader)) + return false; bool r = be::swap(pHead->version) == OneFix && be::swap(pHead->magic_number) == FontHeader::MagicNumber && be::swap(pHead->glyph_data_format) @@ -258,6 +264,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize) { const Sfnt::PostScriptGlyphName * const pPost = reinterpret_cast(pTable); + if (lTableSize < sizeof(Sfnt::PostScriptGlyphName)) + return false; const fixed format = be::swap(pPost->format); bool r = format == PostScriptGlyphName::Format1 || format == PostScriptGlyphName::Format2 @@ -270,6 +278,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize) { const Sfnt::HorizontalHeader * pHhea = reinterpret_cast(pTable); + if (lTableSize < sizeof(Sfnt::HorizontalHeader)) + return false; bool r = be::swap(pHhea->version) == OneFix && be::swap(pHhea->metric_data_format) == 0 && sizeof (Sfnt::HorizontalHeader) <= lTableSize; @@ -280,6 +290,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize) { const Sfnt::MaximumProfile * pMaxp = reinterpret_cast(pTable); + if (lTableSize < sizeof(Sfnt::MaximumProfile)) + return false; bool r = be::swap(pMaxp->version) == OneFix && sizeof(Sfnt::MaximumProfile) <= lTableSize; return r; @@ -324,6 +336,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize) { const Sfnt::FontNames * pName = reinterpret_cast(pTable); + if (lTableSize < sizeof(Sfnt::FontNames)) + return false; return be::swap(pName->format) == 0; } @@ -796,7 +810,7 @@ bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize, const void size_t cLongHorMetrics = be::swap(phhea->num_long_hor_metrics); if (nGlyphId < cLongHorMetrics) { // glyph id is acceptable - if (nGlyphId * sizeof(Sfnt::HorizontalMetric) >= lHmtxSize) return false; + if ((nGlyphId + 1) * sizeof(Sfnt::HorizontalMetric) > lHmtxSize) return false; nAdvWid = be::swap(phmtx[nGlyphId].advance_width); nLsb = be::swap(phmtx[nGlyphId].left_side_bearing); } @@ -806,7 +820,7 @@ bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize, const void size_t lLsbOffset = sizeof(Sfnt::HorizontalMetric) * cLongHorMetrics + sizeof(int16) * (nGlyphId - cLongHorMetrics); // offset in bytes // We test like this as LsbOffset is an offset not a length. - if (lLsbOffset > lHmtxSize - sizeof(int16)) + if (lLsbOffset >= lHmtxSize - sizeof(int16) || cLongHorMetrics == 0) { nLsb = 0; return false; @@ -873,7 +887,7 @@ const void * FindCmapSubtable(const void * pCmap, int nPlatformId, /* =3 */ int /*---------------------------------------------------------------------------------------------- Check the Microsoft Unicode subtable for expected values ----------------------------------------------------------------------------------------------*/ -bool CheckCmapSubtable4(const void * pCmapSubtable4 /*, unsigned int maxgid*/) +bool CheckCmapSubtable4(const void * pCmapSubtable4, size_t table_len /*, unsigned int maxgid*/) { if (!pCmapSubtable4) return false; const Sfnt::CmapSubTable * pTable = reinterpret_cast(pCmapSubtable4); @@ -882,6 +896,8 @@ bool CheckCmapSubtable4(const void * pCmapSubtable4 /*, unsigned int maxgid*/) if (be::swap(pTable->format) != 4) return false; const Sfnt::CmapSubTableFormat4 * pTable4 = reinterpret_cast(pCmapSubtable4); uint16 length = be::swap(pTable4->length); + if (length > table_len) + return false; if (length < sizeof(Sfnt::CmapSubTableFormat4)) return false; uint16 nRanges = be::swap(pTable4->seg_count_x2) >> 1; @@ -919,7 +935,7 @@ bool CheckCmapSubtable4(const void * pCmapSubtable4 /*, unsigned int maxgid*/) lastend = end; } #endif - return true;; + return true; } /*---------------------------------------------------------------------------------------------- @@ -1062,7 +1078,7 @@ unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnico /*---------------------------------------------------------------------------------------------- Check the Microsoft UCS-4 subtable for expected values. ----------------------------------------------------------------------------------------------*/ -bool CheckCmapSubtable12(const void *pCmapSubtable12 /*, unsigned int maxgid*/) +bool CheckCmapSubtable12(const void *pCmapSubtable12, size_t table_len /*, unsigned int maxgid*/) { if (!pCmapSubtable12) return false; const Sfnt::CmapSubTable * pTable = reinterpret_cast(pCmapSubtable12); @@ -1070,6 +1086,8 @@ bool CheckCmapSubtable12(const void *pCmapSubtable12 /*, unsigned int maxgid*/) return false; const Sfnt::CmapSubTableFormat12 * pTable12 = reinterpret_cast(pCmapSubtable12); uint32 length = be::swap(pTable12->length); + if (length > table_len) + return false; if (length < sizeof(Sfnt::CmapSubTableFormat12)) return false; uint32 num_groups = be::swap(pTable12->num_groups); @@ -1221,7 +1239,7 @@ size_t LocaLookup(gid16 nGlyphId, void * GlyfLookup(const void * pGlyf, size_t nGlyfOffset, size_t nTableLen) { const uint8 * pByte = reinterpret_cast(pGlyf); - if (nGlyfOffset == size_t(-1) || nGlyfOffset == size_t(-2) || nGlyfOffset >= nTableLen) + if (nGlyfOffset + pByte < pByte || nGlyfOffset + sizeof(Sfnt::Glyph) >= nTableLen) return NULL; return const_cast(pByte + nGlyfOffset); } @@ -1833,7 +1851,6 @@ bool GlyfContourEndPoints(gid16 nGlyphId, const void * pGlyf, const void * pLoca This range is parallel to the prgnX & prgnY Return true if successful, false otherwise. On false, all points may be INT_MIN False may indicate a white space glyph, a multi-level composite, or a corrupt font - // TODO: doesn't support composite glyphs whose components are themselves components It's not clear from the TTF spec when the transforms should be applied. Should the transform be done before or after attachment point calcs? (current code - before) Should the transform be applied to other offsets? (currently - no; however commented diff --git a/gfx/graphite2/src/call_machine.cpp b/gfx/graphite2/src/call_machine.cpp index cfe57076fab2..e1d0ce5d2ff6 100644 --- a/gfx/graphite2/src/call_machine.cpp +++ b/gfx/graphite2/src/call_machine.cpp @@ -70,6 +70,7 @@ struct regbank { SlotMap & smap; slotref * const map_base; const instr * & ip; + uint8 direction; int8 flags; }; @@ -86,6 +87,7 @@ namespace { #define map reg.map #define mapb reg.map_base #define flags reg.flags +#define dir reg.direction #include "inc/opcodes.h" @@ -96,6 +98,7 @@ namespace { #undef map #undef mapb #undef flags +#undef dir } Machine::stack_t Machine::run(const instr * program, @@ -110,7 +113,7 @@ Machine::stack_t Machine::run(const instr * program, const byte * dp = data; stack_t * sp = _stack + Machine::STACK_GUARD, * const sb = sp; - regbank reg = {*map, map, _map, _map.begin()+_map.context(), ip, 0}; + regbank reg = {*map, map, _map, _map.begin()+_map.context(), ip, _map.dir(), 0}; // Run the program while ((reinterpret_cast(*++ip))(dp, sp, sb, reg)) {} diff --git a/gfx/graphite2/src/direct_machine.cpp b/gfx/graphite2/src/direct_machine.cpp index 09709c30336c..b6b9ee042359 100644 --- a/gfx/graphite2/src/direct_machine.cpp +++ b/gfx/graphite2/src/direct_machine.cpp @@ -61,6 +61,7 @@ const void * direct_run(const bool get_table_mode, const byte * data, Machine::stack_t * stack, slotref * & __map, + uint8 _dir, SlotMap * __smap=0) { // We need to define and return to opcode table from within this function @@ -79,6 +80,7 @@ const void * direct_run(const bool get_table_mode, slotref is = *__map, * map = __map, * const mapb = smap.begin()+smap.context(); + uint8 dir = _dir; int8 flags = 0; // start the program @@ -109,7 +111,7 @@ Machine::stack_t Machine::run(const instr * program, assert(program != 0); const stack_t *sp = static_cast( - direct_run(false, program, data, _stack, is, &_map)); + direct_run(false, program, data, _stack, is, _map.dir(), &_map)); const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0; check_final_stack(sp); return ret; diff --git a/gfx/graphite2/src/files.mk b/gfx/graphite2/src/files.mk index b1ff7736f2bd..fde83761c569 100644 --- a/gfx/graphite2/src/files.mk +++ b/gfx/graphite2/src/files.mk @@ -47,7 +47,6 @@ $(_NS)_SOURCES = \ $($(_NS)_BASE)/src/gr_segment.cpp \ $($(_NS)_BASE)/src/gr_slot.cpp \ $($(_NS)_BASE)/src/json.cpp \ - $($(_NS)_BASE)/src/Bidi.cpp \ $($(_NS)_BASE)/src/CachedFace.cpp \ $($(_NS)_BASE)/src/CmapCache.cpp \ $($(_NS)_BASE)/src/Code.cpp \ @@ -78,13 +77,12 @@ $(_NS)_PRIVATE_HEADERS = \ $($(_NS)_BASE)/src/inc/bits.h \ $($(_NS)_BASE)/src/inc/debug.h \ $($(_NS)_BASE)/src/inc/json.h \ - $($(_NS)_BASE)/src/inc/locale2lcid.h \ - $($(_NS)_BASE)/src/inc/Bidi.h \ $($(_NS)_BASE)/src/inc/CachedFace.h \ $($(_NS)_BASE)/src/inc/CharInfo.h \ $($(_NS)_BASE)/src/inc/CmapCache.h \ $($(_NS)_BASE)/src/inc/Code.h \ $($(_NS)_BASE)/src/inc/Collider.h \ + $($(_NS)_BASE)/src/inc/Compression.h \ $($(_NS)_BASE)/src/inc/Decompressor.h \ $($(_NS)_BASE)/src/inc/Endian.h \ $($(_NS)_BASE)/src/inc/Error.h \ @@ -110,7 +108,6 @@ $(_NS)_PRIVATE_HEADERS = \ $($(_NS)_BASE)/src/inc/SegCacheEntry.h \ $($(_NS)_BASE)/src/inc/SegCacheStore.h \ $($(_NS)_BASE)/src/inc/Segment.h \ - $($(_NS)_BASE)/src/inc/Shrinker.h \ $($(_NS)_BASE)/src/inc/Silf.h \ $($(_NS)_BASE)/src/inc/Slot.h \ $($(_NS)_BASE)/src/inc/Sparse.h \ diff --git a/gfx/graphite2/src/gr_segment.cpp b/gfx/graphite2/src/gr_segment.cpp index aab74e40ff55..0ab7a0854cc4 100644 --- a/gfx/graphite2/src/gr_segment.cpp +++ b/gfx/graphite2/src/gr_segment.cpp @@ -48,7 +48,7 @@ namespace delete pRes; return NULL; } - pRes->finalise(font); + pRes->finalise(font, true); return static_cast(pRes); } diff --git a/gfx/graphite2/src/inc/Code.h b/gfx/graphite2/src/inc/Code.h index c27ff0d9da14..02d09a109d66 100644 --- a/gfx/graphite2/src/inc/Code.h +++ b/gfx/graphite2/src/inc/Code.h @@ -69,7 +69,6 @@ public: }; private: - static byte * local_memory; class decoder; instr * _code; @@ -87,22 +86,24 @@ private: void failure(const status_t) throw(); public: + static size_t estimateCodeDataOut(size_t num_bytecodes); + Code() throw(); Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end, uint8 pre_context, uint16 rule_length, const Silf &, const Face &, - enum passtype pt, byte * & _out = local_memory); + enum passtype pt, byte * * const _out = 0); Code(const Machine::Code &) throw(); ~Code() throw(); Code & operator=(const Code &rhs) throw(); - operator bool () const throw(); - status_t status() const throw(); - bool constraint() const throw(); - size_t dataSize() const throw(); - size_t instructionCount() const throw(); - bool immutable() const throw(); - bool deletes() const throw(); - size_t maxRef() const throw(); + operator bool () const throw() { return _code && status() == loaded; } + status_t status() const throw() { return _status; } + bool constraint() const throw() { return _constraint; } + size_t dataSize() const throw() { return _data_size; } + size_t instructionCount() const throw() { return _instr_count; } + bool immutable() const throw() { return !(_delete || _modify); } + bool deletes() const throw() { return _delete; } + size_t maxRef() const throw() { return _max_ref; } void externalProgramMoved(ptrdiff_t) throw(); int32 run(Machine &m, slotref * & map) const; @@ -110,10 +111,16 @@ public: CLASS_NEW_DELETE; }; +inline +size_t Machine::Code::estimateCodeDataOut(size_t n_bc) +{ + return n_bc * (sizeof(instr)+sizeof(byte)); +} + inline Machine::Code::Code() throw() : _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), - _status(loaded), _constraint(false), _modify(false),_delete(false), + _status(loaded), _constraint(false), _modify(false), _delete(false), _own(false) { } @@ -149,41 +156,6 @@ inline Machine::Code & Machine::Code::operator=(const Machine::Code &rhs) throw( return *this; } -inline Machine::Code::operator bool () const throw () { - return _code && status() == loaded; -} - -inline Machine::Code::status_t Machine::Code::status() const throw() { - return _status; -} - -inline bool Machine::Code::constraint() const throw() { - return _constraint; -} - -inline size_t Machine::Code::dataSize() const throw() { - return _data_size; -} - -inline size_t Machine::Code::instructionCount() const throw() { - return _instr_count; -} - -inline bool Machine::Code::immutable() const throw() -{ - return !(_delete || _modify); -} - -inline bool Machine::Code::deletes() const throw() -{ - return _delete; -} - -inline size_t Machine::Code::maxRef() const throw() -{ - return _max_ref; -} - inline void Machine::Code::externalProgramMoved(ptrdiff_t dist) throw() { if (_code && !_own) diff --git a/gfx/graphite2/src/inc/Collider.h b/gfx/graphite2/src/inc/Collider.h index 635f9b07324c..bfa290978b07 100644 --- a/gfx/graphite2/src/inc/Collider.h +++ b/gfx/graphite2/src/inc/Collider.h @@ -28,7 +28,7 @@ of the License or (at your option) any later version. #include #include "inc/List.h" -#include "inc/Slot.h" +//#include "inc/Slot.h" #include "inc/Position.h" #include "inc/Intervals.h" #include "inc/debug.h" @@ -118,8 +118,8 @@ private: }; // end of class SlotColllision -class BBox; -class SlantBox; +struct BBox; +struct SlantBox; class ShiftCollider { @@ -128,13 +128,7 @@ public: typedef Vector vfpairs; typedef vfpairs::iterator ivfpairs; - ShiftCollider(GR_MAYBE_UNUSED json *dbgout) - { -#if !defined GRAPHITE2_NTRACING - for (int i = 0; i < 4; ++i) - _ranges[i].setdebug(dbgout); -#endif - } + ShiftCollider(json *dbgout); ~ShiftCollider() throw() { }; bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint, @@ -176,10 +170,25 @@ protected: }; // end of class ShiftCollider +inline +ShiftCollider::ShiftCollider(GR_MAYBE_UNUSED json *dbgout) +: _target(0), + _margin(0.0), + _marginWt(0.0), + _seqClass(0), + _seqProxClass(0), + _seqOrder(0) +{ +#if !defined GRAPHITE2_NTRACING + for (int i = 0; i < 4; ++i) + _ranges[i].setdebug(dbgout); +#endif +} + class KernCollider { public: - KernCollider(GR_MAYBE_UNUSED json *dbg) : _miny(-1e38f), _maxy(1e38f) { }; + KernCollider(json *dbg); ~KernCollider() throw() { }; bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint, float margin, const Position &currShift, const Position &offsetPrev, int dir, @@ -213,8 +222,24 @@ private: inline -float sqr(float x) { return x * x; } +float sqr(float x) { + return x * x; +} +inline +KernCollider::KernCollider(GR_MAYBE_UNUSED json *dbg) +: _target(0), + _margin(0.0f), + _miny(-1e38f), + _maxy(1e38f), + _sliceWidth(0.0f), + _mingap(0.0f), + _xbound(0.0) +{ +#if !defined GRAPHITE2_NTRACING + _seg = 0; +#endif +}; }; // end of namespace graphite2 diff --git a/gfx/graphite2/src/inc/Compression.h b/gfx/graphite2/src/inc/Compression.h new file mode 100644 index 000000000000..2a665f3a3644 --- /dev/null +++ b/gfx/graphite2/src/inc/Compression.h @@ -0,0 +1,120 @@ +/* GRAPHITE2 LICENSING + + Copyright 2015, SIL International + All rights reserved. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should also have received a copy of the GNU Lesser General Public + License along with this library in the file named "LICENSE". + If not, write to the Free Software Foundation, 51 Franklin Street, + Suite 500, Boston, MA 02110-1335, USA or visit their web page on the + internet at http://www.fsf.org/licenses/lgpl.html. + +Alternatively, the contents of this file may be used under the terms of the +Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public +License, as published by the Free Software Foundation, either version 2 +of the License or (at your option) any later version. +*/ + +#pragma once + +#include +#include +#include + +#include + +#if ((defined GCC_VERSION && GCC_VERSION >= 302) || (defined __INTEL_COMPILER && __INTEL_COMPILER >= 800) || defined(__clang__)) + #define expect(expr,value) (__builtin_expect ((expr),(value)) ) +#else + #define expect(expr,value) (expr) +#endif + +#define likely(expr) expect((expr) != 0, 1) +#define unlikely(expr) expect((expr) != 0, 0) + + +namespace +{ + +#if defined(_MSC_VER) +typedef unsigned __int8 u8; +typedef unsigned __int16 u16; +typedef unsigned __int32 u32; +typedef unsigned __int64 u64; +#else +#include +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +#endif + +ptrdiff_t const MINMATCH = 4; + +template +inline +void unaligned_copy(void * d, void const * s) { + ::memcpy(d, s, S); +} + +inline +size_t align(size_t p) { + return (p + sizeof(unsigned long)-1) & ~(sizeof(unsigned long)-1); +} + +inline +u8 * overrun_copy(u8 * d, u8 const * s, size_t n) { + size_t const WS = sizeof(unsigned long); + u8 const * e = s + n; + do + { + unaligned_copy(d, s); + d += WS; + s += WS; + } + while (s < e); + d-=(s-e); + + return d; +} + + +inline +u8 * fast_copy(u8 * d, u8 const * s, size_t n) { + size_t const WS = sizeof(unsigned long); + size_t wn = n/WS; + while (wn--) + { + unaligned_copy(d, s); + d += WS; + s += WS; + } + n &= WS-1; + while (n--) {*d++ = *s++; } + + return d; +} + + +inline +u8 * copy(u8 * d, u8 const * s, size_t n) { + if (likely(d>s+sizeof(unsigned long))) + return overrun_copy(d,s,n); + else + while (n--) *d++ = *s++; + return d; +} + +} // end of anonymous namespace + + diff --git a/gfx/graphite2/src/inc/Decompressor.h b/gfx/graphite2/src/inc/Decompressor.h index e79410455eeb..ddda0c0f58c4 100644 --- a/gfx/graphite2/src/inc/Decompressor.h +++ b/gfx/graphite2/src/inc/Decompressor.h @@ -1,51 +1,39 @@ -/* Copyright (c) 2012, Siyuan Fu - Copyright (c) 2015, SIL International +/* GRAPHITE2 LICENSING + + Copyright 2015, SIL International All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should also have received a copy of the GNU Lesser General Public + License along with this library in the file named "LICENSE". + If not, write to the Free Software Foundation, 51 Franklin Street, + Suite 500, Boston, MA 02110-1335, USA or visit their web page on the + internet at http://www.fsf.org/licenses/lgpl.html. + +Alternatively, the contents of this file may be used under the terms of the +Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public +License, as published by the Free Software Foundation, either version 2 +of the License or (at your option) any later version. */ + #pragma once #include -namespace shrinker +namespace lz4 { +// return value is either decompressed size of -1 int decompress(void const *in, size_t in_size, void *out, size_t out_size); -/* -in: inbuf --- compressed data -out: outbuf --- decompressed data to place in -size: decompressed(original) data size should be - -return value: - positive integer means decompress success and it's the sizeof decompressed data, - which should be equal to size. - or -1 means decompress failed -*/ } // end of namespace shrinker diff --git a/gfx/graphite2/src/inc/Face.h b/gfx/graphite2/src/inc/Face.h index 252646f32d98..ba1f24aee914 100644 --- a/gfx/graphite2/src/inc/Face.h +++ b/gfx/graphite2/src/inc/Face.h @@ -43,6 +43,7 @@ class FileFace; class GlyphCache; class NameTable; class json; +class Font; using TtfUtil::Tag; @@ -174,6 +175,8 @@ class Face::Table Error decompress(); + void releaseBuffers(); + public: Table() throw(); Table(const Face & face, const Tag n, uint32 version=0xffffffff) throw(); @@ -202,10 +205,7 @@ Face::Table::Table(const Table & rhs) throw() inline Face::Table::~Table() throw() { - if (_compressed) - free(const_cast(_p)); - else if (_p && _f->m_ops.release_table) - (*_f->m_ops.release_table)(_f->m_appFaceHandle, _p); + releaseBuffers(); } inline diff --git a/gfx/graphite2/src/inc/FeatureMap.h b/gfx/graphite2/src/inc/FeatureMap.h index a199a87d71ff..fc845f6e1653 100644 --- a/gfx/graphite2/src/inc/FeatureMap.h +++ b/gfx/graphite2/src/inc/FeatureMap.h @@ -56,7 +56,7 @@ class FeatureRef static const uint8 SIZEOF_CHUNK = sizeof(chunk_t)*8; public: - FeatureRef() : m_nameValues(0) {} + FeatureRef(); FeatureRef(const Face & face, unsigned short & bits_offset, uint32 max_val, uint32 name, uint16 uiName, uint16 flags, FeatureSetting *settings, uint16 num_set) throw(); @@ -99,6 +99,16 @@ private: //unimplemented }; +inline +FeatureRef::FeatureRef() +: m_pFace(0), m_nameValues(0), + m_mask(0), m_max(0), m_id(0), + m_nameid(0), m_flags(0), m_numSet(0), + m_bits(0), m_index(0) +{ +} + + class NameAndFeatureRef { public: diff --git a/gfx/graphite2/src/inc/GlyphCache.h b/gfx/graphite2/src/inc/GlyphCache.h index 821aae53f2de..cf7c2469c3cf 100644 --- a/gfx/graphite2/src/inc/GlyphCache.h +++ b/gfx/graphite2/src/inc/GlyphCache.h @@ -39,10 +39,11 @@ class FeatureVal; class Segment; -class SlantBox +struct SlantBox { -public: - SlantBox(float psi = 0., float pdi = 0., float psa = 0., float pda = 0.) : si(psi), di(pdi), sa(psa), da(pda) {}; + static const SlantBox empty; + +// SlantBox(float psi = 0., float pdi = 0., float psa = 0., float pda = 0.) : si(psi), di(pdi), sa(psa), da(pda) {}; float width() const { return sa - si; } float height() const { return da - di; } float si; // min @@ -51,11 +52,9 @@ public: float da; // max }; -static SlantBox nullSlant(0, 0, 0, 0); -class BBox +struct BBox { -public: BBox(float pxi = 0, float pyi = 0., float pxa = 0., float pya = 0.) : xi(pxi), yi(pyi), xa(pxa), ya(pya) {}; float width() const { return xa - xi; } float height() const { return ya - yi; } @@ -65,7 +64,6 @@ public: float ya; // max }; -static BBox nullBBox(0, 0, 0, 0); class GlyphBox { @@ -95,8 +93,6 @@ class GlyphCache GlyphCache(const GlyphCache&); GlyphCache& operator=(const GlyphCache&); - static const Rect nullRect; - public: GlyphCache(const Face & face, const uint32 face_options); ~GlyphCache(); @@ -110,7 +106,7 @@ public: float getBoundingMetric(unsigned short glyphid, uint8 metric) const; uint8 numSubBounds(unsigned short glyphid) const; float getSubBoundingMetric(unsigned short glyphid, uint8 subindex, uint8 metric) const; - const Rect & slant(unsigned short glyphid) const { return _boxes[glyphid] ? _boxes[glyphid]->slant() : nullRect; } + const Rect & slant(unsigned short glyphid) const { return _boxes[glyphid] ? _boxes[glyphid]->slant() : _empty_slant_box; } const SlantBox & getBoundingSlantBox(unsigned short glyphid) const; const BBox & getBoundingBBox(unsigned short glyphid) const; const SlantBox & getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const; @@ -120,6 +116,7 @@ public: CLASS_NEW_DELETE; private: + const Rect _empty_slant_box; const Loader * _glyph_loader; const GlyphFace * * _glyphs; GlyphBox * * _boxes; @@ -149,7 +146,7 @@ unsigned short GlyphCache::unitsPerEm() const throw() inline bool GlyphCache::check(unsigned short glyphid) const { - return glyphid < _num_glyphs; + return _boxes && glyphid < _num_glyphs; } inline @@ -177,7 +174,7 @@ float GlyphCache::getBoundingMetric(unsigned short glyphid, uint8 metric) const inline const SlantBox &GlyphCache::getBoundingSlantBox(unsigned short glyphid) const { - return _boxes[glyphid] ? *(SlantBox *)(&(_boxes[glyphid]->slant())) : nullSlant; + return _boxes[glyphid] ? *(SlantBox *)(&(_boxes[glyphid]->slant())) : SlantBox::empty; } inline const BBox &GlyphCache::getBoundingBBox(unsigned short glyphid) const @@ -207,14 +204,12 @@ float GlyphCache::getSubBoundingMetric(unsigned short glyphid, uint8 subindex, u inline const SlantBox &GlyphCache::getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const { GlyphBox *b = _boxes[glyphid]; -// if (b == NULL || subindex >= b->num()) return nullSlant; return *(SlantBox *)(b->subs() + 2 * subindex + 1); } inline const BBox &GlyphCache::getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const { GlyphBox *b = _boxes[glyphid]; -// if (b == NULL || subindex >= b->num()) return nullBBox; return *(BBox *)(b->subs() + 2 * subindex); } diff --git a/gfx/graphite2/src/inc/Intervals.h b/gfx/graphite2/src/inc/Intervals.h index bc9fab65ab1e..34fecce17952 100644 --- a/gfx/graphite2/src/inc/Intervals.h +++ b/gfx/graphite2/src/inc/Intervals.h @@ -144,6 +144,9 @@ inline Zones::Zones() : _margin_len(0), _margin_weight(0), _pos(0), _posm(0) { +#if !defined GRAPHITE2_NTRACING + _dbg = 0; +#endif _exclusions.reserve(8); } diff --git a/gfx/graphite2/src/inc/List.h b/gfx/graphite2/src/inc/List.h index 41e51738c3e9..020560235c15 100644 --- a/gfx/graphite2/src/inc/List.h +++ b/gfx/graphite2/src/inc/List.h @@ -105,6 +105,7 @@ void Vector::reserve(size_t n) { const ptrdiff_t sz = size(); m_first = static_cast(realloc(m_first, n*sizeof(T))); + if (!m_first) std::abort(); m_last = m_first + sz; m_end = m_first + n; } diff --git a/gfx/graphite2/src/inc/Main.h b/gfx/graphite2/src/inc/Main.h index 8ff062a71d64..5c6546916889 100644 --- a/gfx/graphite2/src/inc/Main.h +++ b/gfx/graphite2/src/inc/Main.h @@ -85,7 +85,7 @@ template T * gralloc(size_t n) #ifdef GRAPHITE2_TELEMETRY telemetry::count_bytes(sizeof(T) * n); #endif - return reinterpret_cast(malloc(sizeof(T) * n)); + return static_cast(malloc(sizeof(T) * n)); } template T * grzeroalloc(size_t n) @@ -93,7 +93,7 @@ template T * grzeroalloc(size_t n) #ifdef GRAPHITE2_TELEMETRY telemetry::count_bytes(sizeof(T) * n); #endif - return reinterpret_cast(calloc(n, sizeof(T))); + return static_cast(calloc(n, sizeof(T))); } template @@ -128,5 +128,5 @@ inline T max(const T a, const T b) #ifdef _MSC_VER #pragma warning(disable: 4800) -#pragma warning(once: 4355) +#pragma warning(disable: 4355) #endif diff --git a/gfx/graphite2/src/inc/Pass.h b/gfx/graphite2/src/inc/Pass.h index f0f9a5f12493..c8f1aa20ba5c 100644 --- a/gfx/graphite2/src/inc/Pass.h +++ b/gfx/graphite2/src/inc/Pass.h @@ -53,9 +53,10 @@ public: bool readPass(const byte * pPass, size_t pass_length, size_t subtable_base, Face & face, enum passtype pt, uint32 version, Error &e); - bool runGraphite(vm::Machine & m, FiniteStateMachine & fsm) const; + bool runGraphite(vm::Machine & m, FiniteStateMachine & fsm, bool reverse) const; void init(Silf *silf) { m_silf = silf; } - byte flags() const { return m_flags; } + byte collisionLoops() const { return m_numCollRuns; } + bool reverseDir() const { return m_isReverseDir; } CLASS_NEW_DELETE private: @@ -73,7 +74,7 @@ private: uint16 glyphToCol(const uint16 gid) const; bool runFSM(FiniteStateMachine & fsm, Slot * slot) const; void dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const; - void dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * os) const; + void dumpRuleEventOutput(const FiniteStateMachine & fsm, vm::Machine & m, const Rule & r, Slot * os) const; void adjustSlot(int delta, Slot * & slot_out, SlotMap &) const; bool collisionShift(Segment *seg, int dir, json * const dbgout) const; bool collisionKern(Segment *seg, int dir, json * const dbgout) const; @@ -93,7 +94,8 @@ private: vm::Machine::Code * m_codes; byte * m_progs; - byte m_flags; + byte m_numCollRuns; + byte m_kernColls; byte m_iMaxLoop; uint16 m_numGlyphs; uint16 m_numRules; @@ -105,6 +107,7 @@ private: byte m_minPreCtxt; byte m_maxPreCtxt; byte m_colThreshold; + bool m_isReverseDir; vm::Machine::Code m_cPConstraint; private: //defensive diff --git a/gfx/graphite2/src/inc/Rule.h b/gfx/graphite2/src/inc/Rule.h index caec236274b5..36c8d89a63d2 100644 --- a/gfx/graphite2/src/inc/Rule.h +++ b/gfx/graphite2/src/inc/Rule.h @@ -41,8 +41,8 @@ struct Rule { uint16 rule_idx; #endif - Rule() : constraint(0), action(0), sort(0), preContext(0) {} - ~Rule(); + Rule(); + ~Rule() {} CLASS_NEW_DELETE; @@ -51,8 +51,16 @@ private: Rule & operator = (const Rule &); }; -inline Rule::~Rule() +inline +Rule::Rule() +: constraint(0), + action(0), + sort(0), + preContext(0) { +#ifndef NDEBUG + rule_idx = 0; +#endif } @@ -94,7 +102,7 @@ class SlotMap { public: enum {MAX_SLOTS=64}; - SlotMap(Segment & seg); + SlotMap(Segment & seg, uint8 direction); Slot * * begin(); Slot * * end(); @@ -105,19 +113,22 @@ public: Slot * const & operator[](int n) const; Slot * & operator [] (int); void pushSlot(Slot * const slot); - void collectGarbage(); + void collectGarbage(Slot *& aSlot); Slot * highwater() { return m_highwater; } void highwater(Slot *s) { m_highwater = s; m_highpassed = false; } bool highpassed() const { return m_highpassed; } void highpassed(bool v) { m_highpassed = v; } + uint8 dir() const { return m_dir; } + Segment & segment; private: Slot * m_slot_map[MAX_SLOTS+1]; unsigned short m_size; unsigned short m_precontext; Slot * m_highwater; + uint8 m_dir; bool m_highpassed; }; @@ -231,8 +242,8 @@ void FiniteStateMachine::Rules::accumulate_rules(const State &state) } inline -SlotMap::SlotMap(Segment & seg) -: segment(seg), m_size(0), m_precontext(0), m_highwater(0), m_highpassed(false) +SlotMap::SlotMap(Segment & seg, uint8 direction) +: segment(seg), m_size(0), m_precontext(0), m_highwater(0), m_dir(direction), m_highpassed(false) { m_slot_map[0] = 0; } diff --git a/gfx/graphite2/src/inc/SegCache.h b/gfx/graphite2/src/inc/SegCache.h index ad48258d0535..b360f7c9337c 100644 --- a/gfx/graphite2/src/inc/SegCache.h +++ b/gfx/graphite2/src/inc/SegCache.h @@ -263,7 +263,7 @@ private: unsigned long long minAccessCount, unsigned long long oldAccessTime); uint16 m_prefixLength; - uint16 m_maxCachedSegLength; +// uint16 m_maxCachedSegLength; size_t m_segmentCount; SegCachePrefixArray m_prefixes; Features m_features; diff --git a/gfx/graphite2/src/inc/Segment.h b/gfx/graphite2/src/inc/Segment.h index b814c5f0f9e2..08f6afdd7114 100644 --- a/gfx/graphite2/src/inc/Segment.h +++ b/gfx/graphite2/src/inc/Segment.h @@ -39,7 +39,7 @@ of the License or (at your option) any later version. #include "inc/Slot.h" #include "inc/Position.h" #include "inc/List.h" -#include "inc/Bidi.h" +//#include "inc/Bidi.h" #include "inc/Collider.h" #define MAX_SEG_GROWTH_FACTOR 256 @@ -48,7 +48,7 @@ namespace graphite2 { typedef Vector FeatureList; typedef Vector SlotRope; -typedef Vector AttributeRope; +typedef Vector AttributeRope; typedef Vector JustifyRope; #ifndef GRAPHITE2_NSEGCACHE @@ -101,7 +101,6 @@ public: unsigned int charInfoCount() const { return m_numCharinfo; } const CharInfo *charinfo(unsigned int index) const { return index < m_numCharinfo ? m_charinfo + index : NULL; } CharInfo *charinfo(unsigned int index) { return index < m_numCharinfo ? m_charinfo + index : NULL; } - int8 dir() const { return m_dir; } Segment(unsigned int numchars, const Face* face, uint32 script, int dir); ~Segment(); @@ -124,7 +123,7 @@ public: void freeSlot(Slot *); SlotJustify *newJustify(); void freeJustify(SlotJustify *aJustify); - Position positionSlots(const Font *font=0, Slot *first=0, Slot *last=0, bool isFinal = true); + Position positionSlots(const Font *font=0, Slot *first=0, Slot *last=0, bool isRtl = false, bool isFinal = true); void associateChars(int offset, int num); void linkClusters(Slot *first, Slot *last); uint16 getClassGlyph(uint16 cid, uint16 offset) const { return m_silf->getClassGlyph(cid, offset); } @@ -138,11 +137,13 @@ public: if (val > pFR->maxVal()) val = pFR->maxVal(); pFR->applyValToFeature(val, m_feats[index]); } } + int8 dir() const { return m_dir; } void dir(int8 val) { m_dir = val; } + bool currdir() const { return ((m_dir >> 6) ^ m_dir) & 1; } unsigned int passBits() const { return m_passBits; } void mergePassBits(const unsigned int val) { m_passBits &= val; } int16 glyphAttr(uint16 gid, uint16 gattr) const { const GlyphFace * p = m_face->glyphs().glyphSafe(gid); return p ? p->attrs()[gattr] : 0; } - int32 getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel) const; + int32 getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel, bool rtl) const; float glyphAdvance(uint16 gid) const { return m_face->glyphs().glyph(gid)->theAdvance().x; } const Rect &theGlyphBBoxTemporary(uint16 gid) const { return m_face->glyphs().glyph(gid)->theBBox(); } //warning value may become invalid when another glyph is accessed Slot *findRoot(Slot *is) const { return is->attachedTo() ? findRoot(is->attachedTo()) : is; } @@ -150,10 +151,13 @@ public: int defaultOriginal() const { return m_defaultOriginal; } const Face * getFace() const { return m_face; } const Features & getFeatures(unsigned int /*charIndex*/) { assert(m_feats.size() == 1); return m_feats[0]; } - void bidiPass(uint8 aBidi, int paradir, uint8 aMirror); + void bidiPass(int paradir, uint8 aMirror); + int8 getSlotBidiClass(Slot *s) const; + void doMirror(uint16 aMirror); Slot *addLineEnd(Slot *nSlot); void delLineEnd(Slot *s); bool hasJustification() const { return m_justifies.size() != 0; } + void reverseSlots(); bool isWhitespace(const int cid) const; bool hasCollisionInfo() const { return m_collisions != 0; } @@ -163,7 +167,7 @@ public: public: //only used by: GrSegment* makeAndInitialize(const GrFont *font, const GrFace *face, uint32 script, const FeaturesHandle& pFeats/*must not be IsNull*/, encform enc, const void* pStart, size_t nChars, int dir); bool read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void*pStart, size_t nChars); - void finalise(const Font *font); + void finalise(const Font *font, bool reverse=false); float justify(Slot *pSlot, const Font *font, float width, enum justFlags flags, Slot *pFirst, Slot *pLast); bool initCollisions(); @@ -190,24 +194,34 @@ private: uint8 m_flags; // General purpose flags }; - +inline +int8 Segment::getSlotBidiClass(Slot *s) const +{ + int8 res = s->getBidiClass(); + if (res != -1) return res; + res = glyphAttr(s->gid(), m_silf->aBidi()); + s->setBidiClass(res); + return res; +} inline -void Segment::finalise(const Font *font) +void Segment::finalise(const Font *font, bool reverse) { if (!m_first) return; - m_advance = positionSlots(font); + m_advance = positionSlots(font, m_first, m_last, m_silf->dir(), true); //associateChars(0, m_numCharinfo); + if (reverse && currdir() != (m_dir & 1)) + reverseSlots(); linkClusters(m_first, m_last); } inline -int32 Segment::getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel) const { +int32 Segment::getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel, bool rtl) const { if (attrLevel > 0) { Slot *is = findRoot(iSlot); - return is->clusterMetric(this, metric, attrLevel); + return is->clusterMetric(this, metric, attrLevel, rtl); } else return m_face->getGlyphMetric(iSlot->gid(), metric); diff --git a/gfx/graphite2/src/inc/Silf.h b/gfx/graphite2/src/inc/Silf.h index a31d4bf35f98..8e49f70c942e 100644 --- a/gfx/graphite2/src/inc/Silf.h +++ b/gfx/graphite2/src/inc/Silf.h @@ -94,6 +94,7 @@ public: uint8 maxCompPerLig() const { return m_iMaxComp; } uint16 numClasses() const { return m_nClass; } byte flags() const { return m_flags; } + byte dir() const { return m_dir; } uint8 numJustLevels() const { return m_numJusts; } Justinfo *justAttrs() const { return m_justs; } uint16 endLineGlyphid() const { return m_gEndLine; } @@ -113,7 +114,7 @@ private: uint8 m_numPasses; uint8 m_numJusts; uint8 m_sPass, m_pPass, m_jPass, m_bPass, - m_flags; + m_flags, m_dir; uint8 m_aPseudo, m_aBreak, m_aUser, m_aBidi, m_aMirror, m_aPassBits, m_iMaxComp, m_aCollision; diff --git a/gfx/graphite2/src/inc/Slot.h b/gfx/graphite2/src/inc/Slot.h index 65ee5af8bc87..a6e05491c6d8 100644 --- a/gfx/graphite2/src/inc/Slot.h +++ b/gfx/graphite2/src/inc/Slot.h @@ -32,15 +32,13 @@ of the License or (at your option) any later version. #include "inc/Font.h" #include "inc/Position.h" - - namespace graphite2 { typedef gr_attrCode attrCode; class GlyphFace; -class Segment; class SegCacheEntry; +class Segment; struct SlotJustify { @@ -82,7 +80,7 @@ public: uint32 index() const { return m_index; } void index(uint32 val) { m_index = val; } - Slot(); + Slot(int16 *m_userAttr = NULL); void set(const Slot & slot, int charOffset, size_t numUserAttr, size_t justLevels, size_t numChars); Slot *next() const { return m_next; } void next(Slot *s) { m_next = s; } @@ -99,7 +97,7 @@ public: void after(int ind) { m_after = ind; } bool isBase() const { return (!m_parent); } void update(int numSlots, int numCharInfo, Position &relpos); - Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool isFinal); + Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal); bool isDeleted() const { return (m_flags & DELETED) ? true : false; } void markDeleted(bool state) { if (state) m_flags |= DELETED; else m_flags &= ~DELETED; } bool isCopied() const { return (m_flags & COPIED) ? true : false; } @@ -109,6 +107,7 @@ public: bool isInsertBefore() const { return !(m_flags & INSERTED); } uint8 getBidiLevel() const { return m_bidiLevel; } void setBidiLevel(uint8 level) { m_bidiLevel = level; } + int8 getBidiClass(const Segment *seg); int8 getBidiClass() const { return m_bidiCls; } void setBidiClass(int8 cls) { m_bidiCls = cls; } int16 *userAttrs() const { return m_userAttr; } @@ -130,7 +129,7 @@ public: bool sibling(Slot *ap); bool removeChild(Slot *ap); bool removeSibling(Slot *ap); - int32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel); + int32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel, bool rtl); void positionShift(Position a) { m_position += a; } void floodShift(Position adj); float just() const { return m_just; } diff --git a/gfx/graphite2/src/inc/Sparse.h b/gfx/graphite2/src/inc/Sparse.h index b87ab88f3c82..2c9248f3272d 100644 --- a/gfx/graphite2/src/inc/Sparse.h +++ b/gfx/graphite2/src/inc/Sparse.h @@ -56,7 +56,7 @@ private: key_type offset; }; - static chunk empty_chunk; + static const chunk empty_chunk; sparse(const sparse &); sparse & operator = (const sparse &); @@ -88,7 +88,7 @@ private: inline sparse::sparse() throw() : m_nchunks(0) { - m_array.map = &empty_chunk; + m_array.map = const_cast(&empty_chunk); } @@ -113,7 +113,7 @@ sparse::sparse(I attr, const I last) } if (m_nchunks == 0) { - m_array.map=&empty_chunk; + m_array.map=const_cast(&empty_chunk); return; } diff --git a/gfx/graphite2/src/inc/TtfUtil.h b/gfx/graphite2/src/inc/TtfUtil.h index 428dea09f13a..43ef2daa9edc 100644 --- a/gfx/graphite2/src/inc/TtfUtil.h +++ b/gfx/graphite2/src/inc/TtfUtil.h @@ -137,11 +137,11 @@ public: ////////////////////////////////// cmap lookup tools const void * FindCmapSubtable(const void * pCmap, int nPlatformId = 3, int nEncodingId = 1, size_t length = 0); - bool CheckCmapSubtable4(const void * pCmap31 /*, unsigned int maxgid*/); + bool CheckCmapSubtable4(const void * pCmap31, size_t table_len /*, unsigned int maxgid*/); gid16 CmapSubtable4Lookup(const void * pCmapSubtabel4, unsigned int nUnicodeId, int rangeKey = 0); unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnicodeId, int * pRangeKey = 0); - bool CheckCmapSubtable12(const void *pCmap310 /*, unsigned int maxgid*/); + bool CheckCmapSubtable12(const void *pCmap310, size_t table_len /*, unsigned int maxgid*/); gid16 CmapSubtable12Lookup(const void * pCmap310, unsigned int uUnicodeId, int rangeKey = 0); unsigned int CmapSubtable12NextCodepoint(const void *pCmap310, unsigned int nUnicodeId, int * pRangeKey = 0); diff --git a/gfx/graphite2/src/inc/opcodes.h b/gfx/graphite2/src/inc/opcodes.h index 1c36c301b641..ec84b5175851 100644 --- a/gfx/graphite2/src/inc/opcodes.h +++ b/gfx/graphite2/src/inc/opcodes.h @@ -61,6 +61,7 @@ of the License or (at your option) any later version. // isl = The last positioned slot // ip = The current instruction pointer // endPos = Position of advance of last cluster +// dir = writing system directionality of the font // #define NOT_IMPLEMENTED assert(false) @@ -313,6 +314,8 @@ STARTOP(insert) { newSlot->originate(seg.defaultOriginal()); } + if (is == smap.highwater()) + smap.highpassed(false); is = newSlot; seg.extendLength(1); if (map != &smap[-1]) @@ -389,7 +392,7 @@ STARTOP(attr_add) const int val = int(pop()); if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) { - seg.positionSlots(0, *smap.begin(), *(smap.end()-1)); + seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir); flags |= POSITIONED; } int res = is->getAttr(&seg, slat, 0); @@ -402,7 +405,7 @@ STARTOP(attr_sub) const int val = int(pop()); if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) { - seg.positionSlots(0, *smap.begin(), *(smap.end()-1)); + seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir); flags |= POSITIONED; } int res = is->getAttr(&seg, slat, 0); @@ -431,7 +434,7 @@ STARTOP(push_slot_attr) const int slot_ref = int8(param[1]); if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) { - seg.positionSlots(0, *smap.begin(), *(smap.end()-1)); + seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir); flags |= POSITIONED; } slotref slot = slotat(slot_ref); @@ -458,7 +461,7 @@ STARTOP(push_glyph_metric) const signed int attr_level = uint8(param[2]); slotref slot = slotat(slot_ref); if (slot) - push(seg.getGlyphMetric(slot, glyph_attr, attr_level)); + push(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir)); ENDOP STARTOP(push_feat) @@ -496,7 +499,7 @@ STARTOP(push_att_to_glyph_metric) { slotref att = slot->attachedTo(); if (att) slot = att; - push(int32(seg.getGlyphMetric(slot, glyph_attr, attr_level))); + push(int32(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir))); } ENDOP @@ -507,7 +510,7 @@ STARTOP(push_islot_attr) idx = uint8(param[2]); if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) { - seg.positionSlots(0, *smap.begin(), *(smap.end()-1)); + seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir); flags |= POSITIONED; } slotref slot = slotat(slot_ref); @@ -552,7 +555,7 @@ STARTOP(iattr_add) const int val = int(pop()); if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) { - seg.positionSlots(0, *smap.begin(), *(smap.end()-1)); + seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir); flags |= POSITIONED; } int res = is->getAttr(&seg, slat, idx); @@ -566,7 +569,7 @@ STARTOP(iattr_sub) const int val = int(pop()); if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) { - seg.positionSlots(0, *smap.begin(), *(smap.end()-1)); + seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir); flags |= POSITIONED; } int res = is->getAttr(&seg, slat, idx); From b45a7983d029c264a234e470a2de259c0e496e79 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 11 Sep 2015 12:31:59 +0100 Subject: [PATCH 009/131] Bug 1200098 - patch 2 - Remove the data-shrinker copyright notice that was added for graphite 1.3.0; no longer present in release 1.3.2. r=gerv --- toolkit/content/license.html | 45 ------------------------------------ 1 file changed, 45 deletions(-) diff --git a/toolkit/content/license.html b/toolkit/content/license.html index 6552195c212c..5eeff0884963 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -85,7 +85,6 @@
  • cubic-bezier License
  • D3 License
  • Dagre-D3 License
  • -
  • data-shrinker License
  • dtoa License
  • Dutch Spellchecking Dictionary License
  • Estonian Spellchecking Dictionary License
  • @@ -2857,50 +2856,6 @@ THE SOFTWARE. -
    - -

    data-shrinker License

    - -

    This license applies to the files: -

    -
      -
    • gfx/graphite2/src/Decompressor.cpp
    • -
    • gfx/graphite2/src/inc/Decompressor.h
    • -
    - -
    -Copyright (c) 2012, Siyuan Fu <fusiyuan2010@gmail.com>
    -Copyright (c) 2015, SIL International
    -All rights reserved.
    -
    -Redistribution and use in source and binary forms, with or without
    -modification, are permitted provided that the following conditions are met:
    -
    -1. Redistributions of source code must retain the above copyright notice,
    -   this list of conditions and the following disclaimer.
    -
    -2. Redistributions in binary form must reproduce the above copyright
    -   notice, this list of conditions and the following disclaimer in the
    -   documentation and/or other materials provided with the distribution.
    -
    -3. Neither the name of the copyright holder nor the names of its
    -   contributors may be used to endorse or promote products derived from
    -   this software without specific prior written permission.
    -
    -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    -POSSIBILITY OF SUCH DAMAGE.
    -
    - -

    dtoa License

    From 6bd9c973edce73bc952f6b1053e1d1e5e79eceaa Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 11 Sep 2015 12:32:00 +0100 Subject: [PATCH 010/131] Bug 1200098 - patch 3 - Pass the gr_nobidi flag when shaping with graphite2, as we split text into unidirectional runs ahead of time. r=jdaggett --- gfx/thebes/gfxGraphiteShaper.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gfx/thebes/gfxGraphiteShaper.cpp b/gfx/thebes/gfxGraphiteShaper.cpp index ac1a71360db7..ee7b4db3a5fc 100644 --- a/gfx/thebes/gfxGraphiteShaper.cpp +++ b/gfx/thebes/gfxGraphiteShaper.cpp @@ -165,9 +165,10 @@ gfxGraphiteShaper::ShapeText(gfxContext *aContext, size_t numChars = gr_count_unicode_characters(gr_utf16, aText, aText + aLength, nullptr); + gr_bidirtl grBidi = gr_bidirtl(aShapedText->IsRightToLeft() + ? (gr_rtl | gr_nobidi) : gr_nobidi); gr_segment *seg = gr_make_seg(mGrFont, mGrFace, 0, grFeatures, - gr_utf16, aText, numChars, - aShapedText->IsRightToLeft()); + gr_utf16, aText, numChars, grBidi); gr_featureval_destroy(grFeatures); From f1b7fd9686ebe0a07f83cd008f1fddbe88e6b485 Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Fri, 11 Sep 2015 13:43:29 +0200 Subject: [PATCH 011/131] Bug 1176288 - Part 4: Fix octane regression, r=bbouvier --- js/src/jit/IonBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index a5eda475d689..308b1021164b 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -4066,7 +4066,7 @@ IonBuilder::processCondSwitchCase(CFGState& state) MDefinition* caseOperand = current->pop(); MDefinition* switchOperand = current->peek(-1); - if (jsop_compare(JSOP_STRICTEQ, switchOperand, caseOperand)) + if (!jsop_compare(JSOP_STRICTEQ, switchOperand, caseOperand)) return ControlStatus_Error; MInstruction* cmpResult = current->pop()->toInstruction(); MOZ_ASSERT(!cmpResult->isEffectful()); From 5ba59fca687d9e85f17a579d349f6c07cb1c8056 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Fri, 11 Sep 2015 13:47:50 +0200 Subject: [PATCH 012/131] Bug 1199719 mips - Add missing return in Assembler::haltingAlign. r=hev --- js/src/jit/mips32/Assembler-mips32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jit/mips32/Assembler-mips32.cpp b/js/src/jit/mips32/Assembler-mips32.cpp index cff988a8206a..797784d47a19 100644 --- a/js/src/jit/mips32/Assembler-mips32.cpp +++ b/js/src/jit/mips32/Assembler-mips32.cpp @@ -560,7 +560,7 @@ BufferOffset Assembler::haltingAlign(int alignment) { // TODO: Implement a proper halting align. - nopAlign(alignment); + return nopAlign(alignment); } BufferOffset From c7480c1b1cbf343385db75d2595d9e00dfe89533 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Fri, 11 Sep 2015 13:47:51 +0200 Subject: [PATCH 013/131] Bug 1199719 werr - Remove some of the uninitialized variable noise. r=jorendorff --- js/src/asmjs/AsmJSValidate.cpp | 2 +- js/src/frontend/Parser.cpp | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 0eaf9da171ca..64f36a9c5cc8 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -2699,7 +2699,7 @@ ExtractSimdValue(ModuleValidator& m, ParseNode* pn) { MOZ_ASSERT(IsSimdLiteral(m, pn)); - AsmJSSimdType type; + AsmJSSimdType type = AsmJSSimdType_int32x4; JS_ALWAYS_TRUE(IsSimdTuple(m, pn, &type)); ParseNode* arg = CallArgList(pn); diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 797a35f7f3d3..f2a2f33c5569 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1456,7 +1456,7 @@ Parser::newFunction(HandleAtom atom, FunctionSyntaxKind kind, static bool MatchOrInsertSemicolon(TokenStream& ts, TokenStream::Modifier modifier = TokenStream::None) { - TokenKind tt; + TokenKind tt = TOK_EOF; if (!ts.peekTokenSameLine(&tt, modifier)) return false; if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) { @@ -3083,9 +3083,9 @@ Parser::statements(YieldHandling yieldHandling) bool canHaveDirectives = pc->atBodyLevel(); bool afterReturn = false; bool warnedAboutStatementsAfterReturn = false; - uint32_t statementBegin; + uint32_t statementBegin = 0; for (;;) { - TokenKind tt; + TokenKind tt = TOK_EOF; if (!tokenStream.peekToken(&tt, TokenStream::Operand)) { if (tokenStream.isEOF()) isUnexpectedEOF_ = true; @@ -3161,7 +3161,7 @@ template bool Parser::matchLabel(YieldHandling yieldHandling, MutableHandle label) { - TokenKind tt; + TokenKind tt = TOK_EOF; if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return false; @@ -5650,7 +5650,7 @@ Parser::switchStatement(YieldHandling yieldHandling) bool afterReturn = false; bool warnedAboutStatementsAfterReturn = false; - uint32_t statementBegin; + uint32_t statementBegin = 0; while (true) { if (!tokenStream.peekToken(&tt, TokenStream::Operand)) return null(); @@ -5813,7 +5813,7 @@ Parser::returnStatement(YieldHandling yieldHandling) // // This is ugly, but we don't want to require a semicolon. Node exprNode; - TokenKind tt; + TokenKind tt = TOK_EOF; if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return null(); TokenStream::Modifier modifier = TokenStream::Operand; @@ -5893,7 +5893,7 @@ Parser::yieldExpression(InHandling inHandling) Node exprNode; ParseNodeKind kind = PNK_YIELD; - TokenKind tt; + TokenKind tt = TOK_EOF; if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return null(); switch (tt) { @@ -5962,7 +5962,7 @@ Parser::yieldExpression(InHandling inHandling) // Legacy generators do not require a value. Node exprNode; - TokenKind tt; + TokenKind tt = TOK_EOF; if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return null(); switch (tt) { @@ -6093,7 +6093,7 @@ Parser::throwStatement(YieldHandling yieldHandling) uint32_t begin = pos().begin; /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */ - TokenKind tt; + TokenKind tt = TOK_EOF; if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return null(); if (tt == TOK_EOF || tt == TOK_SEMI || tt == TOK_RC) { @@ -7069,7 +7069,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl case TOK_ARROW: { // A line terminator between ArrowParameters and the => should trigger a SyntaxError. tokenStream.ungetToken(); - TokenKind next; + TokenKind next = TOK_EOF; if (!tokenStream.peekTokenSameLine(&next) || next != TOK_ARROW) { report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TOK_ARROW)); @@ -7179,7 +7179,7 @@ Parser::reportIfNotValidSimpleAssignmentTarget(Node target, Assign return false; } - unsigned errnum; + unsigned errnum = 0; const char* extra = nullptr; switch (flavor) { From 17e7e8a931d4ecfd95d410287dfce7dfa13818c7 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Fri, 11 Sep 2015 13:47:51 +0200 Subject: [PATCH 014/131] Bug 1199719 werr.2 - Remove some of the uninitialized variable noise. r=bbouvier --- js/src/asmjs/AsmJSModule.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/src/asmjs/AsmJSModule.cpp b/js/src/asmjs/AsmJSModule.cpp index 203e04a0aa1d..acabcd1fe561 100644 --- a/js/src/asmjs/AsmJSModule.cpp +++ b/js/src/asmjs/AsmJSModule.cpp @@ -1438,7 +1438,9 @@ AsmJSModule::CodeRange::CodeRange(AsmJSExit::BuiltinKind builtin, uint32_t begin void AsmJSModule::CodeRange::updateOffsets(jit::MacroAssembler& masm) { - uint32_t entryBefore, profilingJumpBefore, profilingEpilogueBefore; + uint32_t entryBefore = 0; + uint32_t profilingJumpBefore = 0; + uint32_t profilingEpilogueBefore = 0; if (isFunction()) { entryBefore = entry(); profilingJumpBefore = profilingJump(); From 57a0322b5667150804a55248cea1a5e5268cf720 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Fri, 11 Sep 2015 13:47:52 +0200 Subject: [PATCH 015/131] Bug 1199719 part 0 - Add jit//MacroAssembler--inl.h files. r=jandem --- js/src/jit/MacroAssembler-inl.h | 14 ++++++++++ js/src/jit/arm/MacroAssembler-arm-inl.h | 25 +++++++++++++++++ js/src/jit/arm64/MacroAssembler-arm64-inl.h | 25 +++++++++++++++++ js/src/jit/mips32/MacroAssembler-mips32-inl.h | 25 +++++++++++++++++ js/src/jit/x64/MacroAssembler-x64-inl.h | 27 +++++++++++++++++++ .../MacroAssembler-x86-shared-inl.h | 25 +++++++++++++++++ js/src/jit/x86/MacroAssembler-x86-inl.h | 27 +++++++++++++++++++ 7 files changed, 168 insertions(+) create mode 100644 js/src/jit/arm/MacroAssembler-arm-inl.h create mode 100644 js/src/jit/arm64/MacroAssembler-arm64-inl.h create mode 100644 js/src/jit/mips32/MacroAssembler-mips32-inl.h create mode 100644 js/src/jit/x64/MacroAssembler-x64-inl.h create mode 100644 js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h create mode 100644 js/src/jit/x86/MacroAssembler-x86-inl.h diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h index 714a6676abb9..a3330103c18d 100644 --- a/js/src/jit/MacroAssembler-inl.h +++ b/js/src/jit/MacroAssembler-inl.h @@ -9,6 +9,20 @@ #include "jit/MacroAssembler.h" +#if defined(JS_CODEGEN_X86) +# include "jit/x86/MacroAssembler-x86-inl.h" +#elif defined(JS_CODEGEN_X64) +# include "jit/x64/MacroAssembler-x64-inl.h" +#elif defined(JS_CODEGEN_ARM) +# include "jit/arm/MacroAssembler-arm-inl.h" +#elif defined(JS_CODEGEN_ARM64) +# include "jit/arm64/MacroAssembler-arm64-inl.h" +#elif defined(JS_CODEGEN_MIPS32) +# include "jit/mips32/MacroAssembler-mips32-inl.h" +#elif !defined(JS_CODEGEN_NONE) +# error "Unknown architecture!" +#endif + namespace js { namespace jit { diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h new file mode 100644 index 000000000000..7a6462a1c341 --- /dev/null +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_arm_MacroAssembler_arm_inl_h +#define jit_arm_MacroAssembler_arm_inl_h + +#include "jit/arm/MacroAssembler-arm.h" + +namespace js { +namespace jit { + +//{{{ check_macroassembler_style +// =============================================================== + + +//}}} check_macroassembler_style +// =============================================================== + +} // namespace jit +} // namespace js + +#endif /* jit_arm_MacroAssembler_arm_inl_h */ diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h new file mode 100644 index 000000000000..4e61aad44890 --- /dev/null +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_arm64_MacroAssembler_arm64_inl_h +#define jit_arm64_MacroAssembler_arm64_inl_h + +#include "jit/arm64/MacroAssembler-arm64.h" + +namespace js { +namespace jit { + +//{{{ check_macroassembler_style +// =============================================================== + + +//}}} check_macroassembler_style +// =============================================================== + +} // namespace jit +} // namespace js + +#endif /* jit_arm64_MacroAssembler_arm64_inl_h */ diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h new file mode 100644 index 000000000000..514c763f8273 --- /dev/null +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_mips32_MacroAssembler_mips32_inl_h +#define jit_mips32_MacroAssembler_mips32_inl_h + +#include "jit/mips32/MacroAssembler-mips32.h" + +namespace js { +namespace jit { + +//{{{ check_macroassembler_style +// =============================================================== + + +//}}} check_macroassembler_style +// =============================================================== + +} // namespace jit +} // namespace js + +#endif /* jit_mips32_MacroAssembler_mips32_inl_h */ diff --git a/js/src/jit/x64/MacroAssembler-x64-inl.h b/js/src/jit/x64/MacroAssembler-x64-inl.h new file mode 100644 index 000000000000..9af5917244cd --- /dev/null +++ b/js/src/jit/x64/MacroAssembler-x64-inl.h @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_x64_MacroAssembler_x64_inl_h +#define jit_x64_MacroAssembler_x64_inl_h + +#include "jit/x64/MacroAssembler-x64.h" + +#include "jit/x86-shared/MacroAssembler-x86-shared-inl.h" + +namespace js { +namespace jit { + +//{{{ check_macroassembler_style +// =============================================================== + + +//}}} check_macroassembler_style +// =============================================================== + +} // namespace jit +} // namespace js + +#endif /* jit_x64_MacroAssembler_x64_inl_h */ diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h new file mode 100644 index 000000000000..19dbdd68d42f --- /dev/null +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_x86_shared_MacroAssembler_x86_shared_inl_h +#define jit_x86_shared_MacroAssembler_x86_shared_inl_h + +#include "jit/x86-shared/MacroAssembler-x86-shared.h" + +namespace js { +namespace jit { + +//{{{ check_macroassembler_style +// =============================================================== + + +//}}} check_macroassembler_style +// =============================================================== + +} // namespace jit +} // namespace js + +#endif /* jit_x86_shared_MacroAssembler_x86_shared_inl_h */ diff --git a/js/src/jit/x86/MacroAssembler-x86-inl.h b/js/src/jit/x86/MacroAssembler-x86-inl.h new file mode 100644 index 000000000000..10539791e9ee --- /dev/null +++ b/js/src/jit/x86/MacroAssembler-x86-inl.h @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_x86_MacroAssembler_x86_inl_h +#define jit_x86_MacroAssembler_x86_inl_h + +#include "jit/x86/MacroAssembler-x86.h" + +#include "jit/x86-shared/MacroAssembler-x86-shared-inl.h" + +namespace js { +namespace jit { + +//{{{ check_macroassembler_style +// =============================================================== + + +//}}} check_macroassembler_style +// =============================================================== + +} // namespace jit +} // namespace js + +#endif /* jit_x86_MacroAssembler_x86_inl_h */ From 0637b8dce56d8f9652b6fed6c01c344b720cf016 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Fri, 11 Sep 2015 13:47:52 +0200 Subject: [PATCH 016/131] Bug 1199719 part 1 - Move MacroAssembler::and32 into the generic macro assembler. r=h4writer --- js/src/jit/MacroAssembler-inl.h | 16 ++++++++ js/src/jit/MacroAssembler.h | 26 ++++++------- js/src/jit/arm/MacroAssembler-arm-inl.h | 29 ++++++++++++++ js/src/jit/arm/MacroAssembler-arm.cpp | 29 -------------- js/src/jit/arm/MacroAssembler-arm.h | 4 -- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 39 +++++++++++++++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 25 ------------ js/src/jit/mips32/MacroAssembler-mips32-inl.h | 27 +++++++++++++ js/src/jit/mips32/MacroAssembler-mips32.cpp | 27 ------------- js/src/jit/mips32/MacroAssembler-mips32.h | 4 -- js/src/jit/none/MacroAssembler-none.h | 1 - .../MacroAssembler-x86-shared-inl.h | 24 ++++++++++++ .../x86-shared/MacroAssembler-x86-shared.h | 12 ------ 13 files changed, 147 insertions(+), 116 deletions(-) diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h index a3330103c18d..670830c6ec3e 100644 --- a/js/src/jit/MacroAssembler-inl.h +++ b/js/src/jit/MacroAssembler-inl.h @@ -269,6 +269,22 @@ MacroAssembler::hasSelfReference() const //}}} check_macroassembler_style // =============================================================== +void +MacroAssembler::branchFunctionKind(Condition cond, JSFunction::FunctionKind kind, Register fun, + Register scratch, Label* label) +{ + // 16-bit loads are slow and unaligned 32-bit loads may be too so + // perform an aligned 32-bit load and adjust the bitmask accordingly. + MOZ_ASSERT(JSFunction::offsetOfNargs() % sizeof(uint32_t) == 0); + MOZ_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2); + Address address(fun, JSFunction::offsetOfNargs()); + int32_t mask = IMM32_16ADJ(JSFunction::FUNCTION_KIND_MASK); + int32_t bit = IMM32_16ADJ(kind << JSFunction::FUNCTION_KIND_SHIFT); + load32(address, scratch); + and32(Imm32(mask), scratch); + branch32(cond, scratch, Imm32(bit), label); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 1b50c71ba451..6d5b5c5159db 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -655,6 +655,16 @@ class MacroAssembler : public MacroAssemblerSpecific // This is a reference to a patch location where the JitCode* will be written. CodeOffsetLabel selfReferencePatch_; + public: + // =============================================================== + // Logical instructions + + inline void and32(Register src, Register dest) PER_SHARED_ARCH; + inline void and32(Imm32 imm, Register dest) PER_SHARED_ARCH; + inline void and32(Imm32 imm, Register src, Register dest) DEFINED_ON(arm64); + inline void and32(Imm32 imm, const Address& dest) PER_SHARED_ARCH; + inline void and32(const Address& src, Register dest) PER_SHARED_ARCH; + //}}} check_macroassembler_style public: @@ -1182,20 +1192,8 @@ class MacroAssembler : public MacroAssemblerSpecific branchTestClassIsProxy(proxy, scratch, label); } - void branchFunctionKind(Condition cond, JSFunction::FunctionKind kind, Register fun, - Register scratch, Label* label) - { - // 16-bit loads are slow and unaligned 32-bit loads may be too so - // perform an aligned 32-bit load and adjust the bitmask accordingly. - MOZ_ASSERT(JSFunction::offsetOfNargs() % sizeof(uint32_t) == 0); - MOZ_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2); - Address address(fun, JSFunction::offsetOfNargs()); - int32_t mask = IMM32_16ADJ(JSFunction::FUNCTION_KIND_MASK); - int32_t bit = IMM32_16ADJ(kind << JSFunction::FUNCTION_KIND_SHIFT); - load32(address, scratch); - and32(Imm32(mask), scratch); - branch32(cond, scratch, Imm32(bit), label); - } + inline void branchFunctionKind(Condition cond, JSFunction::FunctionKind kind, Register fun, + Register scratch, Label* label); public: #ifndef JS_CODEGEN_ARM64 diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 7a6462a1c341..fd3a72a7ca98 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -14,7 +14,36 @@ namespace jit { //{{{ check_macroassembler_style // =============================================================== +// Logical instructions +void +MacroAssembler::and32(Register src, Register dest) +{ + ma_and(src, dest, SetCC); +} + +void +MacroAssembler::and32(Imm32 imm, Register dest) +{ + ma_and(imm, dest, SetCC); +} + +void +MacroAssembler::and32(Imm32 imm, const Address& dest) +{ + ScratchRegisterScope scratch(*this); + load32(dest, scratch); + ma_and(imm, scratch); + store32(scratch, dest); +} + +void +MacroAssembler::and32(const Address& src, Register dest) +{ + ScratchRegisterScope scratch(*this); + load32(src, scratch); + ma_and(scratch, dest, SetCC); +} //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index d22d62c94784..7711b124ac04 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -1939,26 +1939,6 @@ MacroAssemblerARMCompat::sub32(Register src, Register dest) ma_sub(src, dest, SetCC); } -void -MacroAssemblerARMCompat::and32(Register src, Register dest) -{ - ma_and(src, dest, SetCC); -} - -void -MacroAssemblerARMCompat::and32(Imm32 imm, Register dest) -{ - ma_and(imm, dest, SetCC); -} - -void -MacroAssemblerARMCompat::and32(const Address& src, Register dest) -{ - ScratchRegisterScope scratch(asMasm()); - load32(src, scratch); - ma_and(scratch, dest, SetCC); -} - void MacroAssemblerARMCompat::addPtr(Register src, Register dest) { @@ -1979,15 +1959,6 @@ MacroAssemblerARMCompat::not32(Register reg) ma_mvn(reg, reg); } -void -MacroAssemblerARMCompat::and32(Imm32 imm, const Address& dest) -{ - ScratchRegisterScope scratch(asMasm()); - load32(dest, scratch); - ma_and(imm, scratch); - store32(scratch, dest); -} - void MacroAssemblerARMCompat::or32(Imm32 imm, const Address& dest) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index a3ca908a89e4..3dd91e21af2f 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1202,10 +1202,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM } void xor32(Imm32 imm, Register dest); - void and32(Register src, Register dest); - void and32(Imm32 imm, Register dest); - void and32(Imm32 imm, const Address& dest); - void and32(const Address& src, Register dest); void or32(Register src, Register dest); void or32(Imm32 imm, Register dest); void or32(Imm32 imm, const Address& dest); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index 4e61aad44890..d597ef3a3f60 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -14,7 +14,46 @@ namespace jit { //{{{ check_macroassembler_style // =============================================================== +// Logical instructions +void +MacroAssembler::and32(Register src, Register dest) +{ + And(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(ARMRegister(src, 32))); +} + +void +MacroAssembler::and32(Imm32 imm, Register dest) +{ + And(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value)); +} + +void +MacroAssembler::and32(Imm32 imm, Register src, Register dest) +{ + And(ARMRegister(dest, 32), ARMRegister(src, 32), Operand(imm.value)); +} + +void +MacroAssembler::and32(Imm32 imm, const Address& dest) +{ + vixl::UseScratchRegisterScope temps(this); + const ARMRegister scratch32 = temps.AcquireW(); + MOZ_ASSERT(scratch32.asUnsized() != dest.base); + load32(dest, scratch32.asUnsized()); + And(scratch32, scratch32, Operand(imm.value)); + store32(scratch32.asUnsized(), dest); +} + +void +MacroAssembler::and32(const Address& src, Register dest) +{ + vixl::UseScratchRegisterScope temps(this); + const ARMRegister scratch32 = temps.AcquireW(); + MOZ_ASSERT(scratch32.asUnsized() != src.base); + load32(src, scratch32.asUnsized()); + And(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(scratch32)); +} //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 28289c759be4..805a2bd2a4ed 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -1119,31 +1119,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler void andPtr(Register src, Register dest) { And(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(ARMRegister(src, 64))); } - void and32(Imm32 imm, Register dest) { - And(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value)); - } - void and32(Imm32 imm, Register src, Register dest) { - And(ARMRegister(dest, 32), ARMRegister(src, 32), Operand(imm.value)); - } - - void and32(Register src, Register dest) { - And(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(ARMRegister(src, 32))); - } - void and32(Imm32 mask, Address dest) { - vixl::UseScratchRegisterScope temps(this); - const ARMRegister scratch32 = temps.AcquireW(); - MOZ_ASSERT(scratch32.asUnsized() != dest.base); - load32(dest, scratch32.asUnsized()); - And(scratch32, scratch32, Operand(mask.value)); - store32(scratch32.asUnsized(), dest); - } - void and32(Address src, Register dest) { - vixl::UseScratchRegisterScope temps(this); - const ARMRegister scratch32 = temps.AcquireW(); - MOZ_ASSERT(scratch32.asUnsized() != src.base); - load32(src, scratch32.asUnsized()); - And(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(scratch32)); - } void testPtr(Register lhs, Register rhs) { Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64))); diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index 514c763f8273..721ff87962b6 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -14,7 +14,34 @@ namespace jit { //{{{ check_macroassembler_style // =============================================================== +// Logical instructions +void +MacroAssembler::and32(Register src, Register dest) +{ + ma_and(dest, dest, src); +} + +void +MacroAssembler::and32(Imm32 imm, Register dest) +{ + ma_and(dest, imm); +} + +void +MacroAssembler::and32(Imm32 imm, const Address& dest) +{ + load32(dest, SecondScratchReg); + ma_and(SecondScratchReg, imm); + store32(SecondScratchReg, dest); +} + +void +MacroAssembler::and32(const Address& src, Register dest) +{ + load32(src, SecondScratchReg); + ma_and(dest, SecondScratchReg); +} //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index 61c6a3c8b4f2..01489e56fff0 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -1573,33 +1573,6 @@ MacroAssemblerMIPSCompat::not32(Register reg) } // Logical operations -void -MacroAssemblerMIPSCompat::and32(Register src, Register dest) -{ - ma_and(dest, dest, src); -} - -void -MacroAssemblerMIPSCompat::and32(Imm32 imm, Register dest) -{ - ma_and(dest, imm); -} - -void -MacroAssemblerMIPSCompat::and32(Imm32 imm, const Address& dest) -{ - load32(dest, SecondScratchReg); - ma_and(SecondScratchReg, imm); - store32(SecondScratchReg, dest); -} - -void -MacroAssemblerMIPSCompat::and32(const Address& src, Register dest) -{ - load32(src, SecondScratchReg); - ma_and(dest, SecondScratchReg); -} - void MacroAssemblerMIPSCompat::or32(Imm32 imm, Register dest) { diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index d038f5839e33..01b2a769c6c3 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -1131,10 +1131,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS } } - void and32(Register src, Register dest); - void and32(Imm32 imm, Register dest); - void and32(Imm32 imm, const Address& dest); - void and32(const Address& src, Register dest); void or32(Imm32 imm, Register dest); void or32(Imm32 imm, const Address& dest); void or32(Register src, Register dest); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index c464235c6a7a..94e0399821f9 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -430,7 +430,6 @@ class MacroAssemblerNone : public Assembler template void orPtr(T, S) { MOZ_CRASH(); } template void or32(T, S) { MOZ_CRASH(); } template void andPtr(T, S) { MOZ_CRASH(); } - template void and32(T, S) { MOZ_CRASH(); } template void not32(T) { MOZ_CRASH(); } void convertUInt32ToDouble(Register, FloatRegister) { MOZ_CRASH(); } void convertUInt32ToFloat32(Register, FloatRegister) { MOZ_CRASH(); } diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h index 19dbdd68d42f..888530eb1e15 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -14,7 +14,31 @@ namespace jit { //{{{ check_macroassembler_style // =============================================================== +// Logical instructions +void +MacroAssembler::and32(Register src, Register dest) +{ + andl(src, dest); +} + +void +MacroAssembler::and32(Imm32 imm, Register dest) +{ + andl(imm, dest); +} + +void +MacroAssembler::and32(Imm32 imm, const Address& dest) +{ + andl(imm, Operand(dest)); +} + +void +MacroAssembler::and32(const Address& src, Register dest) +{ + andl(Operand(src), dest); +} //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h index 50426377aedb..2c8921541dbb 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h @@ -123,18 +123,6 @@ class MacroAssemblerX86Shared : public Assembler void move32(Register src, const Operand& dest) { movl(src, dest); } - void and32(Register src, Register dest) { - andl(src, dest); - } - void and32(const Address& src, Register dest) { - andl(Operand(src), dest); - } - void and32(Imm32 imm, Register dest) { - andl(imm, dest); - } - void and32(Imm32 imm, const Address& dest) { - andl(imm, Operand(dest)); - } void or32(Register src, Register dest) { orl(src, dest); } From cf5f53a6d87078717f37359556f4a4555c6f55e7 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Fri, 11 Sep 2015 13:47:53 +0200 Subject: [PATCH 017/131] Bug 1199719 part 2 - Move calleeToken functions to the Jit Frame section of the MacroAssembler. r=sstangl --- js/src/jit/MacroAssembler-inl.h | 29 +++++++++++++++++++++++++++++ js/src/jit/MacroAssembler.h | 25 ++++++++++--------------- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h index 670830c6ec3e..7890a8a557db 100644 --- a/js/src/jit/MacroAssembler-inl.h +++ b/js/src/jit/MacroAssembler-inl.h @@ -213,6 +213,35 @@ MacroAssembler::pushStaticFrameDescriptor(FrameType type) Push(Imm32(descriptor)); } +void +MacroAssembler::PushCalleeToken(Register callee, bool constructing) +{ + if (constructing) { + orPtr(Imm32(CalleeToken_FunctionConstructing), callee); + Push(callee); + andPtr(Imm32(uint32_t(CalleeTokenMask)), callee); + } else { + static_assert(CalleeToken_Function == 0, "Non-constructing call requires no tagging"); + Push(callee); + } +} + +void +MacroAssembler::loadFunctionFromCalleeToken(Address token, Register dest) +{ +#ifdef DEBUG + Label ok; + loadPtr(token, dest); + andPtr(Imm32(uint32_t(~CalleeTokenMask)), dest); + branchPtr(Assembler::Equal, dest, Imm32(CalleeToken_Function), &ok); + branchPtr(Assembler::Equal, dest, Imm32(CalleeToken_FunctionConstructing), &ok); + assumeUnreachable("Unexpected CalleeToken tag"); + bind(&ok); +#endif + loadPtr(token, dest); + andPtr(Imm32(uint32_t(CalleeTokenMask)), dest); +} + uint32_t MacroAssembler::buildFakeExitFrame(Register scratch) { diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 6d5b5c5159db..182d8daeeb0c 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -591,6 +591,16 @@ class MacroAssembler : public MacroAssemblerSpecific // Push the frame descriptor, based on the statically known framePushed. inline void pushStaticFrameDescriptor(FrameType type); + // Push the callee token of a JSFunction which pointer is stored in the + // |callee| register. The callee token is packed with a |constructing| flag + // which correspond to the fact that the JS function is called with "new" or + // not. + inline void PushCalleeToken(Register callee, bool constructing); + + // Unpack a callee token located at the |token| address, and return the + // JSFunction pointer in the |dest| register. + inline void loadFunctionFromCalleeToken(Address token, Register dest); + // This function emulates a call by pushing an exit frame on the stack, // except that the fake-function is inlined within the body of the caller. // @@ -761,21 +771,6 @@ class MacroAssembler : public MacroAssemblerSpecific load32(Address(str, JSString::offsetOfLength()), dest); } - void loadFunctionFromCalleeToken(Address token, Register dest) { - loadPtr(token, dest); - andPtr(Imm32(uint32_t(CalleeTokenMask)), dest); - } - void PushCalleeToken(Register callee, bool constructing) { - if (constructing) { - orPtr(Imm32(CalleeToken_FunctionConstructing), callee); - Push(callee); - andPtr(Imm32(uint32_t(CalleeTokenMask)), callee); - } else { - static_assert(CalleeToken_Function == 0, "Non-constructing call requires no tagging"); - Push(callee); - } - } - void loadStringChars(Register str, Register dest); void loadStringChar(Register str, Register index, Register output); From fa05442ddfd52bd26e6d610ebb4746b90d56af12 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Fri, 11 Sep 2015 13:47:53 +0200 Subject: [PATCH 018/131] Bug 1199719 part 3 - Move MacroAssembler::andPtr into the generic macro assembler. r=djvj --- js/src/jit/MacroAssembler.h | 3 +++ js/src/jit/arm/MacroAssembler-arm-inl.h | 12 +++++++++ js/src/jit/arm/MacroAssembler-arm.cpp | 12 --------- js/src/jit/arm/MacroAssembler-arm.h | 2 -- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 27 +++++++++++++++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 12 ++------- js/src/jit/mips32/MacroAssembler-mips32-inl.h | 12 +++++++++ js/src/jit/mips32/MacroAssembler-mips32.cpp | 14 +--------- js/src/jit/mips32/MacroAssembler-mips32.h | 2 -- js/src/jit/none/MacroAssembler-none.h | 1 - js/src/jit/x64/MacroAssembler-x64-inl.h | 11 ++++++++ js/src/jit/x64/MacroAssembler-x64.h | 6 ----- js/src/jit/x86/MacroAssembler-x86-inl.h | 11 ++++++++ js/src/jit/x86/MacroAssembler-x86.h | 6 ----- 14 files changed, 79 insertions(+), 52 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 182d8daeeb0c..be244b5ff934 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -675,6 +675,9 @@ class MacroAssembler : public MacroAssemblerSpecific inline void and32(Imm32 imm, const Address& dest) PER_SHARED_ARCH; inline void and32(const Address& src, Register dest) PER_SHARED_ARCH; + inline void andPtr(Register src, Register dest) PER_ARCH; + inline void andPtr(Imm32 imm, Register dest) PER_ARCH; + //}}} check_macroassembler_style public: diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index fd3a72a7ca98..04b9fa735678 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -45,6 +45,18 @@ MacroAssembler::and32(const Address& src, Register dest) ma_and(scratch, dest, SetCC); } +void +MacroAssembler::andPtr(Register src, Register dest) +{ + ma_and(src, dest); +} + +void +MacroAssembler::andPtr(Imm32 imm, Register dest) +{ + ma_and(imm, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 7711b124ac04..9195012d8584 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -2004,18 +2004,6 @@ MacroAssemblerARMCompat::orPtr(Register src, Register dest) ma_orr(src, dest); } -void -MacroAssemblerARMCompat::andPtr(Imm32 imm, Register dest) -{ - ma_and(imm, dest); -} - -void -MacroAssemblerARMCompat::andPtr(Register src, Register dest) -{ - ma_and(src, dest); -} - void MacroAssemblerARMCompat::move32(Imm32 imm, Register dest) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 3dd91e21af2f..7f5d0b4073b3 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1209,8 +1209,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void xorPtr(Register src, Register dest); void orPtr(Imm32 imm, Register dest); void orPtr(Register src, Register dest); - void andPtr(Imm32 imm, Register dest); - void andPtr(Register src, Register dest); void addPtr(Register src, Register dest); void addPtr(const Address& src, Register dest); void not32(Register reg); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index d597ef3a3f60..d61ce7ec69fd 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -55,9 +55,36 @@ MacroAssembler::and32(const Address& src, Register dest) And(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(scratch32)); } +void +MacroAssembler::andPtr(Register src, Register dest) +{ + And(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(ARMRegister(src, 64))); +} + +void +MacroAssembler::andPtr(Imm32 imm, Register dest) +{ + And(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); +} + //}}} check_macroassembler_style // =============================================================== +template +void +MacroAssemblerCompat::andToStackPtr(T t) +{ + asMasm().andPtr(t, getStackPointer()); + syncStackPtr(); +} + +template +void +MacroAssemblerCompat::andStackPtrTo(T t) +{ + asMasm().andPtr(getStackPointer(), t); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 805a2bd2a4ed..b2eb5c716c7b 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -1038,10 +1038,8 @@ class MacroAssemblerCompat : public vixl::MacroAssembler template void subStackPtrFrom(T t) { subPtr(getStackPointer(), t); } - template - void andToStackPtr(T t) { andPtr(t, getStackPointer()); syncStackPtr(); } - template - void andStackPtrTo(T t) { andPtr(getStackPointer(), t); } + template void andToStackPtr(T t); + template void andStackPtrTo(T t); template void moveToStackPtr(T t) { movePtr(t, getStackPointer()); syncStackPtr(); } @@ -1113,12 +1111,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Orr(scratch32, scratch32, Operand(imm.value)); store32(scratch32.asUnsized(), dest); } - void andPtr(Imm32 imm, Register dest) { - And(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); - } - void andPtr(Register src, Register dest) { - And(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(ARMRegister(src, 64))); - } void testPtr(Register lhs, Register rhs) { Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64))); diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index 721ff87962b6..0124bb6170f3 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -43,6 +43,18 @@ MacroAssembler::and32(const Address& src, Register dest) ma_and(dest, SecondScratchReg); } +void +MacroAssembler::andPtr(Register src, Register dest) +{ + ma_and(dest, src); +} + +void +MacroAssembler::andPtr(Imm32 imm, Register dest) +{ + ma_and(dest, imm); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index 01489e56fff0..a1f5f2115da5 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -1624,18 +1624,6 @@ MacroAssemblerMIPSCompat::orPtr(Register src, Register dest) ma_or(dest, src); } -void -MacroAssemblerMIPSCompat::andPtr(Imm32 imm, Register dest) -{ - ma_and(dest, imm); -} - -void -MacroAssemblerMIPSCompat::andPtr(Register src, Register dest) -{ - ma_and(dest, src); -} - void MacroAssemblerMIPSCompat::move32(Imm32 imm, Register dest) { @@ -3039,7 +3027,7 @@ MacroAssemblerMIPSCompat::alignStackPointer() { movePtr(StackPointer, SecondScratchReg); subPtr(Imm32(sizeof(uintptr_t)), StackPointer); - andPtr(Imm32(~(ABIStackAlignment - 1)), StackPointer); + asMasm().andPtr(Imm32(~(ABIStackAlignment - 1)), StackPointer); storePtr(SecondScratchReg, Address(StackPointer, 0)); } diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 01b2a769c6c3..400417ed494f 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -1139,8 +1139,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void xorPtr(Register src, Register dest); void orPtr(Imm32 imm, Register dest); void orPtr(Register src, Register dest); - void andPtr(Imm32 imm, Register dest); - void andPtr(Register src, Register dest); void addPtr(Register src, Register dest); void subPtr(Register src, Register dest); void addPtr(const Address& src, Register dest); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 94e0399821f9..cfc4f6167382 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -429,7 +429,6 @@ class MacroAssemblerNone : public Assembler template void xor32(T, S) { MOZ_CRASH(); } template void orPtr(T, S) { MOZ_CRASH(); } template void or32(T, S) { MOZ_CRASH(); } - template void andPtr(T, S) { MOZ_CRASH(); } template void not32(T) { MOZ_CRASH(); } void convertUInt32ToDouble(Register, FloatRegister) { MOZ_CRASH(); } void convertUInt32ToFloat32(Register, FloatRegister) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64-inl.h b/js/src/jit/x64/MacroAssembler-x64-inl.h index 9af5917244cd..0d3a2f5aa391 100644 --- a/js/src/jit/x64/MacroAssembler-x64-inl.h +++ b/js/src/jit/x64/MacroAssembler-x64-inl.h @@ -17,6 +17,17 @@ namespace jit { //{{{ check_macroassembler_style // =============================================================== +void +MacroAssembler::andPtr(Register src, Register dest) +{ + andq(src, dest); +} + +void +MacroAssembler::andPtr(Imm32 imm, Register dest) +{ + andq(imm, dest); +} //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index ecb7c7dcc157..a6bd8d8f1c6c 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -858,12 +858,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared void orPtr(Register src, Register dest) { orq(src, dest); } - void andPtr(Imm32 imm, Register dest) { - andq(imm, dest); - } - void andPtr(Register src, Register dest) { - andq(src, dest); - } void splitTag(Register src, Register dest) { if (src != dest) diff --git a/js/src/jit/x86/MacroAssembler-x86-inl.h b/js/src/jit/x86/MacroAssembler-x86-inl.h index 10539791e9ee..e2b897d42a32 100644 --- a/js/src/jit/x86/MacroAssembler-x86-inl.h +++ b/js/src/jit/x86/MacroAssembler-x86-inl.h @@ -17,6 +17,17 @@ namespace jit { //{{{ check_macroassembler_style // =============================================================== +void +MacroAssembler::andPtr(Register src, Register dest) +{ + andl(src, dest); +} + +void +MacroAssembler::andPtr(Imm32 imm, Register dest) +{ + andl(imm, dest); +} //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 3ea59641efee..9e4c01d42b2d 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -1075,12 +1075,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared void orPtr(Register src, Register dest) { orl(src, dest); } - void andPtr(Imm32 imm, Register dest) { - andl(imm, dest); - } - void andPtr(Register src, Register dest) { - andl(src, dest); - } void loadInstructionPointerAfterCall(Register dest) { movl(Operand(StackPointer, 0x0), dest); From ecf65767846ced0970a2b11188b5c96cb6bc9b47 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Fri, 11 Sep 2015 13:47:54 +0200 Subject: [PATCH 019/131] Bug 1199719 part 4 - Move MacroAssembler::or32 into the generic macro assembler. r=hev --- js/src/jit/MacroAssembler.h | 4 ++++ js/src/jit/arm/MacroAssembler-arm-inl.h | 21 +++++++++++++++++ js/src/jit/arm/MacroAssembler-arm.cpp | 21 ----------------- js/src/jit/arm/MacroAssembler-arm.h | 3 --- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 23 +++++++++++++++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 14 ----------- js/src/jit/mips32/MacroAssembler-mips32-inl.h | 20 ++++++++++++++++ js/src/jit/mips32/MacroAssembler-mips32.cpp | 21 ----------------- js/src/jit/mips32/MacroAssembler-mips32.h | 3 --- js/src/jit/none/MacroAssembler-none.h | 1 - .../MacroAssembler-x86-shared-inl.h | 18 +++++++++++++++ .../x86-shared/MacroAssembler-x86-shared.h | 9 -------- 12 files changed, 86 insertions(+), 72 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index be244b5ff934..688d6f11c48d 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -678,6 +678,10 @@ class MacroAssembler : public MacroAssemblerSpecific inline void andPtr(Register src, Register dest) PER_ARCH; inline void andPtr(Imm32 imm, Register dest) PER_ARCH; + inline void or32(Register src, Register dest) PER_SHARED_ARCH; + inline void or32(Imm32 imm, Register dest) PER_SHARED_ARCH; + inline void or32(Imm32 imm, const Address& dest) PER_SHARED_ARCH; + //}}} check_macroassembler_style public: diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 04b9fa735678..63195e6490b6 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -57,6 +57,27 @@ MacroAssembler::andPtr(Imm32 imm, Register dest) ma_and(imm, dest); } +void +MacroAssembler::or32(Register src, Register dest) +{ + ma_orr(src, dest); +} + +void +MacroAssembler::or32(Imm32 imm, Register dest) +{ + ma_orr(imm, dest); +} + +void +MacroAssembler::or32(Imm32 imm, const Address& dest) +{ + ScratchRegisterScope scratch(*this); + load32(dest, scratch); + ma_orr(imm, scratch); + store32(scratch, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 9195012d8584..0a2fea7845f1 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -1959,27 +1959,6 @@ MacroAssemblerARMCompat::not32(Register reg) ma_mvn(reg, reg); } -void -MacroAssemblerARMCompat::or32(Imm32 imm, const Address& dest) -{ - ScratchRegisterScope scratch(asMasm()); - load32(dest, scratch); - ma_orr(imm, scratch); - store32(scratch, dest); -} - -void -MacroAssemblerARMCompat::or32(Imm32 imm, Register dest) -{ - ma_orr(imm, dest); -} - -void -MacroAssemblerARMCompat::or32(Register src, Register dest) -{ - ma_orr(src, dest); -} - void MacroAssemblerARMCompat::xorPtr(Imm32 imm, Register dest) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 7f5d0b4073b3..9dbcf396f020 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1202,9 +1202,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM } void xor32(Imm32 imm, Register dest); - void or32(Register src, Register dest); - void or32(Imm32 imm, Register dest); - void or32(Imm32 imm, const Address& dest); void xorPtr(Imm32 imm, Register dest); void xorPtr(Register src, Register dest); void orPtr(Imm32 imm, Register dest); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index d61ce7ec69fd..5c5bab83fea1 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -67,6 +67,29 @@ MacroAssembler::andPtr(Imm32 imm, Register dest) And(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); } +void +MacroAssembler::or32(Imm32 imm, Register dest) +{ + Orr(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value)); +} + +void +MacroAssembler::or32(Register src, Register dest) +{ + Orr(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(ARMRegister(src, 32))); +} + +void +MacroAssembler::or32(Imm32 imm, const Address& dest) +{ + vixl::UseScratchRegisterScope temps(this); + const ARMRegister scratch32 = temps.AcquireW(); + MOZ_ASSERT(scratch32.asUnsized() != dest.base); + load32(dest, scratch32.asUnsized()); + Orr(scratch32, scratch32, Operand(imm.value)); + store32(scratch32.asUnsized(), dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index b2eb5c716c7b..3639ad1cc67a 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -1097,20 +1097,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler void orPtr(Register src, Register dest) { Orr(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(ARMRegister(src, 64))); } - void or32(Imm32 imm, Register dest) { - Orr(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value)); - } - void or32(Register src, Register dest) { - Orr(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(ARMRegister(src, 32))); - } - void or32(Imm32 imm, const Address& dest) { - vixl::UseScratchRegisterScope temps(this); - const ARMRegister scratch32 = temps.AcquireW(); - MOZ_ASSERT(scratch32.asUnsized() != dest.base); - load32(dest, scratch32.asUnsized()); - Orr(scratch32, scratch32, Operand(imm.value)); - store32(scratch32.asUnsized(), dest); - } void testPtr(Register lhs, Register rhs) { Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64))); diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index 0124bb6170f3..e71533cd0d40 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -55,6 +55,26 @@ MacroAssembler::andPtr(Imm32 imm, Register dest) ma_and(dest, imm); } +void +MacroAssembler::or32(Register src, Register dest) +{ + ma_or(dest, src); +} + +void +MacroAssembler::or32(Imm32 imm, Register dest) +{ + ma_or(dest, imm); +} + +void +MacroAssembler::or32(Imm32 imm, const Address& dest) +{ + load32(dest, SecondScratchReg); + ma_or(SecondScratchReg, imm); + store32(SecondScratchReg, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index a1f5f2115da5..7882962d8ef9 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -1573,27 +1573,6 @@ MacroAssemblerMIPSCompat::not32(Register reg) } // Logical operations -void -MacroAssemblerMIPSCompat::or32(Imm32 imm, Register dest) -{ - ma_or(dest, imm); -} - - -void -MacroAssemblerMIPSCompat::or32(Imm32 imm, const Address& dest) -{ - load32(dest, SecondScratchReg); - ma_or(SecondScratchReg, imm); - store32(SecondScratchReg, dest); -} - -void -MacroAssemblerMIPSCompat::or32(Register src, Register dest) -{ - ma_or(dest, src); -} - void MacroAssemblerMIPSCompat::xor32(Imm32 imm, Register dest) { diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 400417ed494f..482ffbee1fd8 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -1131,9 +1131,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS } } - void or32(Imm32 imm, Register dest); - void or32(Imm32 imm, const Address& dest); - void or32(Register src, Register dest); void xor32(Imm32 imm, Register dest); void xorPtr(Imm32 imm, Register dest); void xorPtr(Register src, Register dest); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index cfc4f6167382..2007c9b96b1a 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -428,7 +428,6 @@ class MacroAssemblerNone : public Assembler template void xorPtr(T, S) { MOZ_CRASH(); } template void xor32(T, S) { MOZ_CRASH(); } template void orPtr(T, S) { MOZ_CRASH(); } - template void or32(T, S) { MOZ_CRASH(); } template void not32(T) { MOZ_CRASH(); } void convertUInt32ToDouble(Register, FloatRegister) { MOZ_CRASH(); } void convertUInt32ToFloat32(Register, FloatRegister) { MOZ_CRASH(); } diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h index 888530eb1e15..ae17ed571a23 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -40,6 +40,24 @@ MacroAssembler::and32(const Address& src, Register dest) andl(Operand(src), dest); } +void +MacroAssembler::or32(Register src, Register dest) +{ + orl(src, dest); +} + +void +MacroAssembler::or32(Imm32 imm, Register dest) +{ + orl(imm, dest); +} + +void +MacroAssembler::or32(Imm32 imm, const Address& dest) +{ + orl(imm, Operand(dest)); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h index 2c8921541dbb..af337591df13 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h @@ -123,15 +123,6 @@ class MacroAssemblerX86Shared : public Assembler void move32(Register src, const Operand& dest) { movl(src, dest); } - void or32(Register src, Register dest) { - orl(src, dest); - } - void or32(Imm32 imm, Register dest) { - orl(imm, dest); - } - void or32(Imm32 imm, const Address& dest) { - orl(imm, Operand(dest)); - } void neg32(Register reg) { negl(reg); } From 2802723df0c89fe7077d7770679073f339c1ac07 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Fri, 11 Sep 2015 13:47:54 +0200 Subject: [PATCH 020/131] Bug 1199719 part 5 - Move MacroAssembler::orPtr into the generic macro assembler. r=lth --- js/src/jit/MacroAssembler.h | 3 +++ js/src/jit/arm/MacroAssembler-arm-inl.h | 12 ++++++++++++ js/src/jit/arm/MacroAssembler-arm.cpp | 12 ------------ js/src/jit/arm/MacroAssembler-arm.h | 2 -- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 12 ++++++++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 9 --------- js/src/jit/mips32/MacroAssembler-mips32-inl.h | 12 ++++++++++++ js/src/jit/mips32/MacroAssembler-mips32.cpp | 12 ------------ js/src/jit/mips32/MacroAssembler-mips32.h | 2 -- js/src/jit/none/MacroAssembler-none.h | 1 - js/src/jit/x64/MacroAssembler-x64-inl.h | 12 ++++++++++++ js/src/jit/x64/MacroAssembler-x64.h | 6 ------ js/src/jit/x86/MacroAssembler-x86-inl.h | 12 ++++++++++++ js/src/jit/x86/MacroAssembler-x86.h | 6 ------ 14 files changed, 63 insertions(+), 50 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 688d6f11c48d..ec5edbde2437 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -682,6 +682,9 @@ class MacroAssembler : public MacroAssemblerSpecific inline void or32(Imm32 imm, Register dest) PER_SHARED_ARCH; inline void or32(Imm32 imm, const Address& dest) PER_SHARED_ARCH; + inline void orPtr(Register src, Register dest) PER_ARCH; + inline void orPtr(Imm32 imm, Register dest) PER_ARCH; + //}}} check_macroassembler_style public: diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 63195e6490b6..fc384e492fbe 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -78,6 +78,18 @@ MacroAssembler::or32(Imm32 imm, const Address& dest) store32(scratch, dest); } +void +MacroAssembler::orPtr(Register src, Register dest) +{ + ma_orr(src, dest); +} + +void +MacroAssembler::orPtr(Imm32 imm, Register dest) +{ + ma_orr(imm, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 0a2fea7845f1..dd5b785a1550 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -1971,18 +1971,6 @@ MacroAssemblerARMCompat::xorPtr(Register src, Register dest) ma_eor(src, dest); } -void -MacroAssemblerARMCompat::orPtr(Imm32 imm, Register dest) -{ - ma_orr(imm, dest); -} - -void -MacroAssemblerARMCompat::orPtr(Register src, Register dest) -{ - ma_orr(src, dest); -} - void MacroAssemblerARMCompat::move32(Imm32 imm, Register dest) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 9dbcf396f020..4083934ce018 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1204,8 +1204,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void xorPtr(Imm32 imm, Register dest); void xorPtr(Register src, Register dest); - void orPtr(Imm32 imm, Register dest); - void orPtr(Register src, Register dest); void addPtr(Register src, Register dest); void addPtr(const Address& src, Register dest); void not32(Register reg); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index 5c5bab83fea1..5f02cb6013cd 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -90,6 +90,18 @@ MacroAssembler::or32(Imm32 imm, const Address& dest) store32(scratch32.asUnsized(), dest); } +void +MacroAssembler::orPtr(Register src, Register dest) +{ + Orr(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(ARMRegister(src, 64))); +} + +void +MacroAssembler::orPtr(Imm32 imm, Register dest) +{ + Orr(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 3639ad1cc67a..ce057db1bf4e 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -1088,15 +1088,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler void xorPtr(Register src, Register dest) { Eor(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(ARMRegister(src, 64))); } - void orPtr(ImmWord imm, Register dest) { - Orr(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); - } - void orPtr(Imm32 imm, Register dest) { - Orr(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); - } - void orPtr(Register src, Register dest) { - Orr(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(ARMRegister(src, 64))); - } void testPtr(Register lhs, Register rhs) { Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64))); diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index e71533cd0d40..2c137031488f 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -75,6 +75,18 @@ MacroAssembler::or32(Imm32 imm, const Address& dest) store32(SecondScratchReg, dest); } +void +MacroAssembler::orPtr(Register src, Register dest) +{ + ma_or(dest, src); +} + +void +MacroAssembler::orPtr(Imm32 imm, Register dest) +{ + ma_or(dest, imm); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index 7882962d8ef9..85afde66bebb 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -1591,18 +1591,6 @@ MacroAssemblerMIPSCompat::xorPtr(Register src, Register dest) ma_xor(dest, src); } -void -MacroAssemblerMIPSCompat::orPtr(Imm32 imm, Register dest) -{ - ma_or(dest, imm); -} - -void -MacroAssemblerMIPSCompat::orPtr(Register src, Register dest) -{ - ma_or(dest, src); -} - void MacroAssemblerMIPSCompat::move32(Imm32 imm, Register dest) { diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 482ffbee1fd8..81874f18bacd 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -1134,8 +1134,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void xor32(Imm32 imm, Register dest); void xorPtr(Imm32 imm, Register dest); void xorPtr(Register src, Register dest); - void orPtr(Imm32 imm, Register dest); - void orPtr(Register src, Register dest); void addPtr(Register src, Register dest); void subPtr(Register src, Register dest); void addPtr(const Address& src, Register dest); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 2007c9b96b1a..0ded8e4775a8 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -427,7 +427,6 @@ class MacroAssemblerNone : public Assembler void lshiftPtr(Imm32, Register) { MOZ_CRASH(); } template void xorPtr(T, S) { MOZ_CRASH(); } template void xor32(T, S) { MOZ_CRASH(); } - template void orPtr(T, S) { MOZ_CRASH(); } template void not32(T) { MOZ_CRASH(); } void convertUInt32ToDouble(Register, FloatRegister) { MOZ_CRASH(); } void convertUInt32ToFloat32(Register, FloatRegister) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64-inl.h b/js/src/jit/x64/MacroAssembler-x64-inl.h index 0d3a2f5aa391..fa4176d5c666 100644 --- a/js/src/jit/x64/MacroAssembler-x64-inl.h +++ b/js/src/jit/x64/MacroAssembler-x64-inl.h @@ -29,6 +29,18 @@ MacroAssembler::andPtr(Imm32 imm, Register dest) andq(imm, dest); } +void +MacroAssembler::orPtr(Register src, Register dest) +{ + orq(src, dest); +} + +void +MacroAssembler::orPtr(Imm32 imm, Register dest) +{ + orq(imm, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index a6bd8d8f1c6c..d2588d873b6c 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -852,12 +852,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared void xorPtr(Register src, Register dest) { xorq(src, dest); } - void orPtr(Imm32 imm, Register dest) { - orq(imm, dest); - } - void orPtr(Register src, Register dest) { - orq(src, dest); - } void splitTag(Register src, Register dest) { if (src != dest) diff --git a/js/src/jit/x86/MacroAssembler-x86-inl.h b/js/src/jit/x86/MacroAssembler-x86-inl.h index e2b897d42a32..dc91eb87a4da 100644 --- a/js/src/jit/x86/MacroAssembler-x86-inl.h +++ b/js/src/jit/x86/MacroAssembler-x86-inl.h @@ -29,6 +29,18 @@ MacroAssembler::andPtr(Imm32 imm, Register dest) andl(imm, dest); } +void +MacroAssembler::orPtr(Register src, Register dest) +{ + orl(src, dest); +} + +void +MacroAssembler::orPtr(Imm32 imm, Register dest) +{ + orl(imm, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 9e4c01d42b2d..35a6e2b2f475 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -1069,12 +1069,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared void xorPtr(Register src, Register dest) { xorl(src, dest); } - void orPtr(Imm32 imm, Register dest) { - orl(imm, dest); - } - void orPtr(Register src, Register dest) { - orl(src, dest); - } void loadInstructionPointerAfterCall(Register dest) { movl(Operand(StackPointer, 0x0), dest); From 80439faed123bcb8381b905f58cc03cec2908cf0 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Fri, 11 Sep 2015 13:47:54 +0200 Subject: [PATCH 021/131] Bug 1199719 part 6 - Move MacroAssembler::xor32 into the generic macro assembler. r=jandem --- js/src/jit/MacroAssembler.h | 3 +++ js/src/jit/arm/MacroAssembler-arm-inl.h | 6 ++++++ js/src/jit/arm/MacroAssembler-arm.cpp | 6 ------ js/src/jit/arm/MacroAssembler-arm.h | 1 - js/src/jit/arm64/MacroAssembler-arm64-inl.h | 6 ++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 3 --- js/src/jit/mips32/MacroAssembler-mips32-inl.h | 6 ++++++ js/src/jit/mips32/MacroAssembler-mips32.cpp | 6 ------ js/src/jit/mips32/MacroAssembler-mips32.h | 1 - js/src/jit/none/MacroAssembler-none.h | 1 - .../jit/x86-shared/MacroAssembler-x86-shared-inl.h | 12 ++++++++++++ js/src/jit/x86-shared/MacroAssembler-x86-shared.h | 6 ------ 12 files changed, 33 insertions(+), 24 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index ec5edbde2437..27fb933325e5 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -685,6 +685,9 @@ class MacroAssembler : public MacroAssemblerSpecific inline void orPtr(Register src, Register dest) PER_ARCH; inline void orPtr(Imm32 imm, Register dest) PER_ARCH; + inline void xor32(Register src, Register dest) DEFINED_ON(x86_shared); + inline void xor32(Imm32 imm, Register dest) PER_SHARED_ARCH; + //}}} check_macroassembler_style public: diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index fc384e492fbe..1134f4d7eef0 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -90,6 +90,12 @@ MacroAssembler::orPtr(Imm32 imm, Register dest) ma_orr(imm, dest); } +void +MacroAssembler::xor32(Imm32 imm, Register dest) +{ + ma_eor(imm, dest, SetCC); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index dd5b785a1550..40d551d98776 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -1912,12 +1912,6 @@ MacroAssemblerARMCompat::add32(Imm32 imm, Register dest) ma_add(imm, dest, SetCC); } -void -MacroAssemblerARMCompat::xor32(Imm32 imm, Register dest) -{ - ma_eor(imm, dest, SetCC); -} - void MacroAssemblerARMCompat::add32(Imm32 imm, const Address& dest) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 4083934ce018..7bc09044296b 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1200,7 +1200,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM sub32(src, dest); j(cond, label); } - void xor32(Imm32 imm, Register dest); void xorPtr(Imm32 imm, Register dest); void xorPtr(Register src, Register dest); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index 5f02cb6013cd..af39df1f5da3 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -102,6 +102,12 @@ MacroAssembler::orPtr(Imm32 imm, Register dest) Orr(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); } +void +MacroAssembler::xor32(Imm32 imm, Register dest) +{ + Eor(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value)); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index ce057db1bf4e..e56f0889bc0a 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -1081,9 +1081,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler void xorPtr(Imm32 imm, Register dest) { Eor(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); } - void xor32(Imm32 imm, Register dest) { - Eor(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value)); - } void xorPtr(Register src, Register dest) { Eor(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(ARMRegister(src, 64))); diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index 2c137031488f..cef73fe36d8e 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -87,6 +87,12 @@ MacroAssembler::orPtr(Imm32 imm, Register dest) ma_or(dest, imm); } +void +MacroAssembler::xor32(Imm32 imm, Register dest) +{ + ma_xor(dest, imm); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index 85afde66bebb..b419722eca9a 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -1573,12 +1573,6 @@ MacroAssemblerMIPSCompat::not32(Register reg) } // Logical operations -void -MacroAssemblerMIPSCompat::xor32(Imm32 imm, Register dest) -{ - ma_xor(dest, imm); -} - void MacroAssemblerMIPSCompat::xorPtr(Imm32 imm, Register dest) { diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 81874f18bacd..93f9aa60ffe8 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -1131,7 +1131,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS } } - void xor32(Imm32 imm, Register dest); void xorPtr(Imm32 imm, Register dest); void xorPtr(Register src, Register dest); void addPtr(Register src, Register dest); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 0ded8e4775a8..7817948f479a 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -426,7 +426,6 @@ class MacroAssemblerNone : public Assembler void rshiftPtrArithmetic(Imm32, Register) { MOZ_CRASH(); } void lshiftPtr(Imm32, Register) { MOZ_CRASH(); } template void xorPtr(T, S) { MOZ_CRASH(); } - template void xor32(T, S) { MOZ_CRASH(); } template void not32(T) { MOZ_CRASH(); } void convertUInt32ToDouble(Register, FloatRegister) { MOZ_CRASH(); } void convertUInt32ToFloat32(Register, FloatRegister) { MOZ_CRASH(); } diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h index ae17ed571a23..308c9cac7154 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -58,6 +58,18 @@ MacroAssembler::or32(Imm32 imm, const Address& dest) orl(imm, Operand(dest)); } +void +MacroAssembler::xor32(Register src, Register dest) +{ + xorl(src, dest); +} + +void +MacroAssembler::xor32(Imm32 imm, Register dest) +{ + xorl(imm, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h index af337591df13..09968131636d 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h @@ -190,12 +190,6 @@ class MacroAssemblerX86Shared : public Assembler sub32(src, dest); j(cond, label); } - void xor32(Imm32 imm, Register dest) { - xorl(imm, dest); - } - void xor32(Register src, Register dest) { - xorl(src, dest); - } void not32(Register reg) { notl(reg); } From fa1f700dfdc4feddbd0014bdb4c677e6a5e59c41 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Fri, 11 Sep 2015 13:47:55 +0200 Subject: [PATCH 022/131] Bug 1199719 part 7 - Move MacroAssembler::xorPtr into the generic macro assembler. r=bbouvier --- js/src/jit/MacroAssembler.h | 3 +++ js/src/jit/arm/MacroAssembler-arm-inl.h | 12 ++++++++++++ js/src/jit/arm/MacroAssembler-arm.cpp | 12 ------------ js/src/jit/arm/MacroAssembler-arm.h | 2 -- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 12 ++++++++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 7 ------- js/src/jit/mips32/MacroAssembler-mips32-inl.h | 12 ++++++++++++ js/src/jit/mips32/MacroAssembler-mips32.cpp | 12 ------------ js/src/jit/mips32/MacroAssembler-mips32.h | 2 -- js/src/jit/none/MacroAssembler-none.h | 1 - js/src/jit/x64/MacroAssembler-x64-inl.h | 12 ++++++++++++ js/src/jit/x64/MacroAssembler-x64.h | 6 ------ js/src/jit/x86/MacroAssembler-x86-inl.h | 12 ++++++++++++ js/src/jit/x86/MacroAssembler-x86.h | 6 ------ 14 files changed, 63 insertions(+), 48 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 27fb933325e5..0f16b05b22e7 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -688,6 +688,9 @@ class MacroAssembler : public MacroAssemblerSpecific inline void xor32(Register src, Register dest) DEFINED_ON(x86_shared); inline void xor32(Imm32 imm, Register dest) PER_SHARED_ARCH; + inline void xorPtr(Register src, Register dest) PER_ARCH; + inline void xorPtr(Imm32 imm, Register dest) PER_ARCH; + //}}} check_macroassembler_style public: diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 1134f4d7eef0..73ab4320ad52 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -96,6 +96,18 @@ MacroAssembler::xor32(Imm32 imm, Register dest) ma_eor(imm, dest, SetCC); } +void +MacroAssembler::xorPtr(Register src, Register dest) +{ + ma_eor(src, dest); +} + +void +MacroAssembler::xorPtr(Imm32 imm, Register dest) +{ + ma_eor(imm, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 40d551d98776..9213c1e5a0ca 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -1953,18 +1953,6 @@ MacroAssemblerARMCompat::not32(Register reg) ma_mvn(reg, reg); } -void -MacroAssemblerARMCompat::xorPtr(Imm32 imm, Register dest) -{ - ma_eor(imm, dest); -} - -void -MacroAssemblerARMCompat::xorPtr(Register src, Register dest) -{ - ma_eor(src, dest); -} - void MacroAssemblerARMCompat::move32(Imm32 imm, Register dest) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 7bc09044296b..402570dbb7be 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1201,8 +1201,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM j(cond, label); } - void xorPtr(Imm32 imm, Register dest); - void xorPtr(Register src, Register dest); void addPtr(Register src, Register dest); void addPtr(const Address& src, Register dest); void not32(Register reg); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index af39df1f5da3..4a4e36772f39 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -108,6 +108,18 @@ MacroAssembler::xor32(Imm32 imm, Register dest) Eor(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value)); } +void +MacroAssembler::xorPtr(Register src, Register dest) +{ + Eor(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(ARMRegister(src, 64))); +} + +void +MacroAssembler::xorPtr(Imm32 imm, Register dest) +{ + Eor(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index e56f0889bc0a..f8bed172ad4f 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -1078,13 +1078,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler void lshiftPtr(Imm32 imm, Register dest) { Lsl(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value); } - void xorPtr(Imm32 imm, Register dest) { - Eor(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); - } - - void xorPtr(Register src, Register dest) { - Eor(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(ARMRegister(src, 64))); - } void testPtr(Register lhs, Register rhs) { Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64))); diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index cef73fe36d8e..f596a30ab27b 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -93,6 +93,18 @@ MacroAssembler::xor32(Imm32 imm, Register dest) ma_xor(dest, imm); } +void +MacroAssembler::xorPtr(Register src, Register dest) +{ + ma_xor(dest, src); +} + +void +MacroAssembler::xorPtr(Imm32 imm, Register dest) +{ + ma_xor(dest, imm); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index b419722eca9a..bf51c84b17e7 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -1573,18 +1573,6 @@ MacroAssemblerMIPSCompat::not32(Register reg) } // Logical operations -void -MacroAssemblerMIPSCompat::xorPtr(Imm32 imm, Register dest) -{ - ma_xor(dest, imm); -} - -void -MacroAssemblerMIPSCompat::xorPtr(Register src, Register dest) -{ - ma_xor(dest, src); -} - void MacroAssemblerMIPSCompat::move32(Imm32 imm, Register dest) { diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 93f9aa60ffe8..212481d44f47 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -1131,8 +1131,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS } } - void xorPtr(Imm32 imm, Register dest); - void xorPtr(Register src, Register dest); void addPtr(Register src, Register dest); void subPtr(Register src, Register dest); void addPtr(const Address& src, Register dest); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 7817948f479a..004d0d45003a 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -425,7 +425,6 @@ class MacroAssemblerNone : public Assembler void rshiftPtr(Imm32, Register) { MOZ_CRASH(); } void rshiftPtrArithmetic(Imm32, Register) { MOZ_CRASH(); } void lshiftPtr(Imm32, Register) { MOZ_CRASH(); } - template void xorPtr(T, S) { MOZ_CRASH(); } template void not32(T) { MOZ_CRASH(); } void convertUInt32ToDouble(Register, FloatRegister) { MOZ_CRASH(); } void convertUInt32ToFloat32(Register, FloatRegister) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64-inl.h b/js/src/jit/x64/MacroAssembler-x64-inl.h index fa4176d5c666..6a5ff97927aa 100644 --- a/js/src/jit/x64/MacroAssembler-x64-inl.h +++ b/js/src/jit/x64/MacroAssembler-x64-inl.h @@ -41,6 +41,18 @@ MacroAssembler::orPtr(Imm32 imm, Register dest) orq(imm, dest); } +void +MacroAssembler::xorPtr(Register src, Register dest) +{ + xorq(src, dest); +} + +void +MacroAssembler::xorPtr(Imm32 imm, Register dest) +{ + xorq(imm, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index d2588d873b6c..16207ae70ca1 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -846,12 +846,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared void lshiftPtr(Imm32 imm, Register dest) { shlq(imm, dest); } - void xorPtr(Imm32 imm, Register dest) { - xorq(imm, dest); - } - void xorPtr(Register src, Register dest) { - xorq(src, dest); - } void splitTag(Register src, Register dest) { if (src != dest) diff --git a/js/src/jit/x86/MacroAssembler-x86-inl.h b/js/src/jit/x86/MacroAssembler-x86-inl.h index dc91eb87a4da..b5ca8186754f 100644 --- a/js/src/jit/x86/MacroAssembler-x86-inl.h +++ b/js/src/jit/x86/MacroAssembler-x86-inl.h @@ -41,6 +41,18 @@ MacroAssembler::orPtr(Imm32 imm, Register dest) orl(imm, dest); } +void +MacroAssembler::xorPtr(Register src, Register dest) +{ + xorl(src, dest); +} + +void +MacroAssembler::xorPtr(Imm32 imm, Register dest) +{ + xorl(imm, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 35a6e2b2f475..64e079aad67a 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -1063,12 +1063,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared void lshiftPtr(Imm32 imm, Register dest) { shll(imm, dest); } - void xorPtr(Imm32 imm, Register dest) { - xorl(imm, dest); - } - void xorPtr(Register src, Register dest) { - xorl(src, dest); - } void loadInstructionPointerAfterCall(Register dest) { movl(Operand(StackPointer, 0x0), dest); From 2ed00693e3206208f75e895a2fbc4b7b5d3e5bb9 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Fri, 11 Sep 2015 13:47:55 +0200 Subject: [PATCH 023/131] Bug 1199719 part 8 - Move MacroAssembler::not32 into the generic macro assembler. r=h4writer --- js/src/jit/MacroAssembler.h | 2 ++ js/src/jit/arm/MacroAssembler-arm-inl.h | 6 ++++++ js/src/jit/arm/MacroAssembler-arm.cpp | 6 ------ js/src/jit/arm/MacroAssembler-arm.h | 1 - js/src/jit/arm64/MacroAssembler-arm64-inl.h | 6 ++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 3 --- js/src/jit/mips32/MacroAssembler-mips32-inl.h | 6 ++++++ js/src/jit/mips32/MacroAssembler-mips32.cpp | 7 ------- js/src/jit/mips32/MacroAssembler-mips32.h | 1 - js/src/jit/none/MacroAssembler-none.h | 1 - js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h | 6 ++++++ js/src/jit/x86-shared/MacroAssembler-x86-shared.h | 3 --- 12 files changed, 26 insertions(+), 22 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 0f16b05b22e7..2be545e1da7d 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -669,6 +669,8 @@ class MacroAssembler : public MacroAssemblerSpecific // =============================================================== // Logical instructions + inline void not32(Register reg) PER_SHARED_ARCH; + inline void and32(Register src, Register dest) PER_SHARED_ARCH; inline void and32(Imm32 imm, Register dest) PER_SHARED_ARCH; inline void and32(Imm32 imm, Register src, Register dest) DEFINED_ON(arm64); diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 73ab4320ad52..25f7882c50f5 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -16,6 +16,12 @@ namespace jit { // =============================================================== // Logical instructions +void +MacroAssembler::not32(Register reg) +{ + ma_mvn(reg, reg); +} + void MacroAssembler::and32(Register src, Register dest) { diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 9213c1e5a0ca..20badd74b3c4 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -1947,12 +1947,6 @@ MacroAssemblerARMCompat::addPtr(const Address& src, Register dest) ma_add(scratch, dest, SetCC); } -void -MacroAssemblerARMCompat::not32(Register reg) -{ - ma_mvn(reg, reg); -} - void MacroAssemblerARMCompat::move32(Imm32 imm, Register dest) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 402570dbb7be..45035b4dc91d 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1203,7 +1203,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void addPtr(Register src, Register dest); void addPtr(const Address& src, Register dest); - void not32(Register reg); void move32(Imm32 imm, Register dest); void move32(Register src, Register dest); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index 4a4e36772f39..0778b054e3e8 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -16,6 +16,12 @@ namespace jit { // =============================================================== // Logical instructions +void +MacroAssembler::not32(Register reg) +{ + Orn(ARMRegister(reg, 32), vixl::wzr, ARMRegister(reg, 32)); +} + void MacroAssembler::and32(Register src, Register dest) { diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index f8bed172ad4f..a8d98d4e7de8 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -811,9 +811,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler BufferOffset movePatchablePtr(ImmWord ptr, Register dest); BufferOffset movePatchablePtr(ImmPtr ptr, Register dest); - void not32(Register reg) { - Orn(ARMRegister(reg, 32), vixl::wzr, ARMRegister(reg, 32)); - } void neg32(Register reg) { Negs(ARMRegister(reg, 32), Operand(ARMRegister(reg, 32))); } diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index f596a30ab27b..e21dbbea7620 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -16,6 +16,12 @@ namespace jit { // =============================================================== // Logical instructions +void +MacroAssembler::not32(Register reg) +{ + ma_not(reg, reg); +} + void MacroAssembler::and32(Register src, Register dest) { diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index bf51c84b17e7..71eee8eef0b2 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -1566,13 +1566,6 @@ MacroAssemblerMIPSCompat::subPtr(Register src, Register dest) ma_subu(dest, dest, src); } -void -MacroAssemblerMIPSCompat::not32(Register reg) -{ - ma_not(reg, reg); -} - -// Logical operations void MacroAssemblerMIPSCompat::move32(Imm32 imm, Register dest) { diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 212481d44f47..b6fb58df6a66 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -1134,7 +1134,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void addPtr(Register src, Register dest); void subPtr(Register src, Register dest); void addPtr(const Address& src, Register dest); - void not32(Register reg); void move32(Imm32 imm, Register dest); void move32(Register src, Register dest); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 004d0d45003a..acb038c31d86 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -425,7 +425,6 @@ class MacroAssemblerNone : public Assembler void rshiftPtr(Imm32, Register) { MOZ_CRASH(); } void rshiftPtrArithmetic(Imm32, Register) { MOZ_CRASH(); } void lshiftPtr(Imm32, Register) { MOZ_CRASH(); } - template void not32(T) { MOZ_CRASH(); } void convertUInt32ToDouble(Register, FloatRegister) { MOZ_CRASH(); } void convertUInt32ToFloat32(Register, FloatRegister) { MOZ_CRASH(); } void inc64(AbsoluteAddress) { MOZ_CRASH(); } diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h index 308c9cac7154..42f2376ecc5c 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -16,6 +16,12 @@ namespace jit { // =============================================================== // Logical instructions +void +MacroAssembler::not32(Register reg) +{ + notl(reg); +} + void MacroAssembler::and32(Register src, Register dest) { diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h index 09968131636d..406ee1171a16 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h @@ -190,9 +190,6 @@ class MacroAssemblerX86Shared : public Assembler sub32(src, dest); j(cond, label); } - void not32(Register reg) { - notl(reg); - } void atomic_inc32(const Operand& addr) { lock_incl(addr); } From b3ee47117cf9e4d8af9e25aafc23b5c18d53ce14 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Fri, 11 Sep 2015 14:18:09 +0200 Subject: [PATCH 024/131] Backed out 7 changesets (bug 1181516, bug 1198257, bug 1193257, bug 1194166, bug 1193223, bug 1193224, bug 1181520) for test bustages on Android on a CLOSED TREE Backed out changeset efe681ac063f (bug 1194166) Backed out changeset bfcbce193ccf (bug 1193257) Backed out changeset bb035419fd9c (bug 1193224) Backed out changeset eb2d48b71c37 (bug 1198257) Backed out changeset 0d6532c1e99e (bug 1193223) Backed out changeset da3dd2f650d0 (bug 1181516) Backed out changeset 29c33bbaac01 (bug 1181520) --- layout/tools/reftest/Makefile.in | 1 - layout/tools/reftest/b2g_desktop.py | 23 +- layout/tools/reftest/mach_commands.py | 478 +++++++---- layout/tools/reftest/reftest-cmdline.js | 33 +- layout/tools/reftest/reftest.js | 99 ++- layout/tools/reftest/reftestcommandline.py | 740 ------------------ layout/tools/reftest/remotereftest.py | 222 +++++- layout/tools/reftest/runreftest.py | 358 ++++++--- layout/tools/reftest/runreftestb2g.py | 254 +++++- testing/mach_commands.py | 7 +- .../configs/android/android_panda_releng.py | 11 +- .../mozharness/configs/android/androidarm.py | 57 +- .../configs/android/androidarm_4_3.py | 153 ++-- .../mozharness/configs/android/androidx86.py | 36 +- .../configs/b2g/emulator_automation_config.py | 7 +- .../configs/unittests/linux_unittest.py | 90 +-- .../configs/unittests/mac_unittest.py | 51 +- .../configs/unittests/win_unittest.py | 66 +- .../scripts/android_emulator_unittest.py | 9 - .../scripts/androidx86_emulator_unittest.py | 5 - .../scripts/b2g_desktop_unittest.py | 7 +- .../scripts/b2g_emulator_unittest.py | 8 +- .../mozharness/scripts/desktop_unittest.py | 4 +- testing/testsuite-targets.mk | 4 +- testing/xpcshell/Makefile.in | 1 - testing/xpcshell/mach_commands.py | 390 ++++++--- testing/xpcshell/remotexpcshelltests.py | 146 ++-- testing/xpcshell/runtestsb2g.py | 111 ++- testing/xpcshell/runxpcshelltests.py | 245 ++++-- testing/xpcshell/selftest.py | 1 + testing/xpcshell/xpcshellcommandline.py | 202 ----- 31 files changed, 1935 insertions(+), 1884 deletions(-) delete mode 100644 layout/tools/reftest/reftestcommandline.py delete mode 100644 testing/xpcshell/xpcshellcommandline.py diff --git a/layout/tools/reftest/Makefile.in b/layout/tools/reftest/Makefile.in index f64b2351a26f..044ae5fc1a61 100644 --- a/layout/tools/reftest/Makefile.in +++ b/layout/tools/reftest/Makefile.in @@ -7,7 +7,6 @@ _DEST_DIR = $(DEPTH)/_tests/reftest _HARNESS_FILES = \ $(srcdir)/runreftest.py \ - $(srcdir)/reftestcommandline.py \ $(srcdir)/remotereftest.py \ $(srcdir)/runreftestb2g.py \ $(srcdir)/b2g_desktop.py \ diff --git a/layout/tools/reftest/b2g_desktop.py b/layout/tools/reftest/b2g_desktop.py index 45c0cd6c6942..97a104b58fe5 100644 --- a/layout/tools/reftest/b2g_desktop.py +++ b/layout/tools/reftest/b2g_desktop.py @@ -9,7 +9,7 @@ import sys here = os.path.abspath(os.path.dirname(__file__)) -from runreftest import RefTest +from runreftest import RefTest, ReftestOptions from marionette_driver import expected from marionette_driver.by import By @@ -51,10 +51,12 @@ class B2GDesktopReftest(RefTest): f.close() self.marionette.execute_script(self.test_script) - def run_tests(self, tests, options): - manifests = self.resolver.resolveManifests(options, tests) + def run_tests(self, test_path, options): + reftestlist = self.getManifestPath(test_path) + if not reftestlist.startswith('file://'): + reftestlist = 'file://%s' % reftestlist - self.profile = self.create_profile(options, manifests, + self.profile = self.create_profile(options, reftestlist, profile_to_clone=options.profile) env = self.buildBrowserEnv(options, self.profile.profile) kp_kwargs = { 'processOutputLine': [self._on_output], @@ -105,8 +107,8 @@ class B2GDesktopReftest(RefTest): log.info("%s | Running tests: end.", os.path.basename(__file__)) return status - def create_profile(self, options, manifests, profile_to_clone=None): - profile = RefTest.createReftestProfile(self, options, manifests, + def create_profile(self, options, reftestlist, profile_to_clone=None): + profile = RefTest.createReftestProfile(self, options, reftestlist, profile_to_clone=profile_to_clone) prefs = {} @@ -134,6 +136,7 @@ class B2GDesktopReftest(RefTest): prefs["network.dns.localDomains"] = "app://test-container.gaiamobile.org" prefs["reftest.browser.iframe.enabled"] = False prefs["reftest.remote"] = False + prefs["reftest.uri"] = "%s" % reftestlist # Set a future policy version to avoid the telemetry prompt. prefs["toolkit.telemetry.prompted"] = 999 prefs["toolkit.telemetry.notifiedOptOut"] = 999 @@ -189,7 +192,7 @@ class MuletReftest(B2GDesktopReftest): Wait(self.marionette, timeout).until(expected.element_present( By.CSS_SELECTOR, '#homescreen[loading-state=false]')) -def run_desktop_reftests(parser, options): +def run_desktop_reftests(parser, options, args): marionette_args = {} if options.marionette: host, port = options.marionette.split(':') @@ -201,7 +204,9 @@ def run_desktop_reftests(parser, options): else: reftest = B2GDesktopReftest(marionette_args) - parser.validate(options, reftest) + options = ReftestOptions.verifyCommonOptions(parser, options, reftest) + if options == None: + sys.exit(1) # add a -bin suffix if b2g-bin exists, but just b2g was specified if options.app[-4:] != '-bin': @@ -214,4 +219,4 @@ def run_desktop_reftests(parser, options): if options.desktop and not options.profile: raise Exception("must specify --profile when specifying --desktop") - sys.exit(reftest.run_tests(options.tests, options)) + sys.exit(reftest.run_tests(args[0], options)) diff --git a/layout/tools/reftest/mach_commands.py b/layout/tools/reftest/mach_commands.py index d5a91700490a..e4b13e5f8204 100644 --- a/layout/tools/reftest/mach_commands.py +++ b/layout/tools/reftest/mach_commands.py @@ -23,7 +23,8 @@ from mach.decorators import ( Command, ) -import reftestcommandline + +DEBUGGER_HELP = 'Debugger binary to run test in. Program name or path.' ADB_NOT_FOUND = ''' The %s command requires the adb binary to be on your path. @@ -80,10 +81,43 @@ class ReftestRunner(MozbuildObject): self.tests_dir = os.path.join(self.topobjdir, '_tests') self.reftest_dir = os.path.join(self.tests_dir, 'reftest') + def _manifest_file(self, suite): + """Returns the manifest file used for a given test suite.""" + files = { + 'reftest': 'reftest.list', + 'reftest-ipc': 'reftest.list', + 'crashtest': 'crashtests.list', + 'crashtest-ipc': 'crashtests.list', + 'jstestbrowser': 'jstests.list' + } + assert suite in files + return files[suite] + + def _find_manifest(self, suite, test_file): + """Return a tuple of (manifest-path, filter-string) for running test_file. + + test_file can be a relative path to a single test file or manifest from + the top source directory, an absolute path to the same, or a directory + containing a manifest. + """ + assert test_file + path_arg = self._wrap_path_argument(test_file) + relpath = path_arg.relpath() + + if os.path.isdir(path_arg.srcdir_path()): + return (mozpath.join(relpath, self._manifest_file(suite)), None) + + if relpath.endswith('.list'): + return (relpath, None) + + return (self._find_manifest(suite, mozpath.dirname(test_file))[0], + mozpath.basename(test_file)) + def _make_shell_string(self, s): return "'%s'" % re.sub("'", r"'\''", s) - def run_b2g_test(self, b2g_home=None, xre_path=None, **kwargs): + def run_b2g_test(self, b2g_home=None, xre_path=None, test_file=None, + suite=None, filter=None, **kwargs): """Runs a b2g reftest. filter is a regular expression (in JS syntax, as could be passed to the @@ -96,189 +130,324 @@ class ReftestRunner(MozbuildObject): suite is the type of reftest to run. It can be one of ('reftest', 'crashtest'). """ - if kwargs["suite"] not in ('reftest', 'crashtest'): + if suite not in ('reftest', 'crashtest'): raise Exception('None or unrecognized reftest suite type.') - sys.path.insert(0, self.reftest_dir) - - test_subdir = {"reftest": os.path.join('layout', 'reftests'), - "crashtest": os.path.join('layout', 'crashtest')}[kwargs["suite"]] - # Find the manifest file - if not kwargs["tests"]: - if not os.path.exists(os.path.join(self.topsrcdir, test_subdir)): - test_file = mozpath.relpath(os.path.abspath(test_subdir), - self.topsrcdir) - kwargs["tests"] = [test_subdir] + if not test_file: + if suite == 'reftest': + test_file = mozpath.join('layout', 'reftests') + elif suite == 'crashtest': + test_file = mozpath.join('testing', 'crashtest') + if not os.path.exists(os.path.join(self.topsrcdir, test_file)): + test_file = mozpath.relpath(os.path.abspath(test_file), + self.topsrcdir) + + (manifest, single_file_filter) = self._find_manifest(suite, test_file) + if not os.path.exists(mozpath.join(self.topsrcdir, manifest)): + raise Exception('No manifest file was found at %s.' % manifest) + if single_file_filter: + if filter: + raise Exception('Cannot run single files in conjunction with --filter') + filter = single_file_filter + + # Need to chdir to reftest_dir otherwise imports fail below. + os.chdir(self.reftest_dir) + + # The imp module can spew warnings if the modules below have + # already been imported, ignore them. + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + + import imp + path = os.path.join(self.reftest_dir, 'runreftestb2g.py') + with open(path, 'r') as fh: + imp.load_module('reftest', fh, path, ('.py', 'r', imp.PY_SOURCE)) + import reftest + + # Set up the reftest options. + parser = reftest.B2GOptions() + options, args = parser.parse_args([]) + + # Tests need to be served from a subdirectory of the server. Symlink + # topsrcdir here to get around this. tests = os.path.join(self.reftest_dir, 'tests') if not os.path.isdir(tests): os.symlink(self.topsrcdir, tests) + args.insert(0, os.path.join('tests', manifest)) - for i, path in enumerate(kwargs["tests"]): - # Non-absolute paths are relative to the packaged directory, which - # has an extra tests/ at the start - if os.path.exists(os.path.abspath(path)): - path = os.path.relpath(path, os.path.join(self.topsrcdir)) - kwargs["tests"][i] = os.path.join('tests', path) + for k, v in kwargs.iteritems(): + setattr(options, k, v) if conditions.is_b2g_desktop(self): - return self.run_b2g_desktop(**kwargs) + if self.substs.get('ENABLE_MARIONETTE') != '1': + print(MARIONETTE_DISABLED % ('mochitest-b2g-desktop', + self.mozconfig['path'])) + return 1 - return self.run_b2g_remote(b2g_home, xre_path, **kwargs) - - def run_b2g_desktop(self, **kwargs): - if self.substs.get('ENABLE_MARIONETTE') != '1': - print(MARIONETTE_DISABLED % ('mochitest-b2g-desktop', - self.mozconfig['path'])) - return 1 - - if not kwargs["profile"]: - gaia_profile = os.environ.get('GAIA_PROFILE') - if not gaia_profile: + options.profile = options.profile or os.environ.get('GAIA_PROFILE') + if not options.profile: print(GAIA_PROFILE_NOT_FOUND % 'reftest-b2g-desktop') return 1 - kwargs["profile"] = gaia_profile + if os.path.isfile(os.path.join(options.profile, 'extensions', \ + 'httpd@gaiamobile.org')): + print(GAIA_PROFILE_IS_DEBUG % ('mochitest-b2g-desktop', + options.profile)) + return 1 - if os.path.isfile(os.path.join(kwargs["profile"], 'extensions', - 'httpd@gaiamobile.org')): - print(GAIA_PROFILE_IS_DEBUG % ('mochitest-b2g-desktop', - kwargs["profile"])) - return 1 + options.desktop = True + options.app = self.get_binary_path() + if options.oop: + options.browser_arg = '-oop' + if not options.app.endswith('-bin'): + options.app = '%s-bin' % options.app + if not os.path.isfile(options.app): + options.app = options.app[:-len('-bin')] - kwargs["desktop"] = True - kwargs["app"] = self.get_binary_path() - if kwargs["oop"]: - options.browser_arg = '-oop' - if not kwargs["app"].endswith('-bin'): - kwargs["app"] = '%s-bin' % options.app - if not os.path.isfile(kwargs["app"]): - options.app = kwargs["app"][:-len('-bin')] + return reftest.run_desktop_reftests(parser, options, args) - return runreftestb2g.run(**kwargs) - - def run_b2g_remote(self, b2g_home, xre_path, **kwargs): - import runreftestb2g try: which.which('adb') except which.WhichError: # TODO Find adb automatically if it isn't on the path - raise Exception(ADB_NOT_FOUND % ('%s-remote' % kwargs["suite"], b2g_home)) + raise Exception(ADB_NOT_FOUND % ('%s-remote' % suite, b2g_home)) - kwargs["b2gPath"] = b2g_home - kwargs["logdir"] = self.reftest_dir - kwargs["httpdPath"] = os.path.join(self.topsrcdir, 'netwerk', 'test', 'httpserver') - kwargs["xrePath"] = xre_path - kwargs["ignoreWindowSize"] = True + options.b2gPath = b2g_home + options.logdir = self.reftest_dir + options.httpdPath = os.path.join(self.topsrcdir, 'netwerk', 'test', 'httpserver') + options.xrePath = xre_path + options.ignoreWindowSize = True + options.filter = filter # Don't enable oop for crashtest until they run oop in automation - if kwargs["suite"] == 'reftest': - kwargs["oop"] = True + if suite == 'reftest': + options.oop = True - return runreftestb2g.run_remote(**kwargs) + return reftest.run_remote_reftests(parser, options, args) - def run_desktop_test(self, **kwargs): - """Runs a reftest.""" - import runreftest + def run_desktop_test(self, test_file=None, filter=None, suite=None, + debugger=None, debugger_args=None, parallel=False, shuffle=False, + e10s=False, extraPrefs=None, this_chunk=None, total_chunks=None): + """Runs a reftest. - if kwargs["suite"] not in ('reftest', 'crashtest', 'jstestbrowser'): + test_file is a path to a test file. It can be a relative path from the + top source directory, an absolute filename, or a directory containing + test files. + + filter is a regular expression (in JS syntax, as could be passed to the + RegExp constructor) to select which reftests to run from the manifest. + + suite is the type of reftest to run. It can be one of ('reftest', + 'crashtest', 'jstestbrowser'). + + debugger is the program name (in $PATH) or the full path of the + debugger to run. + + debugger_args are the arguments passed to the debugger. + + parallel indicates whether tests should be run in parallel or not. + + shuffle indicates whether to run tests in random order. + """ + + if suite not in ('reftest', 'reftest-ipc', 'crashtest', 'crashtest-ipc', 'jstestbrowser'): raise Exception('None or unrecognized reftest suite type.') - default_manifest = { - "reftest": (self.topsrcdir, "layout", "reftests", "reftest.list"), - "crashtest": (self.topsrcdir, "testing", "crashtest", "crashtests.list"), - "jstestbrowser": (self.topobjdir, "dist", "test-stage", "jsreftest", "tests", - "jstests.list") - } + env = {} + extra_args = [] - kwargs["extraProfileFiles"] = [os.path.join(self.topobjdir, "dist", "plugins")] - kwargs["symbolsPath"] = os.path.join(self.topobjdir, "crashreporter-symbols") + if test_file: + (path, single_file_filter) = self._find_manifest(suite, test_file) + if not os.path.exists(mozpath.join(self.topsrcdir, path)): + raise Exception('No manifest file was found at %s.' % path) + if single_file_filter: + if filter: + raise Exception('Cannot run single files in conjunction with --filter') + filter = single_file_filter + env[b'TEST_PATH'] = path + if filter: + extra_args.extend(['--filter', self._make_shell_string(filter)]) - if not kwargs["tests"]: - kwargs["tests"] = [os.path.join(*default_manifest[kwargs["suite"]])] + pass_thru = False - if kwargs["suite"] == "jstestbrowser": - kwargs["extraProfileFiles"].append(os.path.join(self.topobjdir, "dist", - "test-stage", "jsreftest", - "tests", "user.js")) + if debugger: + extra_args.append('--debugger=\'%s\'' % debugger) + pass_thru = True + if debugger_args: + # Use _make_shell_string (which quotes) so that we + # handle multiple args being passed to the debugger. + extra_args.extend(['--debugger-args', self._make_shell_string(debugger_args)]) + else: + if debugger_args: + print("--debugger-args passed, but no debugger specified.") + return 1 - if not kwargs["runTestsInParallel"]: - kwargs["logFile"] = "%s.log" % kwargs["suite"] + if parallel: + extra_args.append('--run-tests-in-parallel') - #Remove the stdout handler from the internal logger and let mach deal with it - runreftest.log.removeHandler(runreftest.log.handlers[0]) - self.log_manager.enable_unstructured() - rv = runreftest.run(**kwargs) - self.log_manager.disable_unstructured() + if shuffle: + extra_args.append('--shuffle') - return rv + if e10s: + extra_args.append('--e10s') + + if extraPrefs: + for pref in extraPrefs: + extra_args.extend(['--setpref', pref]) + + if this_chunk: + extra_args.append('--this-chunk=%s' % this_chunk) + + if total_chunks: + extra_args.append('--total-chunks=%s' % total_chunks) + + if extra_args: + args = [os.environ.get(b'EXTRA_TEST_ARGS', '')] + args.extend(extra_args) + env[b'EXTRA_TEST_ARGS'] = ' '.join(args) + + # TODO hook up harness via native Python + return self._run_make(directory='.', target=suite, append_env=env, + pass_thru=pass_thru, ensure_exit_code=False) -def process_test_objects(kwargs): - """|mach test| works by providing a test_objects argument, from - which the test path must be extracted and converted into a normal - reftest tests argument.""" +def ReftestCommand(func): + """Decorator that adds shared command arguments to reftest commands.""" - if "test_objects" in kwargs: - if kwargs["tests"] is None: - kwargs["tests"] = [] - kwargs["tests"].extend(item["path"] for item in kwargs["test_objects"]) - del kwargs["test_objects"] + debugger = CommandArgument('--debugger', metavar='DEBUGGER', + help=DEBUGGER_HELP) + func = debugger(func) + + debugger_args = CommandArgument('--debugger-args', metavar='DEBUGGER_ARGS', + help='Arguments to pass to the debugger.') + func = debugger_args(func) + + flter = CommandArgument('--filter', metavar='REGEX', + help='A JS regular expression to match test URLs against, to select ' + 'a subset of tests to run.') + func = flter(func) + + path = CommandArgument('test_file', nargs='?', metavar='MANIFEST', + help='Reftest manifest file, or a directory in which to select ' + 'reftest.list. If omitted, the entire test suite is executed.') + func = path(func) + + parallel = CommandArgument('--parallel', action='store_true', + help='Run tests in parallel.') + func = parallel(func) + + shuffle = CommandArgument('--shuffle', action='store_true', + help='Run tests in random order.') + func = shuffle(func) + + e10s = CommandArgument('--e10s', action='store_true', + help='Use content processes.') + func = e10s(func) + + extraPrefs = CommandArgument('--setpref', action='append', + default=[], dest='extraPrefs', metavar='PREF=VALUE', + help='Set prefs in the reftest profile.') + func = extraPrefs(func) + + totalChunks = CommandArgument('--total-chunks', + help = 'How many chunks to split the tests up into.') + func = totalChunks(func) + + thisChunk = CommandArgument('--this-chunk', + help = 'Which chunk to run between 1 and --total-chunks.') + func = thisChunk(func) + + return func + +def B2GCommand(func): + """Decorator that adds shared command arguments to b2g reftest commands.""" + + busybox = CommandArgument('--busybox', default=None, + help='Path to busybox binary to install on device') + func = busybox(func) + + logdir = CommandArgument('--logdir', default=None, + help='directory to store log files') + func = logdir(func) + + sdcard = CommandArgument('--sdcard', default="10MB", + help='Define size of sdcard: 1MB, 50MB...etc') + func = sdcard(func) + + emulator_res = CommandArgument('--emulator-res', default='800x1000', + help='Emulator resolution of the format \'x\'') + func = emulator_res(func) + + marionette = CommandArgument('--marionette', default=None, + help='host:port to use when connecting to Marionette') + func = marionette(func) + + totalChunks = CommandArgument('--total-chunks', dest='totalChunks', + type = int, + help = 'How many chunks to split the tests up into.') + func = totalChunks(func) + + thisChunk = CommandArgument('--this-chunk', dest='thisChunk', + type = int, + help = 'Which chunk to run between 1 and --total-chunks.') + func = thisChunk(func) + + flter = CommandArgument('--filter', metavar='REGEX', + help='A JS regular expression to match test URLs against, to select ' + 'a subset of tests to run.') + func = flter(func) + + oop = CommandArgument('--enable-oop', action='store_true', dest='oop', + help = 'Run tests in out-of-process mode.') + func = oop(func) + + path = CommandArgument('test_file', default=None, nargs='?', + metavar='TEST', + help='Test to run. Can be specified as a single file, a ' \ + 'directory, or omitted. If omitted, the entire test suite is ' \ + 'executed.') + func = path(func) + + return func @CommandProvider class MachCommands(MachCommandBase): - @Command('reftest', - category='testing', - description='Run reftests (layout and graphics correctness).', - parser=reftestcommandline.DesktopArgumentsParser) - def run_reftest(self, **kwargs): - kwargs["suite"] = "reftest" - return self._run_reftest(**kwargs) + @Command('reftest', category='testing', description='Run reftests (layout and graphics correctness).') + @ReftestCommand + def run_reftest(self, test_file, **kwargs): + return self._run_reftest(test_file, suite='reftest', **kwargs) - @Command('jstestbrowser', - category='testing', - description='Run js/src/tests in the browser.', - parser=reftestcommandline.DesktopArgumentsParser) - def run_jstestbrowser(self, **kwargs): - self._mach_context.commands.dispatch("build", - self._mach_context, - what=["stage-jstests"]) - kwargs["suite"] = "jstestbrowser" - return self._run_reftest(**kwargs) + @Command('jstestbrowser', category='testing', + description='Run js/src/tests in the browser.') + @ReftestCommand + def run_jstestbrowser(self, test_file, **kwargs): + return self._run_reftest(test_file, suite='jstestbrowser', **kwargs) - @Command('reftest-ipc', - category='testing', - description='Run IPC reftests (layout and graphics correctness, separate process).', - parser=reftestcommandline.DesktopArgumentsParser) - def run_ipc(self, **kwargs): - kwargs["ipc"] = True - kwargs["suite"] = "reftest" - return self._run_reftest(**kwargs) + @Command('reftest-ipc', category='testing', + description='Run IPC reftests (layout and graphics correctness, separate process).') + @ReftestCommand + def run_ipc(self, test_file, **kwargs): + return self._run_reftest(test_file, suite='reftest-ipc', **kwargs) - @Command('crashtest', - category='testing', - description='Run crashtests (Check if crashes on a page).', - parser=reftestcommandline.DesktopArgumentsParser) - def run_crashtest(self, **kwargs): - kwargs["suite"] = "crashtest" - return self._run_reftest(**kwargs) + @Command('crashtest', category='testing', + description='Run crashtests (Check if crashes on a page).') + @ReftestCommand + def run_crashtest(self, test_file, **kwargs): + return self._run_reftest(test_file, suite='crashtest', **kwargs) - @Command('crashtest-ipc', - category='testing', - description='Run IPC crashtests (Check if crashes on a page, separate process).', - parser=reftestcommandline.DesktopArgumentsParser) - def run_crashtest_ipc(self, **kwargs): - kwargs["ipc"] = True - kwargs["suite"] = "crashtest" - return self._run_reftest(**kwargs) + @Command('crashtest-ipc', category='testing', + description='Run IPC crashtests (Check if crashes on a page, separate process).') + @ReftestCommand + def run_crashtest_ipc(self, test_file, **kwargs): + return self._run_reftest(test_file, suite='crashtest-ipc', **kwargs) - def _run_reftest(self, **kwargs): - process_test_objects(kwargs) + def _run_reftest(self, test_file=None, suite=None, **kwargs): reftest = self._spawn(ReftestRunner) - return reftest.run_desktop_test(**kwargs) + return reftest.run_desktop_test(test_file, suite=suite, **kwargs) # TODO For now b2g commands will only work with the emulator, @@ -297,31 +466,27 @@ class B2GCommands(MachCommandBase): setattr(self, attr, getattr(context, attr, None)) @Command('reftest-remote', category='testing', - description='Run a remote reftest (b2g layout and graphics correctness, remote device).', - conditions=[conditions.is_b2g, is_emulator], - parser=reftestcommandline.B2GArgumentParser) - def run_reftest_remote(self, **kwargs): - kwargs["suite"] = "reftest" - return self._run_reftest(**kwargs) + description='Run a remote reftest (b2g layout and graphics correctness, remote device).', + conditions=[conditions.is_b2g, is_emulator]) + @B2GCommand + def run_reftest_remote(self, test_file, **kwargs): + return self._run_reftest(test_file, suite='reftest', **kwargs) @Command('reftest-b2g-desktop', category='testing', - description='Run a b2g desktop reftest (b2g desktop layout and graphics correctness).', - conditions=[conditions.is_b2g_desktop], - parser=reftestcommandline.B2GArgumentParser) - def run_reftest_b2g_desktop(self, **kwargs): - kwargs["suite"] = "reftest" - return self._run_reftest(**kwargs) + description='Run a b2g desktop reftest (b2g desktop layout and graphics correctness).', + conditions=[conditions.is_b2g_desktop]) + @B2GCommand + def run_reftest_b2g_desktop(self, test_file, **kwargs): + return self._run_reftest(test_file, suite='reftest', **kwargs) @Command('crashtest-remote', category='testing', - description='Run a remote crashtest (Check if b2g crashes on a page, remote device).', - conditions=[conditions.is_b2g, is_emulator], - parser=reftestcommandline.B2GArgumentParser) + description='Run a remote crashtest (Check if b2g crashes on a page, remote device).', + conditions=[conditions.is_b2g, is_emulator]) + @B2GCommand def run_crashtest_remote(self, test_file, **kwargs): - kwargs["suite"] = "crashtest" - return self._run_reftest(**kwargs) + return self._run_reftest(test_file, suite='crashtest', **kwargs) - def _run_reftest(self, **kwargs): - process_test_objects(kwargs) + def _run_reftest(self, test_file=None, suite=None, **kwargs): if self.device_name: if self.device_name.startswith('emulator'): emulator = 'arm' @@ -330,4 +495,5 @@ class B2GCommands(MachCommandBase): kwargs['emulator'] = emulator reftest = self._spawn(ReftestRunner) - return reftest.run_b2g_test(self.b2g_home, self.xre_path, **kwargs) + return reftest.run_b2g_test(self.b2g_home, self.xre_path, + test_file, suite=suite, **kwargs) diff --git a/layout/tools/reftest/reftest-cmdline.js b/layout/tools/reftest/reftest-cmdline.js index 5094f6b8bdc2..fde70c9c04ae 100644 --- a/layout/tools/reftest/reftest-cmdline.js +++ b/layout/tools/reftest/reftest-cmdline.js @@ -21,6 +21,37 @@ RefTestCmdLineHandler.prototype = /* nsICommandLineHandler */ handle : function handler_handle(cmdLine) { + var args = { }; + args.wrappedJSObject = args; + try { + var uristr = cmdLine.handleFlagWithParam("reftest", false); + if (uristr == null) + return; + try { + args.uri = cmdLine.resolveURI(uristr).spec; + } + catch (e) { + return; + } + } + catch (e) { + cmdLine.handleFlag("reftest", true); + } + + try { + var nocache = cmdLine.handleFlag("reftestnocache", false); + args.nocache = nocache; + } + catch (e) { + } + + try { + var skipslowtests = cmdLine.handleFlag("reftestskipslowtests", false); + args.skipslowtests = skipslowtests; + } + catch (e) { + } + /* Ignore the platform's online/offline status while running reftests. */ var ios = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService2); @@ -47,7 +78,7 @@ RefTestCmdLineHandler.prototype = function loadReftests() { wwatch.openWindow(null, "chrome://reftest/content/reftest.xul", "_blank", - "chrome,dialog=no,all", {}); + "chrome,dialog=no,all", args); } var remote = false; diff --git a/layout/tools/reftest/reftest.js b/layout/tools/reftest/reftest.js index b8dd5a030816..8bd0ed039d5b 100644 --- a/layout/tools/reftest/reftest.js +++ b/layout/tools/reftest/reftest.js @@ -48,7 +48,7 @@ var gShuffle = false; var gTotalChunks = 0; var gThisChunk = 0; var gContainingWindow = null; -var gURLFilterRegex = {}; +var gURLFilterRegex = null; const FOCUS_FILTER_ALL_TESTS = "all"; const FOCUS_FILTER_NEEDS_FOCUS_TESTS = "needs-focus"; const FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS = "non-needs-focus"; @@ -69,7 +69,6 @@ var gCanvas1, gCanvas2; // RecordResult. var gCurrentCanvas = null; var gURLs; -var gManifestsLoaded = {}; // Map from URI spec to the number of times it remains to be used var gURIUseCounts; // Map from URI spec to the canvas rendered for that URI @@ -390,6 +389,10 @@ function InitAndStartRefTests() gThisChunk = 0; } + try { + gURLFilterRegex = new RegExp(prefs.getCharPref("reftest.filter")); + } catch(e) {} + try { gFocusFilterMode = prefs.getCharPref("reftest.focusFilterMode"); } catch(e) {} @@ -446,7 +449,8 @@ function Shuffle(array) function StartTests() { - var manifests; + var uri; +#if BOOTSTRAP /* These prefs are optional, so we don't need to spit an error to the log */ try { var prefs = Components.classes["@mozilla.org/preferences-service;1"]. @@ -473,32 +477,41 @@ function StartTests() gRunSlowTests = false; } + try { + uri = prefs.getCharPref("reftest.uri"); + } catch(e) { + uri = ""; + } + + if (uri == "") { + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | Unable to find reftest.uri pref. Please ensure your profile is setup properly\n"); + DoneTests(); + } +#else + try { + // Need to read the manifest once we have gHttpServerPort.. + var args = window.arguments[0].wrappedJSObject; + + if ("nocache" in args && args["nocache"]) + gNoCanvasCache = true; + + if ("skipslowtests" in args && args.skipslowtests) + gRunSlowTests = false; + + uri = args.uri; + } catch (e) { + ++gTestResults.Exception; + gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n"); + DoneTests(); + } +#endif + if (gShuffle) { gNoCanvasCache = true; } - gURLs = []; - try { - var manifests = JSON.parse(prefs.getCharPref("reftest.manifests")); - gURLFilterRegex = manifests[null]; - } catch(e) { - gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | Unable to find reftest.manifests pref. Please ensure your profile is setup properly\n"); - DoneTests(); - } - - try { - var globalFilter = manifests.hasOwnProperty("") ? new RegExp(manifests[""]) : null; - var manifestURLs = Object.keys(manifests); - - // Ensure we read manifests from higher up the directory tree first so that we - // process includes before reading the included manifest again - manifestURLs.sort(function(a,b) {return a.length - b.length}) - manifestURLs.forEach(function(manifestURL) { - gDumpLog("Readings manifest" + manifestURL + "\n"); - var filter = manifests[manifestURL] ? new RegExp(manifests[manifestURL]) : null; - ReadTopManifest(manifestURL, [globalFilter, filter, false]); - }); + ReadTopManifest(uri); BuildUseCounts(); // Filter tests which will be skipped to get a more even distribution when chunking @@ -751,25 +764,18 @@ function AddPrefSettings(aWhere, aPrefName, aPrefValExpression, aSandbox, aTestP return true; } -function ReadTopManifest(aFileURL, aFilter) +function ReadTopManifest(aFileURL) { + gURLs = new Array(); var url = gIOService.newURI(aFileURL, null, null); if (!url) throw "Expected a file or http URL for the manifest."; - ReadManifest(url, EXPECTED_PASS, aFilter); + ReadManifest(url, EXPECTED_PASS); } -function AddTestItem(aTest, aFilter) +function AddTestItem(aTest) { - if (!aFilter) - aFilter = [null, [], false]; - - globalFilter = aFilter[0]; - manifestFilter = aFilter[1]; - invertManifest = aFilter[2]; - if ((globalFilter && !globalFilter.test(aTest.url1.spec)) || - (manifestFilter && - !(invertManifest ^ manifestFilter.test(aTest.url1.spec)))) + if (gURLFilterRegex && !gURLFilterRegex.test(aTest.url1.spec)) return; if (gFocusFilterMode == FOCUS_FILTER_NEEDS_FOCUS_TESTS && !aTest.needsFocus) @@ -782,19 +788,8 @@ function AddTestItem(aTest, aFilter) // Note: If you materially change the reftest manifest parsing, // please keep the parser in print-manifest-dirs.py in sync. -function ReadManifest(aURL, inherited_status, aFilter) +function ReadManifest(aURL, inherited_status) { - // Ensure each manifest is only read once. This assumes that manifests that are - // included with an unusual inherited_status or filters will be read via their - // include before they are read directly in the case of a duplicate - if (gManifestsLoaded.hasOwnProperty(aURL.spec)) { - if (gManifestsLoaded[aURL.spec] === null) - return; - else - aFilter = [aFilter[0], aFilter[1], true]; - } - gManifestsLoaded[aURL.spec] = aFilter[1]; - var secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID] .getService(CI.nsIScriptSecurityManager); @@ -1010,7 +1005,7 @@ function ReadManifest(aURL, inherited_status, aFilter) var incURI = gIOService.newURI(items[1], null, listURL); secMan.checkLoadURIWithPrincipal(principal, incURI, CI.nsIScriptSecurityManager.DISALLOW_SCRIPT); - ReadManifest(incURI, expected_status, aFilter); + ReadManifest(incURI, expected_status); } else if (items[0] == TYPE_LOAD) { if (items.length != 2) throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to load"; @@ -1040,7 +1035,7 @@ function ReadManifest(aURL, inherited_status, aFilter) fuzzyMaxPixels: fuzzy_max_pixels, url1: testURI, url2: null, - chaosMode: chaosMode }, aFilter); + chaosMode: chaosMode }); } else if (items[0] == TYPE_SCRIPT) { if (items.length != 2) throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to script"; @@ -1067,7 +1062,7 @@ function ReadManifest(aURL, inherited_status, aFilter) fuzzyMaxPixels: fuzzy_max_pixels, url1: testURI, url2: null, - chaosMode: chaosMode }, aFilter); + chaosMode: chaosMode }); } else if (items[0] == TYPE_REFTEST_EQUAL || items[0] == TYPE_REFTEST_NOTEQUAL) { if (items.length != 3) throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to " + items[0]; @@ -1097,7 +1092,7 @@ function ReadManifest(aURL, inherited_status, aFilter) fuzzyMaxPixels: fuzzy_max_pixels, url1: testURI, url2: refURI, - chaosMode: chaosMode }, aFilter); + chaosMode: chaosMode }); } else { throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": unknown test type " + items[0]; } diff --git a/layout/tools/reftest/reftestcommandline.py b/layout/tools/reftest/reftestcommandline.py deleted file mode 100644 index b258f9d48623..000000000000 --- a/layout/tools/reftest/reftestcommandline.py +++ /dev/null @@ -1,740 +0,0 @@ -import argparse -import os -from collections import OrderedDict -from urlparse import urlparse - -here = os.path.abspath(os.path.dirname(__file__)) - - -class ReftestArgumentsParser(argparse.ArgumentParser): - def __init__(self, **kwargs): - super(ReftestArgumentsParser, self).__init__(**kwargs) - - # Try to import a MozbuildObject. Success indicates that we are - # running from a source tree. This allows some defaults to be set - # from the source tree. - try: - from mozbuild.base import MozbuildObject - self.build_obj = MozbuildObject.from_environment(cwd=here) - except ImportError: - self.build_obj = None - - self.add_argument("--xre-path", - action="store", - type=str, - dest="xrePath", - # individual scripts will set a sane default - default=None, - help="absolute path to directory containing XRE (probably xulrunner)") - - self.add_argument("--symbols-path", - action="store", - type=str, - dest="symbolsPath", - default=None, - help="absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols") - - self.add_argument("--debugger", - action="store", - dest="debugger", - help="use the given debugger to launch the application") - - self.add_argument("--debugger-args", - action="store", - dest="debuggerArgs", - help="pass the given args to the debugger _before_ " - "the application on the command line") - - self.add_argument("--debugger-interactive", - action="store_true", - dest="debuggerInteractive", - help="prevents the test harness from redirecting " - "stdout and stderr for interactive debuggers") - - self.add_argument("--appname", - action="store", - type=str, - dest="app", - default=None, - help="absolute path to application, overriding default") - - self.add_argument("--extra-profile-file", - action="append", - dest="extraProfileFiles", - default=[], - help="copy specified files/dirs to testing profile") - - self.add_argument("--timeout", - action="store", - dest="timeout", - type=int, - default=5 * 60, # 5 minutes per bug 479518 - help="reftest will timeout in specified number of seconds. [default %(default)s].") - - self.add_argument("--leak-threshold", - action="store", - type=int, - dest="defaultLeakThreshold", - default=0, - help="fail if the number of bytes leaked in default " - "processes through refcounted objects (or bytes " - "in classes with MOZ_COUNT_CTOR and MOZ_COUNT_DTOR) " - "is greater than the given number") - - self.add_argument("--utility-path", - action="store", - type=str, - dest="utilityPath", - default="bindir", - help="absolute path to directory containing utility " - "programs (xpcshell, ssltunnel, certutil)") - - self.add_argument("--total-chunks", - type=int, - dest="totalChunks", - help="how many chunks to split the tests up into") - - self.add_argument("--this-chunk", - type=int, - dest="thisChunk", - help="which chunk to run between 1 and --total-chunks") - - self.add_argument("--log-file", - action="store", - type=str, - dest="logFile", - default=None, - help="file to log output to in addition to stdout") - - self.add_argument("--skip-slow-tests", - dest="skipSlowTests", - action="store_true", - default=False, - help="skip tests marked as slow when running") - - self.add_argument("--ignore-window-size", - dest="ignoreWindowSize", - action="store_true", - default=False, - help="ignore the window size, which may cause spurious failures and passes") - - self.add_argument("--install-extension", - action="append", - dest="extensionsToInstall", - default=[], - help="install the specified extension in the testing profile. " - "The extension file's name should be .xpi where is " - "the extension's id as indicated in its install.rdf. " - "An optional path can be specified too.") - - self.add_argument("--setenv", - action="append", - type=str, - default=[], - dest="environment", - metavar="NAME=VALUE", - help="sets the given variable in the application's " - "environment") - - self.add_argument("--filter", - action="store", - type=str, - dest="filter", - help="specifies a regular expression (as could be passed to the JS " - "RegExp constructor) to test against URLs in the reftest manifest; " - "only test items that have a matching test URL will be run.") - - self.add_argument("--shuffle", - action="store_true", - default=False, - dest="shuffle", - help="run reftests in random order") - - self.add_argument("--focus-filter-mode", - action="store", - type=str, - dest="focusFilterMode", - default="all", - help="filters tests to run by whether they require focus. " - "Valid values are `all', `needs-focus', or `non-needs-focus'. " - "Defaults to `all'.") - - self.add_argument("--e10s", - action="store_true", - default=False, - dest="e10s", - help="enables content processes") - - self.add_argument("--setpref", - action="append", - type=str, - default=[], - dest="extraPrefs", - metavar="PREF=VALUE", - help="defines an extra user preference") - - self.add_argument("--reftest-extension-path", - action="store", - dest="reftestExtensionPath", - help="Path to the reftest extension") - - self.add_argument("--special-powers-extension-path", - action="store", - dest="specialPowersExtensionPath", - help="Path to the special powers extension") - - self.add_argument("--suite", - choices=["reftest", "crashtest", "jstestbrowser"], - default=None, - help=argparse.SUPPRESS) - - self.add_argument("tests", - metavar="TEST_PATH", - nargs="*", - help="Path to test file, manifest file, or directory containing tests") - - def get_ip(self): - import moznetwork - if os.name != "nt": - return moznetwork.get_ip() - else: - self.error( - "ERROR: you must specify a --remote-webserver=\n") - - def set_default_suite(self, options): - manifests = OrderedDict([("reftest.list", "reftest"), - ("crashtests.list", "crashtest"), - ("jstests.list", "jstestbrowser")]) - - for test_path in options.tests: - file_name = os.path.basename(test_path) - if file_name in manifests: - options.suite = manifests[file_name] - return - - for test_path in options.tests: - for manifest_file, suite in manifests.iteritems(): - if os.path.exists(os.path.join(test_path, manifest_file)): - options.suite = suite - return - - self.error("Failed to determine test suite; supply --suite to set this explicitly") - - def validate(self, options, reftest): - import sys - - if not options.tests: - # Can't just set this in the argument parser because mach will set a default - self.error("Must supply at least one path to a manifest file, test directory, or test file to run.") - - if options.suite is None: - self.set_default_suite(options) - - if options.totalChunks is not None and options.thisChunk is None: - self.error( - "thisChunk must be specified when totalChunks is specified") - - if options.totalChunks: - if not 1 <= options.thisChunk <= options.totalChunks: - self.error("thisChunk must be between 1 and totalChunks") - - if options.logFile: - options.logFile = reftest.getFullPath(options.logFile) - - if options.xrePath is not None: - if not os.access(options.xrePath, os.F_OK): - self.error("--xre-path '%s' not found" % options.xrePath) - if not os.path.isdir(options.xrePath): - self.error("--xre-path '%s' is not a directory" % - options.xrePath) - options.xrePath = reftest.getFullPath(options.xrePath) - - if options.reftestExtensionPath is None: - if self.build_obj is not None: - options.reftestExtensionPath = os.path.join(self.build_obj.topobjdir, "_tests", - "reftest", "reftest") - else: - options.reftestExtensionPath = os.path.join(here, "reftest") - - if (options.specialPowersExtensionPath is None and - options.suite in ["crashtest", "jstestbrowser"]): - if self.build_obj is not None: - options.specialPowersExtensionPath = os.path.join(self.build_obj.topobjdir, "_tests", - "reftest", "specialpowers") - else: - options.specialPowersExtensionPath = os.path.join( - here, "specialpowers") - - options.leakThresholds = { - "default": options.defaultLeakThreshold, - "tab": 5000, # See dependencies of bug 1051230. - } - - -class DesktopArgumentsParser(ReftestArgumentsParser): - def __init__(self, **kwargs): - super(DesktopArgumentsParser, self).__init__(**kwargs) - - self.add_argument("--run-tests-in-parallel", - action="store_true", - default=False, - dest="runTestsInParallel", - help="run tests in parallel if possible") - - self.add_argument("--ipc", - action="store_true", - default=False, - help="Run in out-of-processes mode") - - def _prefs_oop(self): - import mozinfo - prefs = ["layers.async-pan-zoom.enabled=true", - "browser.tabs.remote.autostart=true"] - if mozinfo.os == "win": - prefs.append("layers.acceleration.disabled=true") - - return prefs - - def _prefs_gpu(self): - if mozinfo.os != "win": - return ["layers.acceleration.force-enabled=true"] - return [] - - def validate(self, options, reftest): - super(DesktopArgumentsParser, self).validate(options, reftest) - - if options.ipc: - for item in self._prefs_oop(): - if item not in options.extraPrefs: - options.extraPrefs.append(item) - - if options.runTestsInParallel: - if options.logFile is not None: - self.error("cannot specify logfile with parallel tests") - if options.totalChunks is not None or options.thisChunk is not None: - self.error( - "cannot specify thisChunk or totalChunks with parallel tests") - if options.focusFilterMode != "all": - self.error("cannot specify focusFilterMode with parallel tests") - if options.debugger is not None: - self.error("cannot specify a debugger with parallel tests") - - if not options.tests: - self.error("No test files specified.") - - if options.app is None: - bin_dir = (self.build_obj.get_binary_path() if - self.build_obj and self.build_obj.substs[ - 'MOZ_BUILD_APP'] != 'mobile/android' - else None) - - if bin_dir: - options.app = bin_dir - else: - self.error( - "could not find the application path, --appname must be specified") - - options.app = reftest.getFullPath(options.app) - if not os.path.exists(options.app): - self.error("""Error: Path %(app)s doesn't exist. - Are you executing $objdir/_tests/reftest/runreftest.py?""" - % {"app": options.app}) - - if options.xrePath is None: - options.xrePath = os.path.dirname(options.app) - - if options.symbolsPath and len(urlparse(options.symbolsPath).scheme) < 2: - options.symbolsPath = reftest.getFullPath(options.symbolsPath) - - options.utilityPath = reftest.getFullPath(options.utilityPath) - - -class B2GArgumentParser(ReftestArgumentsParser): - def __init__(self, **kwargs): - super(B2GArgumentParser, self).__init__(**kwargs) - - self.add_argument("--browser-arg", - action="store", - type=str, - dest="browser_arg", - help="Optional command-line arg to pass to the browser") - - self.add_argument("--b2gpath", - action="store", - type=str, - dest="b2gPath", - help="path to B2G repo or qemu dir") - - self.add_argument("--marionette", - action="store", - type=str, - dest="marionette", - help="host:port to use when connecting to Marionette") - - self.add_argument("--emulator", - action="store", - type=str, - dest="emulator", - help="Architecture of emulator to use: x86 or arm") - - self.add_argument("--emulator-res", - action="store", - type=str, - dest="emulator_res", - help="Emulator resolution of the format 'x'") - - self.add_argument("--no-window", - action="store_true", - dest="noWindow", - default=False, - help="Pass --no-window to the emulator") - - self.add_argument("--adbpath", - action="store", - type=str, - dest="adb_path", - default="adb", - help="path to adb") - - self.add_argument("--deviceIP", - action="store", - type=str, - dest="deviceIP", - help="ip address of remote device to test") - - self.add_argument("--devicePort", - action="store", - type=str, - dest="devicePort", - default="20701", - help="port of remote device to test") - - self.add_argument("--remote-logfile", - action="store", - type=str, - dest="remoteLogFile", - help="Name of log file on the device relative to the device root. PLEASE ONLY USE A FILENAME.") - - self.add_argument("--remote-webserver", - action="store", - type=str, - dest="remoteWebServer", - help="ip address where the remote web server is hosted at") - - self.add_argument("--http-port", - action="store", - type=str, - dest="httpPort", - help="ip address where the remote web server is hosted at") - - self.add_argument("--ssl-port", - action="store", - type=str, - dest="sslPort", - help="ip address where the remote web server is hosted at") - - self.add_argument("--pidfile", - action="store", - type=str, - dest="pidFile", - default="", - help="name of the pidfile to generate") - - self.add_argument("--gecko-path", - action="store", - type=str, - dest="geckoPath", - help="the path to a gecko distribution that should " - "be installed on the emulator prior to test") - - self.add_argument("--logdir", - action="store", - type=str, - dest="logdir", - help="directory to store log files") - - self.add_argument('--busybox', - action='store', - type=str, - dest='busybox', - help="Path to busybox binary to install on device") - - self.add_argument("--httpd-path", - action="store", - type=str, - dest="httpdPath", - help="path to the httpd.js file") - - self.add_argument("--profile", - action="store", - type=str, - dest="profile", - help="for desktop testing, the path to the " - "gaia profile to use") - - self.add_argument("--desktop", - action="store_true", - dest="desktop", - default=False, - help="Run the tests on a B2G desktop build") - - self.add_argument("--mulet", - action="store_true", - dest="mulet", - default=False, - help="Run the tests on a B2G desktop build") - - self.add_argument("--enable-oop", - action="store_true", - dest="oop", - default=False, - help="Run the tests out of process") - - self.set_defaults(remoteTestRoot=None, - logFile="reftest.log", - autorun=True, - closeWhenDone=True, - testPath="") - - def validate_remote(self, options, automation): - if not options.app: - options.app = automation.DEFAULT_APP - - if not options.remoteTestRoot: - options.remoteTestRoot = automation._devicemanager.deviceRoot + \ - "/reftest" - - options.remoteProfile = options.remoteTestRoot + "/profile" - - productRoot = options.remoteTestRoot + "/" + automation._product - if options.utilityPath is None: - options.utilityPath = productRoot + "/bin" - - if not options.httpPort: - options.httpPort = automation.DEFAULT_HTTP_PORT - - if not options.sslPort: - options.sslPort = automation.DEFAULT_SSL_PORT - - if options.remoteWebServer is None: - options.remoteWebServer = self.get_ip() - - options.webServer = options.remoteWebServer - - if options.geckoPath and not options.emulator: - self.error( - "You must specify --emulator if you specify --gecko-path") - - if options.logdir and not options.emulator: - self.error("You must specify --emulator if you specify --logdir") - - if options.remoteLogFile is None: - options.remoteLogFile = "reftest.log" - - options.localLogName = options.remoteLogFile - options.remoteLogFile = options.remoteTestRoot + \ - '/' + options.remoteLogFile - - # Ensure that the options.logfile (which the base class uses) is set to - # the remote setting when running remote. Also, if the user set the - # log file name there, use that instead of reusing the remotelogfile as - # above. - if (options.logFile): - # If the user specified a local logfile name use that - options.localLogName = options.logFile - options.logFile = options.remoteLogFile - - # Only reset the xrePath if it wasn't provided - if options.xrePath is None: - options.xrePath = options.utilityPath - options.xrePath = os.path.abspath(options.xrePath) - - if options.pidFile != "": - f = open(options.pidFile, 'w') - f.write("%s" % os.getpid()) - f.close() - - # httpd-path is specified by standard makefile targets and may be specified - # on the command line to select a particular version of httpd.js. If not - # specified, try to select the one from from the xre bundle, as - # required in bug 882932. - if not options.httpdPath: - options.httpdPath = os.path.join(options.xrePath, "components") - - return options - - -class RemoteArgumentsParser(ReftestArgumentsParser): - def __init__(self, **kwargs): - super(RemoteArgumentsParser, self).__init__() - - # app, xrePath and utilityPath variables are set in main function - self.set_defaults(logFile="reftest.log", - app="", - xrePath="", - utilityPath="", - localLogName=None) - - self.add_argument("--remote-app-path", - action="store", - type=str, - dest="remoteAppPath", - help="Path to remote executable relative to device root using only forward slashes. Either this or app must be specified, but not both.") - - self.add_argument("--deviceIP", - action="store", - type=str, - dest="deviceIP", - help="ip address of remote device to test") - - self.add_argument("--deviceSerial", - action="store", - type=str, - dest="deviceSerial", - help="adb serial number of remote device to test") - - self.add_argument("--devicePort", - action="store", - type=str, - default="20701", - dest="devicePort", - help="port of remote device to test") - - self.add_argument("--remote-product-name", - action="store", - type=str, - dest="remoteProductName", - default="fennec", - help="Name of product to test - either fennec or firefox, defaults to fennec") - - self.add_argument("--remote-webserver", - action="store", - type=str, - dest="remoteWebServer", - help="IP Address of the webserver hosting the reftest content") - - self.add_argument("--http-port", - action="store", - type=str, - dest="httpPort", - help="port of the web server for http traffic") - - self.add_argument("--ssl-port", - action="store", - type=str, - dest="sslPort", - help="Port for https traffic to the web server") - - self.add_argument("--remote-logfile", - action="store", - type=str, - dest="remoteLogFile", - default="reftest.log", - help="Name of log file on the device relative to device root. PLEASE USE ONLY A FILENAME.") - - self.add_argument("--pidfile", - action="store", - type=str, - dest="pidFile", - default="", - help="name of the pidfile to generate") - - self.add_argument("--bootstrap", - action="store_true", - dest="bootstrap", - default=False, - help="test with a bootstrap addon required for native Fennec") - - self.add_argument("--dm_trans", - action="store", - type=str, - dest="dm_trans", - default="sut", - help="the transport to use to communicate with device: [adb|sut]; default=sut") - - self.add_argument("--remoteTestRoot", - action="store", - type=str, - dest="remoteTestRoot", - help="remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)") - - self.add_argument("--httpd-path", - action="store", - type=str, - dest="httpdPath", - help="path to the httpd.js file") - - def validate_remote(self, options, automation): - # Ensure our defaults are set properly for everything we can infer - if not options.remoteTestRoot: - options.remoteTestRoot = automation._devicemanager.deviceRoot + \ - '/reftest' - options.remoteProfile = options.remoteTestRoot + "/profile" - - if options.remoteWebServer is None: - options.remoteWebServer = self.get_ip() - - # Verify that our remotewebserver is set properly - if options.remoteWebServer == '127.0.0.1': - self.error("ERROR: Either you specified the loopback for the remote webserver or ", - "your local IP cannot be detected. Please provide the local ip in --remote-webserver") - - if not options.httpPort: - options.httpPort = automation.DEFAULT_HTTP_PORT - - if not options.sslPort: - options.sslPort = automation.DEFAULT_SSL_PORT - - # One of remoteAppPath (relative path to application) or the app (executable) must be - # set, but not both. If both are set, we destroy the user's selection for app - # so instead of silently destroying a user specificied setting, we - # error. - if options.remoteAppPath and options.app: - self.error( - "ERROR: You cannot specify both the remoteAppPath and the app") - elif options.remoteAppPath: - options.app = options.remoteTestRoot + "/" + options.remoteAppPath - elif options.app is None: - # Neither remoteAppPath nor app are set -- error - self.error("ERROR: You must specify either appPath or app") - - if options.xrePath is None: - self.error( - "ERROR: You must specify the path to the controller xre directory") - else: - # Ensure xrepath is a full path - options.xrePath = os.path.abspath(options.xrePath) - - options.localLogName = options.remoteLogFile - options.remoteLogFile = options.remoteTestRoot + \ - '/' + options.remoteLogFile - - # Ensure that the options.logfile (which the base class uses) is set to - # the remote setting when running remote. Also, if the user set the - # log file name there, use that instead of reusing the remotelogfile as - # above. - if options.logFile: - # If the user specified a local logfile name use that - options.localLogName = options.logFile - - options.logFile = options.remoteLogFile - - if options.pidFile != "": - with open(options.pidFile, 'w') as f: - f.write(str(os.getpid())) - - # httpd-path is specified by standard makefile targets and may be specified - # on the command line to select a particular version of httpd.js. If not - # specified, try to select the one from hostutils.zip, as required in - # bug 882932. - if not options.httpdPath: - options.httpdPath = os.path.join(options.utilityPath, "components") - - if not options.ignoreWindowSize: - parts = automation._devicemanager.getInfo( - 'screen')['screen'][0].split() - width = int(parts[0].split(':')[1]) - height = int(parts[1].split(':')[1]) - if (width < 1050 or height < 1050): - self.error("ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % ( - width, height)) diff --git a/layout/tools/reftest/remotereftest.py b/layout/tools/reftest/remotereftest.py index 89c1ae3056c2..697e988d70ec 100644 --- a/layout/tools/reftest/remotereftest.py +++ b/layout/tools/reftest/remotereftest.py @@ -9,9 +9,10 @@ import tempfile import traceback # We need to know our current directory so that we can serve our test files from it. -SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(__file__))) +SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0]))) -from runreftest import RefTest, ReftestResolver +from runreftest import RefTest +from runreftest import ReftestOptions from automation import Automation import devicemanager import droid @@ -19,26 +20,159 @@ import mozinfo import moznetwork from remoteautomation import RemoteAutomation, fennecLogcatFilters -import reftestcommandline +class RemoteOptions(ReftestOptions): + def __init__(self, automation): + ReftestOptions.__init__(self) + self.automation = automation -class RemoteReftestResolver(ReftestResolver): - def absManifestPath(self, path): - script_abs_path = os.path.join(SCRIPT_DIRECTORY, path) - if os.path.exists(script_abs_path): - rv = script_abs_path - elif os.path.exists(os.path.abspath(path)): - rv = os.path.abspath(path) + defaults = {} + defaults["logFile"] = "reftest.log" + # app, xrePath and utilityPath variables are set in main function + defaults["app"] = "" + defaults["xrePath"] = "" + defaults["utilityPath"] = "" + defaults["runTestsInParallel"] = False + + self.add_option("--remote-app-path", action="store", + type = "string", dest = "remoteAppPath", + help = "Path to remote executable relative to device root using only forward slashes. Either this or app must be specified, but not both.") + defaults["remoteAppPath"] = None + + self.add_option("--deviceIP", action="store", + type = "string", dest = "deviceIP", + help = "ip address of remote device to test") + defaults["deviceIP"] = None + + self.add_option("--deviceSerial", action="store", + type = "string", dest = "deviceSerial", + help = "adb serial number of remote device to test") + defaults["deviceSerial"] = None + + self.add_option("--devicePort", action="store", + type = "string", dest = "devicePort", + help = "port of remote device to test") + defaults["devicePort"] = 20701 + + self.add_option("--remote-product-name", action="store", + type = "string", dest = "remoteProductName", + help = "Name of product to test - either fennec or firefox, defaults to fennec") + defaults["remoteProductName"] = "fennec" + + self.add_option("--remote-webserver", action="store", + type = "string", dest = "remoteWebServer", + help = "IP Address of the webserver hosting the reftest content") + defaults["remoteWebServer"] = moznetwork.get_ip() + + self.add_option("--http-port", action = "store", + type = "string", dest = "httpPort", + help = "port of the web server for http traffic") + defaults["httpPort"] = automation.DEFAULT_HTTP_PORT + + self.add_option("--ssl-port", action = "store", + type = "string", dest = "sslPort", + help = "Port for https traffic to the web server") + defaults["sslPort"] = automation.DEFAULT_SSL_PORT + + self.add_option("--remote-logfile", action="store", + type = "string", dest = "remoteLogFile", + help = "Name of log file on the device relative to device root. PLEASE USE ONLY A FILENAME.") + defaults["remoteLogFile"] = None + + self.add_option("--pidfile", action = "store", + type = "string", dest = "pidFile", + help = "name of the pidfile to generate") + defaults["pidFile"] = "" + + self.add_option("--bootstrap", action="store_true", dest = "bootstrap", + help = "test with a bootstrap addon required for native Fennec") + defaults["bootstrap"] = False + + self.add_option("--dm_trans", action="store", + type = "string", dest = "dm_trans", + help = "the transport to use to communicate with device: [adb|sut]; default=sut") + defaults["dm_trans"] = "sut" + + self.add_option("--remoteTestRoot", action = "store", + type = "string", dest = "remoteTestRoot", + help = "remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)") + defaults["remoteTestRoot"] = None + + self.add_option("--httpd-path", action = "store", + type = "string", dest = "httpdPath", + help = "path to the httpd.js file") + defaults["httpdPath"] = None + + defaults["localLogName"] = None + + self.set_defaults(**defaults) + + def verifyRemoteOptions(self, options): + if options.runTestsInParallel: + self.error("Cannot run parallel tests here") + + # Ensure our defaults are set properly for everything we can infer + if not options.remoteTestRoot: + options.remoteTestRoot = self.automation._devicemanager.deviceRoot + '/reftest' + options.remoteProfile = options.remoteTestRoot + "/profile" + + # Verify that our remotewebserver is set properly + if (options.remoteWebServer == None or + options.remoteWebServer == '127.0.0.1'): + print "ERROR: Either you specified the loopback for the remote webserver or ", + print "your local IP cannot be detected. Please provide the local ip in --remote-webserver" + return None + + # One of remoteAppPath (relative path to application) or the app (executable) must be + # set, but not both. If both are set, we destroy the user's selection for app + # so instead of silently destroying a user specificied setting, we error. + if (options.remoteAppPath and options.app): + print "ERROR: You cannot specify both the remoteAppPath and the app" + return None + elif (options.remoteAppPath): + options.app = options.remoteTestRoot + "/" + options.remoteAppPath + elif (options.app == None): + # Neither remoteAppPath nor app are set -- error + print "ERROR: You must specify either appPath or app" + return None + + if (options.xrePath == None): + print "ERROR: You must specify the path to the controller xre directory" + return None else: - print >> sys.stderr, "Could not find manifest %s" % script_abs_path - sys.exit(1) - return os.path.normpath(rv) + # Ensure xrepath is a full path + options.xrePath = os.path.abspath(options.xrePath) - def manifestURL(self, options, path): - # Dynamically build the reftest URL if possible, beware that args[0] should exist 'inside' the webroot - # It's possible for this url to have a leading "..", but reftest.js will fix that up - relPath = os.path.relpath(path, SCRIPT_DIRECTORY) - return "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, relPath) + # Default to /reftest/reftest.log + if (options.remoteLogFile == None): + options.remoteLogFile = 'reftest.log' + options.localLogName = options.remoteLogFile + options.remoteLogFile = options.remoteTestRoot + '/' + options.remoteLogFile + + # Ensure that the options.logfile (which the base class uses) is set to + # the remote setting when running remote. Also, if the user set the + # log file name there, use that instead of reusing the remotelogfile as above. + if (options.logFile): + # If the user specified a local logfile name use that + options.localLogName = options.logFile + + options.logFile = options.remoteLogFile + + if (options.pidFile != ""): + f = open(options.pidFile, 'w') + f.write("%s" % os.getpid()) + f.close() + + # httpd-path is specified by standard makefile targets and may be specified + # on the command line to select a particular version of httpd.js. If not + # specified, try to select the one from hostutils.zip, as required in bug 882932. + if not options.httpdPath: + options.httpdPath = os.path.join(options.utilityPath, "components") + + # TODO: Copied from main, but I think these are no longer used in a post xulrunner world + #options.xrePath = options.remoteTestRoot + self.automation._product + '/xulrunner' + #options.utilityPath = options.testRoot + self.automation._product + '/bin' + return options class ReftestServer: """ Web server used to serve Reftests, for closer fidelity to the real web. @@ -126,7 +260,6 @@ class ReftestServer: class RemoteReftest(RefTest): remoteApp = '' - resolver_cls = RemoteReftestResolver def __init__(self, automation, devicemanager, options, scriptDir): RefTest.__init__(self) @@ -209,12 +342,8 @@ class RemoteReftest(RefTest): def stopWebServer(self, options): self.server.stop() - def createReftestProfile(self, options, manifest): - profile = RefTest.createReftestProfile(self, - options, - manifest, - server=options.remoteWebServer, - port=options.httpPort) + def createReftestProfile(self, options, reftestlist): + profile = RefTest.createReftestProfile(self, options, reftestlist, server=options.remoteWebServer, port=options.httpPort) profileDir = profile.profile prefs = {} @@ -226,6 +355,7 @@ class RemoteReftest(RefTest): # Set a future policy version to avoid the telemetry prompt. prefs["toolkit.telemetry.prompted"] = 999 prefs["toolkit.telemetry.notifiedOptOut"] = 999 + prefs["reftest.uri"] = "%s" % reftestlist prefs["datareporting.policy.dataSubmissionPolicyBypassAcceptance"] = True # Point the url-classifier to the local testing server for fast failures @@ -280,6 +410,9 @@ class RemoteReftest(RefTest): print "Automation Error: Failed to copy extra files to device" raise + def getManifestPath(self, path): + return path + def printDeviceInfo(self, printLogcat=False): try: if printLogcat: @@ -340,10 +473,10 @@ class RemoteReftest(RefTest): except: print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % self.pidFile -def main(): +def main(args): automation = RemoteAutomation(None) - parser = reftestcommandline.RemoteArgumentsParser() - options = parser.parse_args() + parser = RemoteOptions(automation) + options, args = parser.parse_args() if (options.dm_trans == 'sut' and options.deviceIP == None): print "Error: If --dm_trans = sut, you must provide a device IP to connect to via the --deviceIP option" @@ -369,7 +502,18 @@ def main(): automation.setProduct(options.remoteProductName) # Set up the defaults and ensure options are set - parser.validate_remote(options, automation) + options = parser.verifyRemoteOptions(options) + if (options == None): + print "ERROR: Invalid options specified, use --help for a list of valid options" + return 1 + + if not options.ignoreWindowSize: + parts = dm.getInfo('screen')['screen'][0].split() + width = int(parts[0].split(':')[1]) + height = int(parts[1].split(':')[1]) + if (width < 1050 or height < 1050): + print "ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % (width, height) + return 1 # Check that Firefox is installed expected = options.app.split('/')[-1] @@ -382,7 +526,7 @@ def main(): automation.setRemoteProfile(options.remoteProfile) automation.setRemoteLog(options.remoteLogFile) reftest = RemoteReftest(automation, dm, options, SCRIPT_DIRECTORY) - parser.validate(options, reftest) + options = parser.verifyCommonOptions(options, reftest) if mozinfo.info['debug']: print "changing timeout for remote debug reftests from %s to 600 seconds" % options.timeout @@ -391,6 +535,17 @@ def main(): # Hack in a symbolic link for jsreftest os.system("ln -s ../jsreftest " + str(os.path.join(SCRIPT_DIRECTORY, "jsreftest"))) + # Dynamically build the reftest URL if possible, beware that args[0] should exist 'inside' the webroot + manifest = args[0] + if os.path.exists(os.path.join(SCRIPT_DIRECTORY, args[0])): + manifest = "http://" + str(options.remoteWebServer) + ":" + str(options.httpPort) + "/" + args[0] + elif os.path.exists(args[0]): + manifestPath = os.path.abspath(args[0]).split(SCRIPT_DIRECTORY)[1].strip('/') + manifest = "http://" + str(options.remoteWebServer) + ":" + str(options.httpPort) + "/" + manifestPath + else: + print "ERROR: Could not find test manifest '%s'" % manifest + return 1 + # Start the webserver retVal = reftest.startWebServer(options) if retVal: @@ -406,8 +561,11 @@ def main(): # manifest = "http://" + options.remoteWebServer + "/reftests/layout/reftests/reftest-sanity/reftest.list" retVal = 0 try: + cmdlineArgs = ["-reftest", manifest] + if options.bootstrap: + cmdlineArgs = [] dm.recordLogcat() - retVal = reftest.runTests(options.tests, options) + retVal = reftest.runTests(manifest, options, cmdlineArgs) except: print "Automation Error: Exception caught while running tests" traceback.print_exc() @@ -420,5 +578,5 @@ def main(): return retVal if __name__ == "__main__": - sys.exit(main()) + sys.exit(main(sys.argv[1:])) diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py index 8853b283b46d..2c5bb2016150 100644 --- a/layout/tools/reftest/runreftest.py +++ b/layout/tools/reftest/runreftest.py @@ -6,8 +6,9 @@ Runs the reftest test harness. """ +from optparse import OptionParser +from urlparse import urlparse import collections -import json import multiprocessing import os import re @@ -18,9 +19,8 @@ import sys import threading SCRIPT_DIRECTORY = os.path.abspath( - os.path.realpath(os.path.dirname(__file__))) -if SCRIPT_DIRECTORY not in sys.path: - sys.path.insert(0, SCRIPT_DIRECTORY) + os.path.realpath(os.path.dirname(sys.argv[0]))) +sys.path.insert(0, SCRIPT_DIRECTORY) import mozcrash import mozdebug @@ -32,7 +32,13 @@ import mozrunner from mozrunner.utils import get_stack_fixer_function, test_environment from mozscreenshot import printstatus, dump_screen -import reftestcommandline +here = os.path.abspath(os.path.dirname(__file__)) + +try: + from mozbuild.base import MozbuildObject + build_obj = MozbuildObject.from_environment(cwd=here) +except ImportError: + build_obj = None # set up logging handler a la automation.py.in for compatability import logging @@ -126,86 +132,14 @@ class ReftestThread(threading.Thread): if summaryHeadRegex.search(line) is None: yield line -class ReftestResolver(object): - def defaultManifest(self, suite): - return {"reftest": "reftest.list", - "crashtest": "crashtests.list", - "jstestbrowser": "jstests.list"}[suite] - - def directoryManifest(self, suite, path): - return os.path.join(path, self.defaultManifest(suite)) - - def findManifest(self, suite, test_file, subdirs=True): - """Return a tuple of (manifest-path, filter-string) for running test_file. - - test_file is a path to a test or a manifest file - """ - rv = [] - default_manifest = self.defaultManifest(suite) - if not os.path.isabs(test_file): - test_file = self.absManifestPath(test_file) - - if os.path.isdir(test_file): - for dirpath, dirnames, filenames in os.walk(test_file): - if default_manifest in filenames: - rv.append((os.path.join(dirpath, default_manifest), None)) - # We keep recursing into subdirectories which means that in the case - # of include directives we get the same manifest multiple times. - # However reftest.js will only read each manifest once - - elif test_file.endswith('.list'): - if os.path.exists(test_file): - rv = [(test_file, None)] - else: - dirname, pathname = os.path.split(test_file) - found = True - while not os.path.exists(os.path.join(dirname, default_manifest)): - dirname, suffix = os.path.split(dirname) - pathname = os.path.join(suffix, pathname) - if os.path.dirname(dirname) == dirname: - found = False - break - if found: - rv = [(os.path.join(dirname, default_manifest), - r".*(?:/|\\)%s$" % pathname)] - - return rv - - def absManifestPath(self, path): - return os.path.normpath(os.path.abspath(path)) - - def manifestURL(self, options, path): - return "file://%s" % path - - def resolveManifests(self, options, tests): - suite = options.suite - manifests = {} - for testPath in tests: - for manifest, filter_str in self.findManifest(suite, testPath): - manifest = self.manifestURL(options, manifest) - if manifest not in manifests: - manifests[manifest] = set() - manifests[manifest].add(filter_str) - - for key in manifests.iterkeys(): - if os.path.split(key)[1] != self.defaultManifest(suite): - print >> sys.stderr, "Invalid manifest for suite %s, %s" %(options.suite, key) - sys.exit(1) - if None in manifests[key]: - manifests[key] = None - else: - manifests[key] = "|".join(list(manifests[key])) - return manifests class RefTest(object): oldcwd = os.getcwd() - resolver_cls = ReftestResolver def __init__(self): self.update_mozinfo() self.lastTestSeen = 'reftest' self.haveDumpedScreen = False - self.resolver = self.resolver_cls() def update_mozinfo(self): """walk up directories to find mozinfo.json update the info""" @@ -224,15 +158,30 @@ class RefTest(object): "Get an absolute path relative to self.oldcwd." return os.path.normpath(os.path.join(self.oldcwd, os.path.expanduser(path))) - def createReftestProfile(self, options, manifests, server='localhost', port=0, - profile_to_clone=None): - """Sets up a profile for reftest. + def getManifestPath(self, path): + "Get the path of the manifest, and for remote testing this function is subclassed to point to remote manifest" + path = self.getFullPath(path) + if os.path.isdir(path): + defaultManifestPath = os.path.join(path, 'reftest.list') + if os.path.exists(defaultManifestPath): + path = defaultManifestPath + else: + defaultManifestPath = os.path.join(path, 'crashtests.list') + if os.path.exists(defaultManifestPath): + path = defaultManifestPath + return path - :param options: Object containing command line options - :param manifests: Dictionary of the form {manifest_path: [filters]} - :param server: Server name to use for http tests - :param profile_to_clone: Path to a profile to use as the basis for the - test profile""" + def makeJSString(self, s): + return '"%s"' % re.sub(r'([\\"])', r'\\\1', s) + + def createReftestProfile(self, options, manifest, server='localhost', port=0, + special_powers=True, profile_to_clone=None): + """ + Sets up a profile for reftest. + 'manifest' is the path to the reftest.list file we want to test with. This is used in + the remote subclass in remotereftest.py so we can write it to a preference for the + bootstrap extension. + """ locations = mozprofile.permissions.ServerLocations() locations.add_host(server, scheme='http', port=port) @@ -251,10 +200,11 @@ class RefTest(object): prefs['reftest.logFile'] = options.logFile if options.ignoreWindowSize: prefs['reftest.ignoreWindowSize'] = True + if options.filter: + prefs['reftest.filter'] = options.filter if options.shuffle: prefs['reftest.shuffle'] = True prefs['reftest.focusFilterMode'] = options.focusFilterMode - prefs['reftest.manifests'] = json.dumps(manifests) # Ensure that telemetry is disabled, so we don't connect to the telemetry # server in the middle of the tests. @@ -299,10 +249,13 @@ class RefTest(object): thispref[1].strip()) # install the reftest extension bits into the profile - addons = [options.reftestExtensionPath] + addons = [] + addons.append(os.path.join(SCRIPT_DIRECTORY, "reftest")) - if options.specialPowersExtensionPath is not None: - addons.append(options.specialPowersExtensionPath) + # I would prefer to use "--install-extension reftest/specialpowers", but that requires tight coordination with + # release engineering and landing on multiple branches at once. + if special_powers and (manifest.endswith('crashtests.list') or manifest.endswith('jstests.list')): + addons.append(os.path.join(SCRIPT_DIRECTORY, 'specialpowers')) # SpecialPowers requires insecure automation-only features that we # put behind a pref. prefs['security.turn_off_all_security_so_that_viruses_can_take_over_this_computer'] = True @@ -383,7 +336,7 @@ class RefTest(object): if profileDir: shutil.rmtree(profileDir, True) - def runTests(self, tests, options, cmdlineArgs=None): + def runTests(self, testPath, options, cmdlineArgs=None): # Despite our efforts to clean up servers started by this script, in practice # we still see infrequent cases where a process is orphaned and interferes # with future tests, typically because the old server is keeping the port in use. @@ -392,12 +345,8 @@ class RefTest(object): self.killNamedOrphans('ssltunnel') self.killNamedOrphans('xpcshell') - manifests = self.resolver.resolveManifests(options, tests) - if options.filter: - manifests[""] = options.filter - - if not hasattr(options, "runTestsInParallel") or not options.runTestsInParallel: - return self.runSerialTests(manifests, options, cmdlineArgs) + if not options.runTestsInParallel: + return self.runSerialTests(testPath, options, cmdlineArgs) cpuCount = multiprocessing.cpu_count() @@ -428,6 +377,7 @@ class RefTest(object): jobArgs.remove("--run-tests-in-parallel") except: pass + jobArgs.insert(-1, "--no-run-tests-in-parallel") jobArgs[0:0] = [sys.executable, "-u"] threads = [ReftestThread(args) for args in perProcessArgs[1:]] @@ -650,7 +600,7 @@ class RefTest(object): status = 1 return status - def runSerialTests(self, manifests, options, cmdlineArgs=None): + def runSerialTests(self, testPath, options, cmdlineArgs=None): debuggerInfo = None if options.debugger: debuggerInfo = mozdebug.get_debugger_info(options.debugger, options.debuggerArgs, @@ -658,9 +608,10 @@ class RefTest(object): profileDir = None try: + reftestlist = self.getManifestPath(testPath) if cmdlineArgs == None: - cmdlineArgs = [] - profile = self.createReftestProfile(options, manifests) + cmdlineArgs = ['-reftest', reftestlist] + profile = self.createReftestProfile(options, reftestlist) profileDir = profile.profile # name makes more sense # browser environment @@ -708,26 +659,209 @@ class RefTest(object): continue -def run(**kwargs): - # Mach gives us kwargs; this is a way to turn them back into an - # options object - parser = reftestcommandline.DesktopArgumentsParser() - reftest = RefTest() - parser.set_defaults(**kwargs) - options = parser.parse_args(kwargs["tests"]) - parser.validate(options, reftest) - return reftest.runTests(options.tests, options) +class ReftestOptions(OptionParser): + + def __init__(self): + OptionParser.__init__(self) + defaults = {} + self.add_option("--xre-path", + action="store", type="string", dest="xrePath", + # individual scripts will set a sane default + default=None, + help="absolute path to directory containing XRE (probably xulrunner)") + self.add_option("--symbols-path", + action="store", type="string", dest="symbolsPath", + default=None, + help="absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols") + self.add_option("--debugger", + action="store", dest="debugger", + help="use the given debugger to launch the application") + self.add_option("--debugger-args", + action="store", dest="debuggerArgs", + help="pass the given args to the debugger _before_ " + "the application on the command line") + self.add_option("--debugger-interactive", + action="store_true", dest="debuggerInteractive", + help="prevents the test harness from redirecting " + "stdout and stderr for interactive debuggers") + self.add_option("--appname", + action="store", type="string", dest="app", + help="absolute path to application, overriding default") + # Certain paths do not make sense when we're cross compiling Fennec. This + # logic is cribbed from the example in + # python/mozbuild/mozbuild/mach_commands.py. + defaults['app'] = build_obj.get_binary_path() if \ + build_obj and build_obj.substs['MOZ_BUILD_APP'] != 'mobile/android' else None + + self.add_option("--extra-profile-file", + action="append", dest="extraProfileFiles", + default=[], + help="copy specified files/dirs to testing profile") + self.add_option("--timeout", + action="store", dest="timeout", type="int", + default=5 * 60, # 5 minutes per bug 479518 + help="reftest will timeout in specified number of seconds. [default %default s].") + self.add_option("--leak-threshold", + action="store", type="int", dest="defaultLeakThreshold", + default=0, + help="fail if the number of bytes leaked in default " + "processes through refcounted objects (or bytes " + "in classes with MOZ_COUNT_CTOR and MOZ_COUNT_DTOR) " + "is greater than the given number") + self.add_option("--utility-path", + action="store", type="string", dest="utilityPath", + help="absolute path to directory containing utility " + "programs (xpcshell, ssltunnel, certutil)") + defaults["utilityPath"] = build_obj.bindir if \ + build_obj and build_obj.substs['MOZ_BUILD_APP'] != 'mobile/android' else None + + self.add_option("--total-chunks", + type="int", dest="totalChunks", + help="how many chunks to split the tests up into") + defaults["totalChunks"] = None + + self.add_option("--this-chunk", + type="int", dest="thisChunk", + help="which chunk to run between 1 and --total-chunks") + defaults["thisChunk"] = None + + self.add_option("--log-file", + action="store", type="string", dest="logFile", + default=None, + help="file to log output to in addition to stdout") + defaults["logFile"] = None + + self.add_option("--skip-slow-tests", + dest="skipSlowTests", action="store_true", + help="skip tests marked as slow when running") + defaults["skipSlowTests"] = False + + self.add_option("--ignore-window-size", + dest="ignoreWindowSize", action="store_true", + help="ignore the window size, which may cause spurious failures and passes") + defaults["ignoreWindowSize"] = False + + self.add_option("--install-extension", + action="append", dest="extensionsToInstall", + help="install the specified extension in the testing profile. " + "The extension file's name should be .xpi where is " + "the extension's id as indicated in its install.rdf. " + "An optional path can be specified too.") + defaults["extensionsToInstall"] = [] + + self.add_option("--run-tests-in-parallel", + action="store_true", dest="runTestsInParallel", + help="run tests in parallel if possible") + self.add_option("--no-run-tests-in-parallel", + action="store_false", dest="runTestsInParallel", + help="do not run tests in parallel") + defaults["runTestsInParallel"] = False + + self.add_option("--setenv", + action="append", type="string", + dest="environment", metavar="NAME=VALUE", + help="sets the given variable in the application's " + "environment") + defaults["environment"] = [] + + self.add_option("--filter", + action="store", type="string", dest="filter", + help="specifies a regular expression (as could be passed to the JS " + "RegExp constructor) to test against URLs in the reftest manifest; " + "only test items that have a matching test URL will be run.") + defaults["filter"] = None + + self.add_option("--shuffle", + action="store_true", dest="shuffle", + help="run reftests in random order") + defaults["shuffle"] = False + + self.add_option("--focus-filter-mode", + action="store", type="string", dest="focusFilterMode", + help="filters tests to run by whether they require focus. " + "Valid values are `all', `needs-focus', or `non-needs-focus'. " + "Defaults to `all'.") + defaults["focusFilterMode"] = "all" + + self.add_option("--e10s", + action="store_true", + dest="e10s", + help="enables content processes") + defaults["e10s"] = False + + self.add_option("--setpref", + action="append", type="string", + default=[], + dest="extraPrefs", metavar="PREF=VALUE", + help="defines an extra user preference") + + self.set_defaults(**defaults) + + def verifyCommonOptions(self, options, reftest): + if options.totalChunks is not None and options.thisChunk is None: + self.error("thisChunk must be specified when totalChunks is specified") + + if options.totalChunks: + if not 1 <= options.thisChunk <= options.totalChunks: + self.error("thisChunk must be between 1 and totalChunks") + + if options.logFile: + options.logFile = reftest.getFullPath(options.logFile) + + if options.xrePath is not None: + if not os.access(options.xrePath, os.F_OK): + self.error("--xre-path '%s' not found" % options.xrePath) + if not os.path.isdir(options.xrePath): + self.error("--xre-path '%s' is not a directory" % + options.xrePath) + options.xrePath = reftest.getFullPath(options.xrePath) + + if options.runTestsInParallel: + if options.logFile is not None: + self.error("cannot specify logfile with parallel tests") + if options.totalChunks is not None and options.thisChunk is None: + self.error("cannot specify thisChunk or totalChunks with parallel tests") + if options.focusFilterMode != "all": + self.error("cannot specify focusFilterMode with parallel tests") + if options.debugger is not None: + self.error("cannot specify a debugger with parallel tests") + + options.leakThresholds = { + "default": options.defaultLeakThreshold, + "tab": 5000, # See dependencies of bug 1051230. + } + + return options def main(): - parser = reftestcommandline.DesktopArgumentsParser() + parser = ReftestOptions() reftest = RefTest() - options = parser.parse_args() - parser.validate(options, reftest) + options, args = parser.parse_args() + if len(args) != 1: + print >>sys.stderr, "No reftest.list specified." + sys.exit(1) - sys.exit(reftest.runTests(options.tests, options)) + options = parser.verifyCommonOptions(options, reftest) + if options.app is None: + parser.error("could not find the application path, --appname must be specified") + options.app = reftest.getFullPath(options.app) + if not os.path.exists(options.app): + print """Error: Path %(app)s doesn't exist. +Are you executing $objdir/_tests/reftest/runreftest.py?""" \ + % {"app": options.app} + sys.exit(1) + + if options.xrePath is None: + options.xrePath = os.path.dirname(options.app) + + if options.symbolsPath and len(urlparse(options.symbolsPath).scheme) < 2: + options.symbolsPath = reftest.getFullPath(options.symbolsPath) + options.utilityPath = reftest.getFullPath(options.utilityPath) + + sys.exit(reftest.runTests(args[0], options)) if __name__ == "__main__": main() diff --git a/layout/tools/reftest/runreftestb2g.py b/layout/tools/reftest/runreftestb2g.py index c0a9257e93ef..085a246ac00c 100644 --- a/layout/tools/reftest/runreftestb2g.py +++ b/layout/tools/reftest/runreftestb2g.py @@ -10,18 +10,207 @@ import traceback # We need to know our current directory so that we can serve our test files from it. here = os.path.abspath(os.path.dirname(__file__)) -if here not in sys.path: - sys.path.insert(0, here) from automation import Automation from b2gautomation import B2GRemoteAutomation from b2g_desktop import run_desktop_reftests -from remotereftest import RemoteReftestResolver, ReftestServer from runreftest import RefTest -import reftestcommandline +from runreftest import ReftestOptions +from remotereftest import ReftestServer from mozdevice import DeviceManagerADB, DMError from marionette import Marionette +import moznetwork + +class B2GOptions(ReftestOptions): + + def __init__(self, **kwargs): + defaults = {} + ReftestOptions.__init__(self) + # This is only used for procName in run_remote_reftests. + defaults["app"] = Automation.DEFAULT_APP + + self.add_option("--browser-arg", action="store", + type = "string", dest = "browser_arg", + help = "Optional command-line arg to pass to the browser") + defaults["browser_arg"] = None + + self.add_option("--b2gpath", action="store", + type = "string", dest = "b2gPath", + help = "path to B2G repo or qemu dir") + defaults["b2gPath"] = None + + self.add_option("--marionette", action="store", + type = "string", dest = "marionette", + help = "host:port to use when connecting to Marionette") + defaults["marionette"] = None + + self.add_option("--emulator", action="store", + type="string", dest = "emulator", + help = "Architecture of emulator to use: x86 or arm") + defaults["emulator"] = None + self.add_option("--emulator-res", action="store", + type="string", dest = "emulator_res", + help = "Emulator resolution of the format 'x'") + defaults["emulator_res"] = None + + self.add_option("--no-window", action="store_true", + dest = "noWindow", + help = "Pass --no-window to the emulator") + defaults["noWindow"] = False + + self.add_option("--adbpath", action="store", + type = "string", dest = "adb_path", + help = "path to adb") + defaults["adb_path"] = "adb" + + self.add_option("--deviceIP", action="store", + type = "string", dest = "deviceIP", + help = "ip address of remote device to test") + defaults["deviceIP"] = None + + self.add_option("--devicePort", action="store", + type = "string", dest = "devicePort", + help = "port of remote device to test") + defaults["devicePort"] = 20701 + + self.add_option("--remote-logfile", action="store", + type = "string", dest = "remoteLogFile", + help = "Name of log file on the device relative to the device root. PLEASE ONLY USE A FILENAME.") + defaults["remoteLogFile"] = None + + self.add_option("--remote-webserver", action = "store", + type = "string", dest = "remoteWebServer", + help = "ip address where the remote web server is hosted at") + defaults["remoteWebServer"] = None + + self.add_option("--http-port", action = "store", + type = "string", dest = "httpPort", + help = "ip address where the remote web server is hosted at") + defaults["httpPort"] = None + + self.add_option("--ssl-port", action = "store", + type = "string", dest = "sslPort", + help = "ip address where the remote web server is hosted at") + defaults["sslPort"] = None + + self.add_option("--pidfile", action = "store", + type = "string", dest = "pidFile", + help = "name of the pidfile to generate") + defaults["pidFile"] = "" + self.add_option("--gecko-path", action="store", + type="string", dest="geckoPath", + help="the path to a gecko distribution that should " + "be installed on the emulator prior to test") + defaults["geckoPath"] = None + self.add_option("--logdir", action="store", + type="string", dest="logdir", + help="directory to store log files") + defaults["logdir"] = None + self.add_option('--busybox', action='store', + type='string', dest='busybox', + help="Path to busybox binary to install on device") + defaults['busybox'] = None + self.add_option("--httpd-path", action = "store", + type = "string", dest = "httpdPath", + help = "path to the httpd.js file") + defaults["httpdPath"] = None + self.add_option("--profile", action="store", + type="string", dest="profile", + help="for desktop testing, the path to the " + "gaia profile to use") + defaults["profile"] = None + self.add_option("--desktop", action="store_true", + dest="desktop", + help="Run the tests on a B2G desktop build") + defaults["desktop"] = False + self.add_option("--mulet", action="store_true", + dest="mulet", + help="Run the tests on a B2G desktop build") + defaults["mulet"] = False + self.add_option("--enable-oop", action="store_true", + dest="oop", + help="Run the tests out of process") + defaults["oop"] = False + defaults["remoteTestRoot"] = None + defaults["logFile"] = "reftest.log" + defaults["autorun"] = True + defaults["closeWhenDone"] = True + defaults["testPath"] = "" + defaults["runTestsInParallel"] = False + + self.set_defaults(**defaults) + + def verifyRemoteOptions(self, options, auto): + if options.runTestsInParallel: + self.error("Cannot run parallel tests here") + + if not options.remoteTestRoot: + options.remoteTestRoot = auto._devicemanager.deviceRoot + "/reftest" + + options.remoteProfile = options.remoteTestRoot + "/profile" + + productRoot = options.remoteTestRoot + "/" + auto._product + if options.utilityPath is None: + options.utilityPath = productRoot + "/bin" + + if options.remoteWebServer == None: + if os.name != "nt": + options.remoteWebServer = moznetwork.get_ip() + else: + print "ERROR: you must specify a --remote-webserver=\n" + return None + + options.webServer = options.remoteWebServer + + if not options.httpPort: + options.httpPort = auto.DEFAULT_HTTP_PORT + + if not options.sslPort: + options.sslPort = auto.DEFAULT_SSL_PORT + + if options.geckoPath and not options.emulator: + self.error("You must specify --emulator if you specify --gecko-path") + + if options.logdir and not options.emulator: + self.error("You must specify --emulator if you specify --logdir") + + #if not options.emulator and not options.deviceIP: + # print "ERROR: you must provide a device IP" + # return None + + if options.remoteLogFile == None: + options.remoteLogFile = "reftest.log" + + options.localLogName = options.remoteLogFile + options.remoteLogFile = options.remoteTestRoot + '/' + options.remoteLogFile + + # Ensure that the options.logfile (which the base class uses) is set to + # the remote setting when running remote. Also, if the user set the + # log file name there, use that instead of reusing the remotelogfile as above. + if (options.logFile): + # If the user specified a local logfile name use that + options.localLogName = options.logFile + options.logFile = options.remoteLogFile + + # Only reset the xrePath if it wasn't provided + if options.xrePath == None: + options.xrePath = options.utilityPath + options.xrePath = os.path.abspath(options.xrePath) + + if options.pidFile != "": + f = open(options.pidFile, 'w') + f.write("%s" % os.getpid()) + f.close() + + # httpd-path is specified by standard makefile targets and may be specified + # on the command line to select a particular version of httpd.js. If not + # specified, try to select the one from from the xre bundle, as required in bug 882932. + if not options.httpdPath: + options.httpdPath = os.path.join(options.xrePath, "components") + + return options + class ProfileConfigParser(ConfigParser.RawConfigParser): """Subclass of RawConfigParser that outputs .ini files in the exact @@ -54,7 +243,6 @@ class B2GRemoteReftest(RefTest): localProfile = None remoteApp = '' profile = None - resolver_cls = RemoteReftestResolver def __init__(self, automation, devicemanager, options, scriptDir): RefTest.__init__(self) @@ -230,9 +418,10 @@ class B2GRemoteReftest(RefTest): pass - def createReftestProfile(self, options, manifests): - profile = RefTest.createReftestProfile(self, options, manifests, - server=options.remoteWebServer) + def createReftestProfile(self, options, reftestlist): + profile = RefTest.createReftestProfile(self, options, reftestlist, + server=options.remoteWebServer, + special_powers=False) profileDir = profile.profile prefs = {} @@ -248,7 +437,7 @@ class B2GRemoteReftest(RefTest): prefs["network.dns.localDomains"] = "app://test-container.gaiamobile.org" prefs["reftest.browser.iframe.enabled"] = False prefs["reftest.remote"] = True - + prefs["reftest.uri"] = "%s" % reftestlist # Set a future policy version to avoid the telemetry prompt. prefs["toolkit.telemetry.prompted"] = 999 prefs["toolkit.telemetry.notifiedOptOut"] = 999 @@ -306,6 +495,9 @@ class B2GRemoteReftest(RefTest): print "Automation Error: Failed to copy extra files to device" raise + def getManifestPath(self, path): + return path + def environment(self, **kwargs): return self.automation.environment(**kwargs) @@ -324,7 +516,7 @@ class B2GRemoteReftest(RefTest): return status -def run_remote_reftests(parser, options): +def run_remote_reftests(parser, options, args): auto = B2GRemoteAutomation(None, "fennec", context_chrome=True) # create our Marionette instance @@ -367,7 +559,11 @@ def run_remote_reftests(parser, options): dm = DeviceManagerADB(**kwargs) auto.setDeviceManager(dm) - parser.validate_remote(options, auto) + options = parser.verifyRemoteOptions(options, auto) + + if (options == None): + print "ERROR: Invalid options specified, use --help for a list of valid options" + sys.exit(1) # TODO fix exception if not options.ignoreWindowSize: @@ -384,7 +580,7 @@ def run_remote_reftests(parser, options): auto.logFinish = "REFTEST TEST-START | Shutdown" reftest = B2GRemoteReftest(auto, dm, options, here) - parser.validate(options, reftest) + options = parser.verifyCommonOptions(options, reftest) logParent = os.path.dirname(options.remoteLogFile) dm.mkDir(logParent); @@ -394,6 +590,16 @@ def run_remote_reftests(parser, options): # Hack in a symbolic link for jsreftest os.system("ln -s %s %s" % (os.path.join('..', 'jsreftest'), os.path.join(here, 'jsreftest'))) + # Dynamically build the reftest URL if possible, beware that args[0] should exist 'inside' the webroot + manifest = args[0] + if os.path.exists(os.path.join(here, args[0])): + manifest = "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, args[0]) + elif os.path.exists(args[0]): + manifestPath = os.path.abspath(args[0]).split(here)[1].strip('/') + manifest = "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, manifestPath) + else: + print "ERROR: Could not find test manifest '%s'" % manifest + return 1 # Start the webserver retVal = 1 @@ -405,7 +611,11 @@ def run_remote_reftests(parser, options): if (dm.processExist(procName)): dm.killProcess(procName) - retVal = reftest.runTests(options.tests, options) + cmdlineArgs = ["-reftest", manifest] + if getattr(options, 'bootstrap', False): + cmdlineArgs = [] + + retVal = reftest.runTests(manifest, options, cmdlineArgs) except: print "Automation Error: Exception caught while running tests" traceback.print_exc() @@ -419,21 +629,13 @@ def run_remote_reftests(parser, options): reftest.stopWebServer(options) return retVal -def run_remote(**kwargs): - # Tests need to be served from a subdirectory of the server. Symlink - # topsrcdir here to get around this. - parser = reftestcommandline.B2GArgumentParser() - parser.set_defaults(**kwargs) - options = parser.parse_args(kwargs["tests"]) - return run_remote_reftests(parser, options) - -def main(): - parser = reftestcommandline.B2GArgumentParser() - options = parser.parse_args() +def main(args=sys.argv[1:]): + parser = B2GOptions() + options, args = parser.parse_args(args) if options.desktop or options.mulet: - return run_desktop_reftests(parser, options) - return run_remote_reftests(parser, options) + return run_desktop_reftests(parser, options, args) + return run_remote_reftests(parser, options, args) if __name__ == "__main__": diff --git a/testing/mach_commands.py b/testing/mach_commands.py index 1b443d94c3db..9134d9d20626 100644 --- a/testing/mach_commands.py +++ b/testing/mach_commands.py @@ -96,7 +96,7 @@ TEST_SUITES = { 'reftest': { 'aliases': ('RR', 'rr', 'Rr'), 'mach_command': 'reftest', - 'kwargs': {'tests': None}, + 'kwargs': {'test_file': None}, }, 'reftest-ipc': { 'aliases': ('Ripc',), @@ -139,10 +139,7 @@ TEST_FLAVORS = { 'mach_command': 'mochitest', 'kwargs': {'flavor': 'mochitest', 'test_paths': []}, }, - 'reftest': { - 'mach_command': 'reftest', - 'kwargs': {'tests': []} - }, + 'reftest': { }, 'steeplechase': { }, 'web-platform-tests': { 'mach_command': 'web-platform-tests', diff --git a/testing/mozharness/configs/android/android_panda_releng.py b/testing/mozharness/configs/android/android_panda_releng.py index 8b1e0e5a3cbd..99428c5b33de 100644 --- a/testing/mozharness/configs/android/android_panda_releng.py +++ b/testing/mozharness/configs/android/android_panda_releng.py @@ -97,9 +97,8 @@ config = { "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", "--symbols-path=%(symbols_path)s", - "--suite=crashtest", + "reftest/tests/testing/crashtest/crashtests.list" ], - "tests": ["reftest/tests/testing/crashtest/crashtests.list",], "run_filename": "remotereftest.py", "testsdir": "reftest" }, @@ -129,12 +128,11 @@ config = { "--ignore-window-size", "--bootstrap", "--extra-profile-file=jsreftest/tests/user.js", + "jsreftest/tests/jstests.list", "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", - "--symbols-path=%(symbols_path)s", - "--suite=jstestbrowser", + "--symbols-path=%(symbols_path)s" ], - "tests": ["jsreftest/tests/jstests.list",], "run_filename": "remotereftest.py", "testsdir": "reftest" }, @@ -168,9 +166,8 @@ config = { "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", "--symbols-path=%(symbols_path)s", - "--suite=reftest", + "reftest/tests/layout/reftests/reftest.list" ], - "tests": ["reftest/tests/layout/reftests/reftest.list"], "run_filename": "remotereftest.py", "testsdir": "reftest" }, diff --git a/testing/mozharness/configs/android/androidarm.py b/testing/mozharness/configs/android/androidarm.py index 3e3ff8fa5ecc..ad57e5d4a94c 100644 --- a/testing/mozharness/configs/android/androidarm.py +++ b/testing/mozharness/configs/android/androidarm.py @@ -140,9 +140,8 @@ config = { "%(modules_dir)s", "--symbols-path=%(symbols_path)s", "--total-chunks=16", - "--suite=reftest", + "tests/layout/reftests/reftest.list", ], - "tests": ["tests/layout/reftests/reftest.list"], }, "crashtest": { "run_filename": "remotereftest.py", @@ -162,9 +161,8 @@ config = { "%(modules_dir)s", "--symbols-path=%(symbols_path)s", "--total-chunks=2", - "--suite=crashtest", + "tests/testing/crashtest/crashtests.list", ], - "tests": ["tests/testing/crashtest/crashtests.list"], }, "jsreftest": { "run_filename": "remotereftest.py", @@ -183,11 +181,10 @@ config = { "--httpd-path", "%(modules_dir)s", "--symbols-path=%(symbols_path)s", + "../jsreftest/tests/jstests.list", "--total-chunks=6", "--extra-profile-file=jsreftest/tests/user.js", - "--suite=jstestbrowser", ], - "tests": ["../jsreftest/tests/jstests.list"], }, "xpcshell": { "run_filename": "remotexpcshelltests.py", @@ -318,67 +315,83 @@ config = { }, "reftest-1": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=1"], + "extra_args": ["--total-chunks=16", "--this-chunk=1", + "tests/layout/reftests/reftest.list"] }, "reftest-2": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=2"], + "extra_args": ["--total-chunks=16", "--this-chunk=2", + "tests/layout/reftests/reftest.list"] }, "reftest-3": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=3"], + "extra_args": ["--total-chunks=16", "--this-chunk=3", + "tests/layout/reftests/reftest.list"] }, "reftest-4": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=4"], + "extra_args": ["--total-chunks=16", "--this-chunk=4", + "tests/layout/reftests/reftest.list"] }, "reftest-5": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=5"], + "extra_args": ["--total-chunks=16", "--this-chunk=5", + "tests/layout/reftests/reftest.list"] }, "reftest-6": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=6"], + "extra_args": ["--total-chunks=16", "--this-chunk=6", + "tests/layout/reftests/reftest.list"] }, "reftest-7": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=7"], + "extra_args": ["--total-chunks=16", "--this-chunk=7", + "tests/layout/reftests/reftest.list"] }, "reftest-8": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=8"], + "extra_args": ["--total-chunks=16", "--this-chunk=8", + "tests/layout/reftests/reftest.list"] }, "reftest-9": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=9"], + "extra_args": ["--total-chunks=16", "--this-chunk=9", + "tests/layout/reftests/reftest.list"] }, "reftest-10": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=10"], + "extra_args": ["--total-chunks=16", "--this-chunk=10", + "tests/layout/reftests/reftest.list"] }, "reftest-11": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=11"], + "extra_args": ["--total-chunks=16", "--this-chunk=11", + "tests/layout/reftests/reftest.list"] }, "reftest-12": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=12"], + "extra_args": ["--total-chunks=16", "--this-chunk=12", + "tests/layout/reftests/reftest.list"] }, "reftest-13": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=13"], + "extra_args": ["--total-chunks=16", "--this-chunk=13", + "tests/layout/reftests/reftest.list"] }, "reftest-14": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=14"], + "extra_args": ["--total-chunks=16", "--this-chunk=14", + "tests/layout/reftests/reftest.list"] }, "reftest-15": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=15"], + "extra_args": ["--total-chunks=16", "--this-chunk=15", + "tests/layout/reftests/reftest.list"] }, "reftest-16": { "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=16"], + "extra_args": ["--total-chunks=16", "--this-chunk=16", + "tests/layout/reftests/reftest.list"] }, "crashtest-1": { "category": "crashtest", diff --git a/testing/mozharness/configs/android/androidarm_4_3.py b/testing/mozharness/configs/android/androidarm_4_3.py index ec5261829ea1..bb0879f1acf4 100644 --- a/testing/mozharness/configs/android/androidarm_4_3.py +++ b/testing/mozharness/configs/android/androidarm_4_3.py @@ -138,9 +138,8 @@ config = { "--httpd-path", "%(modules_dir)s", "--symbols-path=%(symbols_path)s", "--total-chunks=16", - "--suite=reftest", + "tests/layout/reftests/reftest.list", ], - "tests": ["tests/layout/reftests/reftest.list",], }, "crashtest": { "run_filename": "remotereftest.py", @@ -159,9 +158,8 @@ config = { "%(modules_dir)s", "--symbols-path=%(symbols_path)s", "--total-chunks=2", - "--suite=crashtest", + "tests/testing/crashtest/crashtests.list", ], - "tests": ["tests/testing/crashtest/crashtests.list",], }, "jsreftest": { "run_filename": "remotereftest.py", @@ -175,11 +173,10 @@ config = { "--utility-path=%(utility_path)s", "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s", "--httpd-path", "%(modules_dir)s", "--symbols-path=%(symbols_path)s", + "../jsreftest/tests/jstests.list", "--total-chunks=6", "--extra-profile-file=jsreftest/tests/user.js", - "--suite=jstestbrowser", ], - "tests": ["../jsreftest/tests/jstests.list",], }, "xpcshell": { "run_filename": "remotexpcshelltests.py", @@ -378,195 +375,243 @@ config = { }, "reftest-1": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=1"], + "extra_args": ["--total-chunks=48", "--this-chunk=1", + "tests/layout/reftests/reftest.list"] }, "reftest-2": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=2"], + "extra_args": ["--total-chunks=48", "--this-chunk=2", + "tests/layout/reftests/reftest.list"] }, "reftest-3": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=3"], + "extra_args": ["--total-chunks=48", "--this-chunk=3", + "tests/layout/reftests/reftest.list"] }, "reftest-4": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=4"], + "extra_args": ["--total-chunks=48", "--this-chunk=4", + "tests/layout/reftests/reftest.list"] }, "reftest-5": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=5"], + "extra_args": ["--total-chunks=48", "--this-chunk=5", + "tests/layout/reftests/reftest.list"] }, "reftest-6": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=6"], + "extra_args": ["--total-chunks=48", "--this-chunk=6", + "tests/layout/reftests/reftest.list"] }, "reftest-7": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=7"], + "extra_args": ["--total-chunks=48", "--this-chunk=7", + "tests/layout/reftests/reftest.list"] }, "reftest-8": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=8"], + "extra_args": ["--total-chunks=48", "--this-chunk=8", + "tests/layout/reftests/reftest.list"] }, "reftest-9": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=9"], + "extra_args": ["--total-chunks=48", "--this-chunk=9", + "tests/layout/reftests/reftest.list"] }, "reftest-10": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=10"], + "extra_args": ["--total-chunks=48", "--this-chunk=10", + "tests/layout/reftests/reftest.list"] }, "reftest-11": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=11"], + "extra_args": ["--total-chunks=48", "--this-chunk=11", + "tests/layout/reftests/reftest.list"] }, "reftest-12": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=12"], + "extra_args": ["--total-chunks=48", "--this-chunk=12", + "tests/layout/reftests/reftest.list"] }, "reftest-13": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=13"], + "extra_args": ["--total-chunks=48", "--this-chunk=13", + "tests/layout/reftests/reftest.list"] }, "reftest-14": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=14"], + "extra_args": ["--total-chunks=48", "--this-chunk=14", + "tests/layout/reftests/reftest.list"] }, "reftest-15": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=15"], + "extra_args": ["--total-chunks=48", "--this-chunk=15", + "tests/layout/reftests/reftest.list"] }, "reftest-16": { "category": "reftest", - "extra_args": ["--total-chunks=48", "--this-chunk=16"], + "extra_args": ["--total-chunks=48", "--this-chunk=16", + "tests/layout/reftests/reftest.list"] }, "reftest-17": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=17"], + "extra_args": ["--total-chunks=48", "--this-chunk=17", + "tests/layout/reftests/reftest.list"] }, "reftest-18": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=18"], + "extra_args": ["--total-chunks=48", "--this-chunk=18", + "tests/layout/reftests/reftest.list"] }, "reftest-19": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=19"], + "extra_args": ["--total-chunks=48", "--this-chunk=19", + "tests/layout/reftests/reftest.list"] }, "reftest-20": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=20"], + "extra_args": ["--total-chunks=48", "--this-chunk=20", + "tests/layout/reftests/reftest.list"] }, "reftest-21": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=21"], + "extra_args": ["--total-chunks=48", "--this-chunk=21", + "tests/layout/reftests/reftest.list"] }, "reftest-22": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=22"], + "extra_args": ["--total-chunks=48", "--this-chunk=22", + "tests/layout/reftests/reftest.list"] }, "reftest-23": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=23"], + "extra_args": ["--total-chunks=48", "--this-chunk=23", + "tests/layout/reftests/reftest.list"] }, "reftest-24": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=24"], + "extra_args": ["--total-chunks=48", "--this-chunk=24", + "tests/layout/reftests/reftest.list"] }, "reftest-25": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=25"], + "extra_args": ["--total-chunks=48", "--this-chunk=25", + "tests/layout/reftests/reftest.list"] }, "reftest-26": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=26"], + "extra_args": ["--total-chunks=48", "--this-chunk=26", + "tests/layout/reftests/reftest.list"] }, "reftest-27": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=27"], + "extra_args": ["--total-chunks=48", "--this-chunk=27", + "tests/layout/reftests/reftest.list"] }, "reftest-28": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=28"], + "extra_args": ["--total-chunks=48", "--this-chunk=28", + "tests/layout/reftests/reftest.list"] }, "reftest-29": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=29"], + "extra_args": ["--total-chunks=48", "--this-chunk=29", + "tests/layout/reftests/reftest.list"] }, "reftest-30": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=30"], + "extra_args": ["--total-chunks=48", "--this-chunk=30", + "tests/layout/reftests/reftest.list"] }, "reftest-31": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=31"], + "extra_args": ["--total-chunks=48", "--this-chunk=31", + "tests/layout/reftests/reftest.list"] }, "reftest-32": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=32"], + "extra_args": ["--total-chunks=48", "--this-chunk=32", + "tests/layout/reftests/reftest.list"] }, "reftest-33": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=33"], + "extra_args": ["--total-chunks=48", "--this-chunk=33", + "tests/layout/reftests/reftest.list"] }, "reftest-34": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=34"], + "extra_args": ["--total-chunks=48", "--this-chunk=34", + "tests/layout/reftests/reftest.list"] }, "reftest-35": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=35"], + "extra_args": ["--total-chunks=48", "--this-chunk=35", + "tests/layout/reftests/reftest.list"] }, "reftest-36": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=36"], + "extra_args": ["--total-chunks=48", "--this-chunk=36", + "tests/layout/reftests/reftest.list"] }, "reftest-37": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=37"], + "extra_args": ["--total-chunks=48", "--this-chunk=37", + "tests/layout/reftests/reftest.list"] }, "reftest-38": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=38"], + "extra_args": ["--total-chunks=48", "--this-chunk=38", + "tests/layout/reftests/reftest.list"] }, "reftest-39": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=39"], + "extra_args": ["--total-chunks=48", "--this-chunk=39", + "tests/layout/reftests/reftest.list"] }, "reftest-40": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=40"], + "extra_args": ["--total-chunks=48", "--this-chunk=40", + "tests/layout/reftests/reftest.list"] }, "reftest-41": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=41"], + "extra_args": ["--total-chunks=48", "--this-chunk=41", + "tests/layout/reftests/reftest.list"] }, "reftest-42": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=42"], + "extra_args": ["--total-chunks=48", "--this-chunk=42", + "tests/layout/reftests/reftest.list"] }, "reftest-43": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=43"], + "extra_args": ["--total-chunks=48", "--this-chunk=43", + "tests/layout/reftests/reftest.list"] }, "reftest-44": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=44"], + "extra_args": ["--total-chunks=48", "--this-chunk=44", + "tests/layout/reftests/reftest.list"] }, "reftest-45": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=45"], + "extra_args": ["--total-chunks=48", "--this-chunk=45", + "tests/layout/reftests/reftest.list"] }, "reftest-46": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=46"], + "extra_args": ["--total-chunks=48", "--this-chunk=46", + "tests/layout/reftests/reftest.list"] }, "reftest-47": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=47"], + "extra_args": ["--total-chunks=48", "--this-chunk=47", + "tests/layout/reftests/reftest.list"] }, "reftest-48": { "category": "reftest", - "extra args": ["--total-chunks=48", "--this-chunk=48"], + "extra_args": ["--total-chunks=48", "--this-chunk=48", + "tests/layout/reftests/reftest.list"] }, "crashtest-1": { "category": "crashtest", diff --git a/testing/mozharness/configs/android/androidx86.py b/testing/mozharness/configs/android/androidx86.py index e69fd484d9f5..8fffd93f094b 100644 --- a/testing/mozharness/configs/android/androidx86.py +++ b/testing/mozharness/configs/android/androidx86.py @@ -135,11 +135,8 @@ config = { "test_suite_definitions": { "jsreftest": { "category": "reftest", - "tests": ["../jsreftest/tests/jstests.list"], - "extra_args": [ - "--suite=jstestbrowser", - "--extra-profile-file=jsreftest/tests/user.js" - ] + "extra_args": ["../jsreftest/tests/jstests.list", + "--extra-profile-file=jsreftest/tests/user.js"] }, "mochitest-1": { "category": "mochitest", @@ -155,33 +152,22 @@ config = { }, "reftest-1": { "category": "reftest", - "extra_args": [ - "--suite=reftest", - "--total-chunks=3", - "--this-chunk=1", - ], - "tests": ["tests/layout/reftests/reftest.list"], + "extra_args": ["--total-chunks=3", "--this-chunk=1", + "tests/layout/reftests/reftest.list"] }, "reftest-2": { - "extra_args": [ - "--suite=reftest", - "--total-chunks=3", - "--this-chunk=2", - ], - "tests": ["tests/layout/reftests/reftest.list"], + "category": "reftest", + "extra_args": ["--total-chunks=3", "--this-chunk=2", + "tests/layout/reftests/reftest.list"] }, "reftest-3": { - "extra_args": [ - "--suite=reftest", - "--total-chunks=3", - "--this-chunk=3", - ], - "tests": ["tests/layout/reftests/reftest.list"], + "category": "reftest", + "extra_args": ["--total-chunks=3", "--this-chunk=3", + "tests/layout/reftests/reftest.list"] }, "crashtest": { "category": "reftest", - "extra_args": ["--suite=crashtest"], - "tests": ["tests/testing/crashtest/crashtests.list"] + "extra_args": ["tests/testing/crashtest/crashtests.list"] }, "xpcshell": { "category": "xpcshell", diff --git a/testing/mozharness/configs/b2g/emulator_automation_config.py b/testing/mozharness/configs/b2g/emulator_automation_config.py index 03a39952c029..6a2451649b27 100644 --- a/testing/mozharness/configs/b2g/emulator_automation_config.py +++ b/testing/mozharness/configs/b2g/emulator_automation_config.py @@ -74,9 +74,8 @@ config = { "--busybox=%(busybox)s", "--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s", - "--suite=crashtest", + "tests/testing/crashtest/crashtests.list" ], - "tests": ["tests/testing/crashtest/crashtests.list",], "run_filename": "runreftestb2g.py", "testsdir": "reftest" }, @@ -95,8 +94,8 @@ config = { "--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s", "--extra-profile-file=jsreftest/tests/user.js", + "jsreftest/tests/jstests.list" ], - "tests": ["jsreftest/tests/jstests.list",], "run_filename": "remotereftest.py", "testsdir": "reftest" }, @@ -162,8 +161,8 @@ config = { "--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s", "--enable-oop", + "tests/layout/reftests/reftest.list" ], - "tests": ["tests/layout/reftests/reftest.list",], "run_filename": "runreftestsb2g.py", "testsdir": "reftest" }, diff --git a/testing/mozharness/configs/unittests/linux_unittest.py b/testing/mozharness/configs/unittests/linux_unittest.py index f3ffba7c9486..65a9ba371346 100644 --- a/testing/mozharness/configs/unittests/linux_unittest.py +++ b/testing/mozharness/configs/unittests/linux_unittest.py @@ -2,14 +2,14 @@ import os import platform # OS Specifics -ABS_WORK_DIR = os.path.join(os.getcwd(), "build") +ABS_WORK_DIR = os.path.join(os.getcwd(), 'build') BINARY_PATH = os.path.join(ABS_WORK_DIR, "firefox", "firefox-bin") INSTALLER_PATH = os.path.join(ABS_WORK_DIR, "installer.tar.bz2") XPCSHELL_NAME = "xpcshell" -EXE_SUFFIX = "" +EXE_SUFFIX = '' DISABLE_SCREEN_SAVER = True ADJUST_MOUSE_AND_SCREEN = False -if platform.architecture()[0] == "64bit": +if platform.architecture()[0] == '64bit': TOOLTOOL_MANIFEST_PATH = "config/tooltool-manifests/linux64/releng.manifest" MINIDUMP_STACKWALK_PATH = "linux64-minidump_stackwalk" else: @@ -20,9 +20,9 @@ else: config = { "buildbot_json_path": "buildprops.json", "exes": { - "python": "/tools/buildbot/bin/python", - "virtualenv": ["/tools/buildbot/bin/python", "/tools/misc-python/virtualenv.py"], - "tooltool.py": "/tools/tooltool.py", + 'python': '/tools/buildbot/bin/python', + 'virtualenv': ['/tools/buildbot/bin/python', '/tools/misc-python/virtualenv.py'], + 'tooltool.py': "/tools/tooltool.py", }, "find_links": [ "http://pypi.pvt.build.mozilla.org/pub", @@ -199,63 +199,35 @@ config = { }, # local reftest suites "all_reftest_suites": { - "reftest": { - "options": ["--suite=reftest"], - "tests": ["tests/reftest/tests/layout/reftests/reftest.list"] - }, - "crashtest": { - "options": ["--suite=crashtest"], - "tests": ["tests/reftest/tests/testing/crashtest/crashtests.list"] - }, - "jsreftest": { - "options":["--extra-profile-file=tests/jsreftest/tests/user.js", - "--suite=jstestbrowser"], - "tests": ["tests/jsreftest/tests/jstests.list"] - }, - "reftest-ipc": { - "env": { - "MOZ_OMTC_ENABLED": "1", - "MOZ_DISABLE_CONTEXT_SHARING_GLX": "1" - }, - "options": ["--suite=reftest", - "--setpref=browser.tabs.remote=true", - "--setpref=browser.tabs.remote.autostart=true", - "--setpref=layers.offmainthreadcomposition.testing.enabled=true", - "--setpref=layers.async-pan-zoom.enabled=true"], - "tests": ["tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list"] - }, - "reftest-no-accel": { - "options": ["--suite=reftest", - "--setpref=layers.acceleration.force-enabled=disabled"], - "tests": ["tests/reftest/tests/layout/reftests/reftest.list"]}, - "crashtest-ipc": { - "env": { - "MOZ_OMTC_ENABLED": "1", - "MOZ_DISABLE_CONTEXT_SHARING_GLX": "1" - }, - "options": ["--suite=crashtest", - "--setpref=browser.tabs.remote=true", - "--setpref=browser.tabs.remote.autostart=true", - "--setpref=layers.offmainthreadcomposition.testing.enabled=true", - "--setpref=layers.async-pan-zoom.enabled=true"], - "tests": ["tests/reftest/tests/testing/crashtest/crashtests.list"] - }, + "reftest": ["tests/reftest/tests/layout/reftests/reftest.list"], + "crashtest": ["tests/reftest/tests/testing/crashtest/crashtests.list"], + "jsreftest": ["--extra-profile-file=tests/jsreftest/tests/user.js", "tests/jsreftest/tests/jstests.list"], + "reftest-ipc": {'env': {'MOZ_OMTC_ENABLED': '1', + 'MOZ_DISABLE_CONTEXT_SHARING_GLX': '1'}, + 'options': ['--setpref=browser.tabs.remote=true', + '--setpref=browser.tabs.remote.autostart=true', + '--setpref=layers.offmainthreadcomposition.testing.enabled=true', + '--setpref=layers.async-pan-zoom.enabled=true', + 'tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list']}, + "reftest-no-accel": ['--setpref=layers.acceleration.force-enabled=disabled', + 'tests/reftest/tests/layout/reftests/reftest.list'], + "crashtest-ipc": {'env': {'MOZ_OMTC_ENABLED': '1', + 'MOZ_DISABLE_CONTEXT_SHARING_GLX': '1'}, + 'options': ['--setpref=browser.tabs.remote=true', + '--setpref=browser.tabs.remote.autostart=true', + '--setpref=layers.offmainthreadcomposition.testing.enabled=true', + '--setpref=layers.async-pan-zoom.enabled=true', + 'tests/reftest/tests/testing/crashtest/crashtests.list']}, }, "all_xpcshell_suites": { - "xpcshell": { - "options": ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, - "--manifest=tests/xpcshell/tests/all-test-dirs.list"], - "tests": [] - }, - "xpcshell-addons": { - "options": ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, - "--tag=addons", - "--manifest=tests/xpcshell/tests/all-test-dirs.list"], - "tests": [] - }, + "xpcshell": ["--manifest=tests/xpcshell/tests/all-test-dirs.list", + "%(abs_app_dir)s/" + XPCSHELL_NAME], + "xpcshell-addons": ["--manifest=tests/xpcshell/tests/all-test-dirs.list", + "--tag=addons", + "%(abs_app_dir)s/" + XPCSHELL_NAME] }, "all_cppunittest_suites": { - "cppunittest": ["tests/cppunittest"] + "cppunittest": ['tests/cppunittest'] }, "all_gtest_suites": { "gtest": [] diff --git a/testing/mozharness/configs/unittests/mac_unittest.py b/testing/mozharness/configs/unittests/mac_unittest.py index b98bcdae465e..000eec5f8a49 100644 --- a/testing/mozharness/configs/unittests/mac_unittest.py +++ b/testing/mozharness/configs/unittests/mac_unittest.py @@ -166,45 +166,24 @@ config = { }, # local reftest suites "all_reftest_suites": { - "reftest": { - 'options': ["--suite=reftest"], - 'tests': ["tests/reftest/tests/layout/reftests/reftest.list"] - }, - "crashtest": { - 'options': ["--suite=crashtest"], - 'tests': ["tests/reftest/tests/testing/crashtest/crashtests.list"] - }, - "jsreftest": { - 'options':["--extra-profile-file=tests/jsreftest/tests/user.js"], - 'tests': ["tests/jsreftest/tests/jstests.list"] - }, - "reftest-ipc": { - 'options': ['--suite=reftest', - '--setpref=browser.tabs.remote=true', + "reftest": ["tests/reftest/tests/layout/reftests/reftest.list"], + "crashtest": ["tests/reftest/tests/testing/crashtest/crashtests.list"], + "jsreftest": ["--extra-profile-file=tests/jsreftest/tests/user.js", "tests/jsreftest/tests/jstests.list"], + "reftest-ipc": ['--setpref=browser.tabs.remote=true', '--setpref=browser.tabs.remote.autostart=true', - '--setpref=layers.async-pan-zoom.enabled=true'], - 'tests': ['tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list'] - }, - "crashtest-ipc": { - 'options': ['--suite=crashtest', - '--setpref=browser.tabs.remote=true', - '--setpref=browser.tabs.remote.autostart=true', - '--setpref=layers.async-pan-zoom.enabled=true'], - 'tests': ['tests/reftest/tests/testing/crashtest/crashtests.list'] - }, + '--setpref=layers.async-pan-zoom.enabled=true', + 'tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list'], + "crashtest-ipc": ['--setpref=browser.tabs.remote=true', + '--setpref=browser.tabs.remote.autostart=true', + '--setpref=layers.async-pan-zoom.enabled=true', + 'tests/reftest/tests/testing/crashtest/crashtests.list'], }, "all_xpcshell_suites": { - "xpcshell": { - 'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, - "--manifest=tests/xpcshell/tests/all-test-dirs.list"], - 'tests': [] - }, - "xpcshell-addons": { - 'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, - "--tag=addons", - "--manifest=tests/xpcshell/tests/all-test-dirs.list"], - 'tests': [] - }, + "xpcshell": ["--manifest=tests/xpcshell/tests/all-test-dirs.list", + "%(abs_app_dir)s/" + XPCSHELL_NAME], + "xpcshell-addons": ["--manifest=tests/xpcshell/tests/all-test-dirs.list", + "--tag=addons", + "%(abs_app_dir)s/" + XPCSHELL_NAME] }, "all_cppunittest_suites": { "cppunittest": ['tests/cppunittest'] diff --git a/testing/mozharness/configs/unittests/win_unittest.py b/testing/mozharness/configs/unittests/win_unittest.py index 2908a18ffa19..5ad41e844180 100644 --- a/testing/mozharness/configs/unittests/win_unittest.py +++ b/testing/mozharness/configs/unittests/win_unittest.py @@ -176,56 +176,28 @@ config = { }, # local reftest suites "all_reftest_suites": { - "reftest": { - 'options': ["--suite=reftest"], - 'tests': ["tests/reftest/tests/layout/reftests/reftest.list"] - }, - "crashtest": { - 'options': ["--suite=crashtest"], - 'tests': ["tests/reftest/tests/testing/crashtest/crashtests.list"] - }, - "jsreftest": { - 'options':["--extra-profile-file=tests/jsreftest/tests/user.js"], - 'tests': ["tests/jsreftest/tests/jstests.list"] - }, - "reftest-ipc": { - 'options': ['--suite=reftest', - '--setpref=browser.tabs.remote=true', + "reftest": ["tests/reftest/tests/layout/reftests/reftest.list"], + "crashtest": ["tests/reftest/tests/testing/crashtest/crashtests.list"], + "jsreftest": ["--extra-profile-file=tests/jsreftest/tests/user.js", "tests/jsreftest/tests/jstests.list"], + "reftest-ipc": ['--setpref=browser.tabs.remote=true', '--setpref=browser.tabs.remote.autostart=true', - '--setpref=layers.async-pan-zoom.enabled=true'], - 'tests': ['tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list'] - }, - "reftest-no-accel": { - "options": ["--suite=reftest", - "--setpref=gfx.direct2d.disabled=true", - "--setpref=layers.acceleration.disabled=true"], - "tests": ["tests/reftest/tests/layout/reftests/reftest.list"] - }, - "reftest-omtc": { - "options": ["--suite=reftest", - "--setpref=layers.offmainthreadcomposition.enabled=true"], - "tests": ["tests/reftest/tests/layout/reftests/reftest.list"] - }, - "crashtest-ipc": { - "options": ["--suite=crashtest", - '--setpref=browser.tabs.remote=true', - '--setpref=browser.tabs.remote.autostart=true', - '--setpref=layers.async-pan-zoom.enabled=true'], - "tests": ['tests/reftest/tests/testing/crashtest/crashtests.list'], - }, + '--setpref=layers.async-pan-zoom.enabled=true', + 'tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list'], + "reftest-no-accel": ["--setpref=gfx.direct2d.disabled=true", "--setpref=layers.acceleration.disabled=true", + "tests/reftest/tests/layout/reftests/reftest.list"], + "reftest-omtc": ["--setpref=layers.offmainthreadcomposition.enabled=true", + "tests/reftest/tests/layout/reftests/reftest.list"], + "crashtest-ipc": ['--setpref=browser.tabs.remote=true', + '--setpref=browser.tabs.remote.autostart=true', + '--setpref=layers.async-pan-zoom.enabled=true', + 'tests/reftest/tests/testing/crashtest/crashtests.list'], }, "all_xpcshell_suites": { - "xpcshell": { - 'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, - "--manifest=tests/xpcshell/tests/all-test-dirs.list"], - 'tests': [] - }, - "xpcshell-addons": { - 'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME, - "--tag=addons", - "--manifest=tests/xpcshell/tests/all-test-dirs.list"], - 'tests': [] - }, + "xpcshell": ["--manifest=tests/xpcshell/tests/all-test-dirs.list", + "%(abs_app_dir)s/" + XPCSHELL_NAME], + "xpcshell-addons": ["--manifest=tests/xpcshell/tests/all-test-dirs.list", + "--tag=addons", + "%(abs_app_dir)s/" + XPCSHELL_NAME] }, "all_cppunittest_suites": { "cppunittest": ['tests/cppunittest'] diff --git a/testing/mozharness/scripts/android_emulator_unittest.py b/testing/mozharness/scripts/android_emulator_unittest.py index 739e3d6f4514..e46a59da8c77 100644 --- a/testing/mozharness/scripts/android_emulator_unittest.py +++ b/testing/mozharness/scripts/android_emulator_unittest.py @@ -483,15 +483,6 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin continue cmd.append(arg) - tests = None - if "tests" in self.test_suite_definitions[self.test_suite]: - tests = self.test_suite_definitions[self.test_suite]["tests"] - elif "tests" in self.config["suite_definitions"][suite_category]: - tests = self.config["suite_definitions"][suite_category]["tests"] - - if tests: - cmd.extend(tests) - return cmd def _tooltool_fetch(self, url): diff --git a/testing/mozharness/scripts/androidx86_emulator_unittest.py b/testing/mozharness/scripts/androidx86_emulator_unittest.py index c84ebb520966..1d43de694435 100644 --- a/testing/mozharness/scripts/androidx86_emulator_unittest.py +++ b/testing/mozharness/scripts/androidx86_emulator_unittest.py @@ -452,11 +452,6 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin continue cmd.append(arg) - if "tests" in self.suite_definitions[suite_name]: - cmd.extend(self.suite_definitions[suite_name]["tests"]) - elif "tests" in self.tree_config["suite_definitions"][suite_category]: - cmd.extend(self.tree_config["suite_definitions"][suite_category]["tests"]) - return cmd def preflight_run_tests(self): diff --git a/testing/mozharness/scripts/b2g_desktop_unittest.py b/testing/mozharness/scripts/b2g_desktop_unittest.py index f6040a1ab837..24a44db03f1c 100755 --- a/testing/mozharness/scripts/b2g_desktop_unittest.py +++ b/testing/mozharness/scripts/b2g_desktop_unittest.py @@ -154,7 +154,7 @@ class B2GDesktopTest(BlobUploadMixin, TestingMixin, MercurialScript): } if suite not in self.config["suite_definitions"]: - self.fatal("'%s' not defined in the config!" % suite) + self.fatal("'%s' not defined in the config!" % suite), options = self.config["suite_definitions"][suite]["options"] if options: @@ -162,11 +162,6 @@ class B2GDesktopTest(BlobUploadMixin, TestingMixin, MercurialScript): option = option % str_format_values if not option.endswith('None'): cmd.append(option) - - tests = self.config["suite_definitions"][suite].get("tests") - if tests: - cmd.extend(tests) - return cmd def download_and_extract(self): diff --git a/testing/mozharness/scripts/b2g_emulator_unittest.py b/testing/mozharness/scripts/b2g_emulator_unittest.py index 9b78ddb53d47..781551970210 100755 --- a/testing/mozharness/scripts/b2g_emulator_unittest.py +++ b/testing/mozharness/scripts/b2g_emulator_unittest.py @@ -281,11 +281,6 @@ class B2GEmulatorTest(TestingMixin, VCSMixin, BaseScript, BlobUploadMixin): option = option % str_format_values if not option.endswith('None'): cmd.append(option) - - tests = self.config["suite_definitions"][suite].get("tests", []) - if tests: - cmd.extend(tests) - return cmd def _query_adb(self): @@ -341,9 +336,8 @@ class B2GEmulatorTest(TestingMixin, VCSMixin, BaseScript, BlobUploadMixin): self.fatal("Don't know how to run --test-suite '%s'!" % suite) cmd = self._query_abs_base_cmd(suite) - cmd = self.append_harness_extra_args(cmd) - cwd = dirs['abs_%s_dir' % suite] + cmd = self.append_harness_extra_args(cmd) # TODO we probably have to move some of the code in # scripts/desktop_unittest.py and scripts/marionette.py to diff --git a/testing/mozharness/scripts/desktop_unittest.py b/testing/mozharness/scripts/desktop_unittest.py index 3c74b3c8ecfb..f9b41c05050a 100755 --- a/testing/mozharness/scripts/desktop_unittest.py +++ b/testing/mozharness/scripts/desktop_unittest.py @@ -588,8 +588,8 @@ class DesktopUnittest(TestingMixin, MercurialScript, BlobUploadMixin, MozbaseMix options_list = [] env = {} if isinstance(suites[suite], dict): - options_list = suites[suite]['options'] + suites[suite].get("tests", []) - env = copy.deepcopy(suites[suite].get('env', {})) + options_list = suites[suite]['options'] + env = copy.deepcopy(suites[suite]['env']) else: options_list = suites[suite] diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk index 98c7b76e8a04..1e99d2056919 100644 --- a/testing/testsuite-targets.mk +++ b/testing/testsuite-targets.mk @@ -174,7 +174,7 @@ REMOTE_REFTEST = rm -f ./$@.log && $(PYTHON) _tests/reftest/remotereftest.py \ --dm_trans=$(DM_TRANS) --ignore-window-size \ --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \ --httpd-path=_tests/modules \ - $(SYMBOLS_PATH) $(EXTRA_TEST_ARGS) $(1) | tee ./$@.log + $(SYMBOLS_PATH) $(EXTRA_TEST_ARGS) '$(1)' | tee ./$@.log RUN_REFTEST_B2G = rm -f ./$@.log && $(PYTHON) _tests/reftest/runreftestb2g.py \ --remote-webserver=10.0.2.2 --b2gpath=${B2G_PATH} --adbpath=${ADB_PATH} \ @@ -209,7 +209,7 @@ reftest-remote: echo 'please prepare your host with the environment variable TEST_DEVICE'; \ else \ ln -s $(abspath $(topsrcdir)) _tests/reftest/tests; \ - $(call REMOTE_REFTEST,'tests/$(TEST_PATH)'); \ + $(call REMOTE_REFTEST,tests/$(TEST_PATH)); \ $(CHECK_TEST_ERROR); \ fi diff --git a/testing/xpcshell/Makefile.in b/testing/xpcshell/Makefile.in index 5a9d0b567650..ff1fa16729e4 100644 --- a/testing/xpcshell/Makefile.in +++ b/testing/xpcshell/Makefile.in @@ -10,7 +10,6 @@ TEST_HARNESS_FILES := \ runxpcshelltests.py \ remotexpcshelltests.py \ runtestsb2g.py \ - xpcshellcommandline.py \ head.js \ node-spdy \ moz-spdy \ diff --git a/testing/xpcshell/mach_commands.py b/testing/xpcshell/mach_commands.py index c2168c40209f..7683598147da 100644 --- a/testing/xpcshell/mach_commands.py +++ b/testing/xpcshell/mach_commands.py @@ -25,7 +25,8 @@ from mach.decorators import ( Command, ) -from xpcshellcommandline import parser_desktop, parser_remote, parser_b2g +_parser = argparse.ArgumentParser() +structured.commandline.add_logging_group(_parser) ADB_NOT_FOUND = ''' The %s command requires the adb binary to be on your path. @@ -39,7 +40,6 @@ BUSYBOX_URLS = { 'x86': 'http://www.busybox.net/downloads/binaries/latest/busybox-i686' } -here = os.path.abspath(os.path.dirname(__file__)) if sys.version_info[0] < 3: unicode_type = unicode @@ -55,9 +55,20 @@ class InvalidTestPathError(Exception): class XPCShellRunner(MozbuildObject): """Run xpcshell tests.""" def run_suite(self, **kwargs): - return self._run_xpcshell_harness(**kwargs) + from manifestparser import TestManifest + manifest = TestManifest(manifests=[os.path.join(self.topobjdir, + '_tests', 'xpcshell', 'xpcshell.ini')]) - def run_test(self, **kwargs): + return self._run_xpcshell_harness(manifest=manifest, **kwargs) + + def run_test(self, test_paths, interactive=False, + keep_going=False, sequential=False, shuffle=False, + debugger=None, debuggerArgs=None, debuggerInteractive=None, + jsDebugger=False, jsDebuggerPort=None, + rerun_failures=False, test_objects=None, verbose=False, + log=None, test_tags=None, dump_tests=None, + # ignore parameters from other platforms' options + **kwargs): """Runs an individual xpcshell test.""" from mozbuild.testing import TestResolver from manifestparser import TestManifest @@ -71,15 +82,65 @@ class XPCShellRunner(MozbuildObject): if os.path.isdir(src_build_path): sys.path.append(src_build_path) - self.run_suite(**kwargs) + if test_paths == 'all': + self.run_suite(interactive=interactive, + keep_going=keep_going, shuffle=shuffle, sequential=sequential, + debugger=debugger, debuggerArgs=debuggerArgs, + debuggerInteractive=debuggerInteractive, + jsDebugger=jsDebugger, jsDebuggerPort=jsDebuggerPort, + rerun_failures=rerun_failures, + verbose=verbose, log=log, test_tags=test_tags, dump_tests=dump_tests) + return + elif test_paths: + test_paths = [self._wrap_path_argument(p).relpath() for p in test_paths] + if test_objects: + tests = test_objects + else: + resolver = self._spawn(TestResolver) + tests = list(resolver.resolve_tests(paths=test_paths, + flavor='xpcshell')) + + if not tests: + raise InvalidTestPathError('We could not find an xpcshell test ' + 'for the passed test path. Please select a path that is ' + 'a test file or is a directory containing xpcshell tests.') + + # Dynamically write out a manifest holding all the discovered tests. + manifest = TestManifest() + manifest.tests.extend(tests) + + args = { + 'interactive': interactive, + 'keep_going': keep_going, + 'shuffle': shuffle, + 'sequential': sequential, + 'debugger': debugger, + 'debuggerArgs': debuggerArgs, + 'debuggerInteractive': debuggerInteractive, + 'jsDebugger': jsDebugger, + 'jsDebuggerPort': jsDebuggerPort, + 'rerun_failures': rerun_failures, + 'manifest': manifest, + 'verbose': verbose, + 'log': log, + 'test_tags': test_tags, + 'dump_tests': dump_tests, + } + + return self._run_xpcshell_harness(**args) + + def _run_xpcshell_harness(self, manifest, + test_path=None, shuffle=False, interactive=False, + keep_going=False, sequential=False, + debugger=None, debuggerArgs=None, debuggerInteractive=None, + jsDebugger=False, jsDebuggerPort=None, + rerun_failures=False, verbose=False, log=None, test_tags=None, + dump_tests=None): - def _run_xpcshell_harness(self, **kwargs): # Obtain a reference to the xpcshell test runner. import runxpcshelltests - log = kwargs.pop("log") - xpcshell = runxpcshelltests.XPCShellTests(log=log) self.log_manager.enable_unstructured() @@ -87,41 +148,60 @@ class XPCShellRunner(MozbuildObject): modules_dir = os.path.join(self.topobjdir, '_tests', 'modules') # We want output from the test to be written immediately if we are only # running a single test. - single_test = (kwargs["testPaths"] is not None or + single_test = (test_path is not None or (manifest and len(manifest.test_paths())==1)) - sequential = kwargs["sequential"] or single_test + sequential = sequential or single_test - if kwargs["xpcshell"] is None: - kwargs["xpcshell"] = self.get_binary_path('xpcshell') + args = { + 'manifest': manifest, + 'xpcshell': self.get_binary_path('xpcshell'), + 'mozInfo': os.path.join(self.topobjdir, 'mozinfo.json'), + 'symbolsPath': os.path.join(self.distdir, 'crashreporter-symbols'), + 'interactive': interactive, + 'keepGoing': keep_going, + 'logfiles': False, + 'sequential': sequential, + 'shuffle': shuffle, + 'testsRootDir': tests_dir, + 'testingModulesDir': modules_dir, + 'profileName': 'firefox', + 'verbose': verbose or single_test, + 'xunitFilename': os.path.join(self.statedir, 'xpchsell.xunit.xml'), + 'xunitName': 'xpcshell', + 'pluginsPath': os.path.join(self.distdir, 'plugins'), + 'debugger': debugger, + 'debuggerArgs': debuggerArgs, + 'debuggerInteractive': debuggerInteractive, + 'jsDebugger': jsDebugger, + 'jsDebuggerPort': jsDebuggerPort, + 'test_tags': test_tags, + 'dump_tests': dump_tests, + 'utility_path': self.bindir, + } - if kwargs["mozInfo"] is None: - kwargs["mozInfo"] = os.path.join(self.topobjdir, 'mozinfo.json') + if test_path is not None: + args['testPath'] = test_path - if kwargs["symbolsPath"] is None: - kwargs["symbolsPath"] = os.path.join(self.distdir, 'crashreporter-symbols') - - if kwargs["logfiles"] is None: - kwargs["logfiles"] = False - - if kwargs["profileName"] is None: - kwargs["profileName"] = "firefox" - - if kwargs["pluginsPath"] is None: - kwargs['pluginsPath'] = os.path.join(self.distdir, 'plugins') - - if kwargs["utility_path"] is None: - kwargs['utility_path'] = self.bindir - - if kwargs["manifest"] is None: - kwargs["manifest"] = os.path.join(tests_dir, "xpcshell.ini") - - if kwargs["failure_manifest"] is None: - kwargs["failure_manifest"] = os.path.join(self.statedir, 'xpcshell.failures.ini') + # A failure manifest is written by default. If --rerun-failures is + # specified and a prior failure manifest is found, the prior manifest + # will be run. A new failure manifest is always written over any + # prior failure manifest. + failure_manifest_path = os.path.join(self.statedir, 'xpcshell.failures.ini') + rerun_manifest_path = os.path.join(self.statedir, 'xpcshell.rerun.ini') + if os.path.exists(failure_manifest_path) and rerun_failures: + shutil.move(failure_manifest_path, rerun_manifest_path) + args['manifest'] = rerun_manifest_path + elif os.path.exists(failure_manifest_path): + os.remove(failure_manifest_path) + elif rerun_failures: + print("No failures were found to re-run.") + return 0 + args['failureManifest'] = failure_manifest_path # Python through 2.7.2 has issues with unicode in some of the # arguments. Work around that. filtered_args = {} - for k, v in kwargs.iteritems(): + for k, v in args.items(): if isinstance(v, unicode_type): v = v.encode('utf-8') @@ -157,7 +237,12 @@ class AndroidXPCShellRunner(MozbuildObject): return dm """Run Android xpcshell tests.""" - def run_test(self, **kwargs): + def run_test(self, + test_paths, keep_going, + devicemanager, ip, port, remote_test_root, no_setup, local_apk, + test_objects=None, log=None, + # ignore parameters from other platforms' options + **kwargs): # TODO Bug 794506 remove once mach integrates with virtualenv. build_path = os.path.join(self.topobjdir, 'build') if build_path not in sys.path: @@ -165,53 +250,60 @@ class AndroidXPCShellRunner(MozbuildObject): import remotexpcshelltests - dm = self.get_devicemanager(kwargs["dm_trans"], kwargs["deviceIP"], kwargs["devicePort"], - kwargs["remoteTestRoot"]) + dm = self.get_devicemanager(devicemanager, ip, port, remote_test_root) - log = kwargs.pop("log") - self.log_manager.enable_unstructured() - - if kwargs["xpcshell"] is None: - kwargs["xpcshell"] = "xpcshell" - - if not kwargs["objdir"]: - kwargs["objdir"] = self.topobjdir - - if not kwargs["localLib"]: - kwargs["localLib"] = os.path.join(self.topobjdir, 'dist/fennec') - - if not kwargs["localBin"]: - kwargs["localBin"] = os.path.join(self.topobjdir, 'dist/bin') - - if not kwargs["testingModulesDir"]: - kwargs["testingModulesDir"] = os.path.join(self.topobjdir, '_tests/modules') - - if not kwargs["mozInfo"]: - kwargs["mozInfo"] = os.path.join(self.topobjdir, 'mozinfo.json') - - if not kwargs["manifest"]: - kwargs["manifest"] = os.path.join(self.topobjdir, '_tests/xpcshell/xpcshell.ini') - - if not kwargs["symbolsPath"]: - kwargs["symbolsPath"] = os.path.join(self.distdir, 'crashreporter-symbols') - - if not kwargs["localAPK"]: - for file_name in os.listdir(os.path.join(kwargs["objdir"], "dist")): - if file_name.endswith(".apk") and file_name.startswith("fennec"): - kwargs["localAPK"] = os.path.join(kwargs["objdir"], "dist", file_name) - print ("using APK: %s" % kwargs["localAPK"]) + options = remotexpcshelltests.RemoteXPCShellOptions() + options.shuffle = False + options.sequential = True + options.interactive = False + options.debugger = None + options.debuggerArgs = None + options.setup = not no_setup + options.keepGoing = keep_going + options.objdir = self.topobjdir + options.localLib = os.path.join(self.topobjdir, 'dist/fennec') + options.localBin = os.path.join(self.topobjdir, 'dist/bin') + options.testingModulesDir = os.path.join(self.topobjdir, '_tests/modules') + options.mozInfo = os.path.join(self.topobjdir, 'mozinfo.json') + options.manifest = os.path.join(self.topobjdir, '_tests/xpcshell/xpcshell.ini') + options.symbolsPath = os.path.join(self.distdir, 'crashreporter-symbols') + if local_apk: + options.localAPK = local_apk + else: + for file in os.listdir(os.path.join(options.objdir, "dist")): + if file.endswith(".apk") and file.startswith("fennec"): + options.localAPK = os.path.join(options.objdir, "dist") + options.localAPK = os.path.join(options.localAPK, file) + print ("using APK: " + options.localAPK) break else: raise Exception("You must specify an APK") - options = argparse.Namespace(**kwargs) - xpcshell = remotexpcshelltests.XPCShellRemote(dm, options, log) + if test_paths == 'all': + testdirs = [] + options.testPath = None + options.verbose = False + elif test_objects: + if len(test_objects) > 1: + print('Warning: only the first test will be used.') + testdirs = test_objects[0]['dir_relpath'] + options.testPath = test_objects[0]['path'] + options.verbose = True + else: + if len(test_paths) > 1: + print('Warning: only the first test path argument will be used.') + testdirs = test_paths[0] + options.testPath = test_paths[0] + options.verbose = True - result = xpcshell.runTests(testClass=remotexpcshelltests.RemoteXPCShellTestThread, - mobileArgs=xpcshell.mobileArgs, - **vars(options)) + xpcshell = remotexpcshelltests.XPCShellRemote(dm, options, testdirs, log) + + result = xpcshell.runTests(xpcshell='xpcshell', + testClass=remotexpcshelltests.RemoteXPCShellTestThread, + testdirs=testdirs, + mobileArgs=xpcshell.mobileArgs, + **options.__dict__) - self.log_manager.disable_unstructured() return int(not result) @@ -258,66 +350,57 @@ class B2GXPCShellRunner(MozbuildObject): f.write(data.read()) return busybox_path - def run_test(self, **kwargs): + def run_test(self, test_paths, b2g_home=None, busybox=None, device_name=None, + test_objects=None, log=None, + # ignore parameters from other platforms' options + **kwargs): try: import which which.which('adb') except which.WhichError: # TODO Find adb automatically if it isn't on the path - print(ADB_NOT_FOUND % ('mochitest-remote', kwargs["b2g_home"])) + print(ADB_NOT_FOUND % ('mochitest-remote', b2g_home)) sys.exit(1) + test_path = None + if test_objects: + if len(test_objects) > 1: + print('Warning: Only the first test will be used.') + + test_path = self._wrap_path_argument(test_objects[0]['path']) + elif test_paths: + if len(test_paths) > 1: + print('Warning: Only the first test path will be used.') + + test_path = self._wrap_path_argument(test_paths[0]).relpath() + import runtestsb2g + parser = runtestsb2g.B2GOptions() + options, args = parser.parse_args([]) - log = kwargs.pop("log") - self.log_manager.enable_unstructured() + options.b2g_path = b2g_home + options.busybox = busybox or os.environ.get('BUSYBOX') + options.localLib = self.bin_dir + options.localBin = self.bin_dir + options.logdir = self.xpcshell_dir + options.manifest = os.path.join(self.xpcshell_dir, 'xpcshell.ini') + options.mozInfo = os.path.join(self.topobjdir, 'mozinfo.json') + options.objdir = self.topobjdir + options.symbolsPath = os.path.join(self.distdir, 'crashreporter-symbols'), + options.testingModulesDir = os.path.join(self.tests_dir, 'modules') + options.testsRootDir = self.xpcshell_dir + options.testPath = test_path + options.use_device_libs = True - if kwargs["xpcshell"] is None: - kwargs["xpcshell"] = "xpcshell" - if kwargs["b2g_path"] is None: - kwargs["b2g_path"] = kwargs["b2g_home"] - if kwargs["busybox"] is None: - kwargs["busybox"] = os.environ.get('BUSYBOX') - if kwargs["busybox"] is None: - kwargs["busybox"] = self._download_busybox(kwargs["b2g_home"], kwargs["emulator"]) + options.emulator = 'arm' + if device_name.startswith('emulator'): + if 'x86' in device_name: + options.emulator = 'x86' - if kwargs["localLib"] is None: - kwargs["localLib"] = self.bin_dir - if kwargs["localBin"] is None: - kwargs["localBin"] = self.bin_dir - if kwargs["logdir"] is None: - kwargs["logdir"] = self.xpcshell_dir - if kwargs["manifest"] is None: - kwargs["manifest"] = os.path.join(self.xpcshell_dir, 'xpcshell.ini') - if kwargs["mozInfo"] is None: - kwargs["mozInfo"] = os.path.join(self.topobjdir, 'mozinfo.json') - if kwargs["objdir"] is None: - kwargs["objdir"] = self.topobjdir - if kwargs["symbolsPath"] is None: - kwargs["symbolsPath"] = os.path.join(self.distdir, 'crashreporter-symbols') - if kwargs["testingModulesDir"] is None: - kwargs["testingModulesDir"] = os.path.join(self.tests_dir, 'modules') - if kwargs["use_device_libs"] is None: - kwargs["use_device_libs"] = True + if not options.busybox: + options.busybox = self._download_busybox(b2g_home, options.emulator) - if kwargs["device_name"].startswith('emulator') and 'x86' in kwargs["device_name"]: - kwargs["emulator"] = 'x86' - - parser = parser_b2g() - options = argparse.Namespace(**kwargs) - rv = runtestsb2g.run_remote_xpcshell(parser, options, log) - - self.log_manager.disable_unstructured() - return rv - -def get_parser(): - build_obj = MozbuildObject.from_environment(cwd=here) - if conditions.is_android(build_obj): - return parser_remote() - elif conditions.is_b2g(build_obj): - return parser_b2g() - else: - return parser_desktop() + return runtestsb2g.run_remote_xpcshell(parser, options, args, log) @CommandProvider class MachCommands(MachCommandBase): @@ -328,10 +411,61 @@ class MachCommands(MachCommandBase): setattr(self, attr, getattr(context, attr, None)) @Command('xpcshell-test', category='testing', - description='Run XPCOM Shell tests (API direct unit testing)', - conditions=[lambda *args: True], - parser=get_parser) - + description='Run XPCOM Shell tests (API direct unit testing)', + conditions=[lambda *args: True], + parser=_parser) + @CommandArgument('test_paths', default='all', nargs='*', metavar='TEST', + help='Test to run. Can be specified as a single JS file, a directory, ' + 'or omitted. If omitted, the entire test suite is executed.') + @CommandArgument('--verbose', '-v', action='store_true', + help='Provide full output from each test process.') + @CommandArgument("--debugger", default=None, metavar='DEBUGGER', + help = "Run xpcshell under the given debugger.") + @CommandArgument("--debugger-args", default=None, metavar='ARGS', type=str, + dest = "debuggerArgs", + help = "pass the given args to the debugger _before_ " + "the application on the command line") + @CommandArgument("--debugger-interactive", action = "store_true", + dest = "debuggerInteractive", + help = "prevents the test harness from redirecting " + "stdout and stderr for interactive debuggers") + @CommandArgument("--jsdebugger", dest="jsDebugger", action="store_true", + help="Waits for a devtools JS debugger to connect before " + "starting the test.") + @CommandArgument("--jsdebugger-port", dest="jsDebuggerPort", + type=int, default=6000, + help="The port to listen on for a debugger connection if " + "--jsdebugger is specified (default=6000).") + @CommandArgument('--interactive', '-i', action='store_true', + help='Open an xpcshell prompt before running tests.') + @CommandArgument('--keep-going', '-k', action='store_true', + help='Continue running tests after a SIGINT is received.') + @CommandArgument('--sequential', action='store_true', + help='Run the tests sequentially.') + @CommandArgument('--shuffle', '-s', action='store_true', + help='Randomize the execution order of tests.') + @CommandArgument('--rerun-failures', action='store_true', + help='Reruns failures from last time.') + @CommandArgument('--tag', action='append', dest='test_tags', + help='Filter out tests that don\'t have the given tag. Can be used ' + 'multiple times in which case the test must contain at least one ' + 'of the given tags.') + @CommandArgument('--dump-tests', default=None, type=str, dest='dump_tests', + help='Specify path to a filename to dump all the tests that will be run') + @CommandArgument('--devicemanager', default='adb', type=str, + help='(Android) Type of devicemanager to use for communication: adb or sut') + @CommandArgument('--ip', type=str, default=None, + help='(Android) IP address of device') + @CommandArgument('--port', type=int, default=20701, + help='(Android) Port of device') + @CommandArgument('--remote_test_root', type=str, default=None, + help='(Android) Remote test root such as /mnt/sdcard or /data/local') + @CommandArgument('--no-setup', action='store_true', + help='(Android) Do not copy files to device') + @CommandArgument('--local-apk', type=str, default=None, + help='(Android) Use specified Fennec APK') + @CommandArgument('--busybox', type=str, default=None, + help='(B2G) Path to busybox binary (speeds up installation of tests).') def run_xpcshell_test(self, **params): from mozbuild.controller.building import BuildDriver diff --git a/testing/xpcshell/remotexpcshelltests.py b/testing/xpcshell/remotexpcshelltests.py index f4009ba7abfa..b4775726f4f2 100644 --- a/testing/xpcshell/remotexpcshelltests.py +++ b/testing/xpcshell/remotexpcshelltests.py @@ -16,8 +16,6 @@ import mozdevice import mozfile import mozinfo -from xpcshellcommandline import parser_remote - here = os.path.dirname(os.path.abspath(__file__)) def remoteJoin(path1, path2): @@ -107,7 +105,7 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread): return (list(sanitize_list(test['head'], 'head')), list(sanitize_list(test['tail'], 'tail'))) - def buildXpcsCmd(self): + def buildXpcsCmd(self, testdir): # change base class' paths to remote paths and use base class to build command self.xpcshell = remoteJoin(self.remoteBinDir, "xpcw") self.headJSPath = remoteJoin(self.remoteScriptsDir, 'head.js') @@ -115,7 +113,7 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread): self.httpdManifest = remoteJoin(self.remoteComponentsDir, 'httpd.manifest') self.testingModulesDir = self.remoteModulesDir self.testharnessdir = self.remoteScriptsDir - xpcshell.XPCShellTestThread.buildXpcsCmd(self) + xpcshell.XPCShellTestThread.buildXpcsCmd(self, testdir) # remove "-g -a " and add "--greomni " del(self.xpcsCmd[1:5]) if self.options.localAPK: @@ -218,7 +216,7 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread): # via devicemanager. class XPCShellRemote(xpcshell.XPCShellTests, object): - def __init__(self, devmgr, options, log): + def __init__(self, devmgr, options, args, log): xpcshell.XPCShellTests.__init__(self, log) # Add Android version (SDK level) to mozinfo so that manifest entries @@ -519,8 +517,8 @@ class XPCShellRemote(xpcshell.XPCShellTests, object): self.device.removeDir(self.remoteMinidumpDir) self.device.mkDir(self.remoteMinidumpDir) - def buildTestList(self, test_tags=None, test_paths=None): - xpcshell.XPCShellTests.buildTestList(self, test_tags=test_tags, test_paths=test_paths) + def buildTestList(self, test_tags=None): + xpcshell.XPCShellTests.buildTestList(self, test_tags=test_tags) uniqueTestPaths = set([]) for test in self.alltests: uniqueTestPaths.add(test['here']) @@ -529,37 +527,90 @@ class XPCShellRemote(xpcshell.XPCShellTests, object): remoteScriptDir = remoteJoin(self.remoteScriptsDir, abbrevTestDir) self.pathMapping.append(PathMapping(testdir, remoteScriptDir)) -def verifyRemoteOptions(parser, options): - if options.localLib is None: - if options.localAPK and options.objdir: - for path in ['dist/fennec', 'fennec/lib']: - options.localLib = os.path.join(options.objdir, path) - if os.path.isdir(options.localLib): - break - else: - parser.error("Couldn't find local library dir, specify --local-lib-dir") - elif options.objdir: - options.localLib = os.path.join(options.objdir, 'dist/bin') - elif os.path.isfile(os.path.join(here, '..', 'bin', 'xpcshell')): - # assume tests are being run from a tests.zip - options.localLib = os.path.abspath(os.path.join(here, '..', 'bin')) - else: - parser.error("Couldn't find local library dir, specify --local-lib-dir") +class RemoteXPCShellOptions(xpcshell.XPCShellOptions): - if options.localBin is None: - if options.objdir: - for path in ['dist/bin', 'bin']: - options.localBin = os.path.join(options.objdir, path) - if os.path.isdir(options.localBin): - break + def __init__(self): + xpcshell.XPCShellOptions.__init__(self) + defaults = {} + + self.add_option("--deviceIP", action="store", + type = "string", dest = "deviceIP", + help = "ip address of remote device to test") + defaults["deviceIP"] = None + + self.add_option("--devicePort", action="store", + type = "string", dest = "devicePort", + help = "port of remote device to test") + defaults["devicePort"] = 20701 + + self.add_option("--dm_trans", action="store", + type = "string", dest = "dm_trans", + help = "the transport to use to communicate with device: [adb|sut]; default=sut") + defaults["dm_trans"] = "sut" + + self.add_option("--objdir", action="store", + type = "string", dest = "objdir", + help = "local objdir, containing xpcshell binaries") + defaults["objdir"] = None + + self.add_option("--apk", action="store", + type = "string", dest = "localAPK", + help = "local path to Fennec APK") + defaults["localAPK"] = None + + self.add_option("--noSetup", action="store_false", + dest = "setup", + help = "do not copy any files to device (to be used only if device is already setup)") + defaults["setup"] = True + + self.add_option("--local-lib-dir", action="store", + type = "string", dest = "localLib", + help = "local path to library directory") + defaults["localLib"] = None + + self.add_option("--local-bin-dir", action="store", + type = "string", dest = "localBin", + help = "local path to bin directory") + defaults["localBin"] = None + + self.add_option("--remoteTestRoot", action = "store", + type = "string", dest = "remoteTestRoot", + help = "remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)") + defaults["remoteTestRoot"] = None + + self.set_defaults(**defaults) + + def verifyRemoteOptions(self, options): + if options.localLib is None: + if options.localAPK and options.objdir: + for path in ['dist/fennec', 'fennec/lib']: + options.localLib = os.path.join(options.objdir, path) + if os.path.isdir(options.localLib): + break + else: + self.error("Couldn't find local library dir, specify --local-lib-dir") + elif options.objdir: + options.localLib = os.path.join(options.objdir, 'dist/bin') + elif os.path.isfile(os.path.join(here, '..', 'bin', 'xpcshell')): + # assume tests are being run from a tests.zip + options.localLib = os.path.abspath(os.path.join(here, '..', 'bin')) else: - parser.error("Couldn't find local binary dir, specify --local-bin-dir") - elif os.path.isfile(os.path.join(here, '..', 'bin', 'xpcshell')): - # assume tests are being run from a tests.zip - options.localBin = os.path.abspath(os.path.join(here, '..', 'bin')) - else: - parser.error("Couldn't find local binary dir, specify --local-bin-dir") - return options + self.error("Couldn't find local library dir, specify --local-lib-dir") + + if options.localBin is None: + if options.objdir: + for path in ['dist/bin', 'bin']: + options.localBin = os.path.join(options.objdir, path) + if os.path.isdir(options.localBin): + break + else: + self.error("Couldn't find local binary dir, specify --local-bin-dir") + elif os.path.isfile(os.path.join(here, '..', 'bin', 'xpcshell')): + # assume tests are being run from a tests.zip + options.localBin = os.path.abspath(os.path.join(here, '..', 'bin')) + else: + self.error("Couldn't find local binary dir, specify --local-bin-dir") + return options class PathMapping: @@ -568,13 +619,14 @@ class PathMapping: self.remote = remoteDir def main(): + if sys.version_info < (2,7): print >>sys.stderr, "Error: You must use python version 2.7 or newer but less than 3.0" sys.exit(1) - parser = parser_remote() + parser = RemoteXPCShellOptions() commandline.add_logging_group(parser) - options = parser.parse_args() + options, args = parser.parse_args() if not options.localAPK: for file in os.listdir(os.path.join(options.objdir, "dist")): if (file.endswith(".apk") and file.startswith("fennec")): @@ -586,11 +638,16 @@ def main(): print >>sys.stderr, "Error: please specify an APK" sys.exit(1) - options = verifyRemoteOptions(parser, options) + options = parser.verifyRemoteOptions(options) log = commandline.setup_logging("Remote XPCShell", options, {"tbpl": sys.stdout}) + if len(args) < 1 and options.manifest is None: + print >>sys.stderr, """Usage: %s + or: %s --manifest=test.manifest """ % (sys.argv[0], sys.argv[0]) + sys.exit(1) + if options.dm_trans == "adb": if options.deviceIP: dm = mozdevice.DroidADB(options.deviceIP, options.devicePort, packageName=None, deviceRoot=options.remoteTestRoot) @@ -606,17 +663,16 @@ def main(): print >>sys.stderr, "Error: You must specify a test filename in interactive mode!" sys.exit(1) - if options.xpcshell is None: - options.xpcshell = "xpcshell" - - xpcsh = XPCShellRemote(dm, options, log) + xpcsh = XPCShellRemote(dm, options, args, log) # we don't run concurrent tests on mobile options.sequential = True - if not xpcsh.runTests(testClass=RemoteXPCShellTestThread, + if not xpcsh.runTests(xpcshell='xpcshell', + testClass=RemoteXPCShellTestThread, + testdirs=args[0:], mobileArgs=xpcsh.mobileArgs, - **vars(options)): + **options.__dict__): sys.exit(1) diff --git a/testing/xpcshell/runtestsb2g.py b/testing/xpcshell/runtestsb2g.py index 5ea7697118f8..21b1325f13a2 100644 --- a/testing/xpcshell/runtestsb2g.py +++ b/testing/xpcshell/runtestsb2g.py @@ -9,15 +9,14 @@ import os sys.path.insert(0, os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))) import traceback -import remotexpcshelltests -from remotexpcshelltests import RemoteXPCShellTestThread, XPCShellRemote +from remotexpcshelltests import RemoteXPCShellTestThread, XPCShellRemote, RemoteXPCShellOptions from mozdevice import devicemanagerADB, DMError from mozlog import commandline DEVICE_TEST_ROOT = '/data/local/tests' + from marionette import Marionette -from xpcshellcommandline import parser_b2g class B2GXPCShellTestThread(RemoteXPCShellTestThread): # Overridden @@ -76,19 +75,87 @@ class B2GXPCShellRemote(XPCShellRemote): self.env['LD_LIBRARY_PATH'] = '/system/b2g' self.options.use_device_libs = True -def verifyRemoteOptions(parser, options): - if options.b2g_path is None: - parser.error("Need to specify a --b2gpath") +class B2GOptions(RemoteXPCShellOptions): - if options.geckoPath and not options.emulator: - parser.error("You must specify --emulator if you specify --gecko-path") + def __init__(self): + RemoteXPCShellOptions.__init__(self) + defaults = {} - if options.logdir and not options.emulator: - parser.error("You must specify --emulator if you specify --logdir") - return remotexpcshelltests.verifyRemoteOptions(parser, options) + self.add_option('--b2gpath', action='store', + type='string', dest='b2g_path', + help="Path to B2G repo or qemu dir") + defaults['b2g_path'] = None -def run_remote_xpcshell(parser, options, log): - options = verifyRemoteOptions(parser, options) + self.add_option('--emupath', action='store', + type='string', dest='emu_path', + help="Path to emulator folder (if different " + "from b2gpath") + + self.add_option('--no-clean', action='store_false', + dest='clean', + help="Do not clean TESTROOT. Saves [lots of] time") + defaults['clean'] = True + + defaults['emu_path'] = None + + self.add_option('--emulator', action='store', + type='string', dest='emulator', + help="Architecture of emulator to use: x86 or arm") + defaults['emulator'] = None + + self.add_option('--no-window', action='store_true', + dest='no_window', + help="Pass --no-window to the emulator") + defaults['no_window'] = False + + self.add_option('--adbpath', action='store', + type='string', dest='adb_path', + help="Path to adb") + defaults['adb_path'] = 'adb' + + self.add_option('--address', action='store', + type='string', dest='address', + help="host:port of running Gecko instance to connect to") + defaults['address'] = None + + self.add_option('--use-device-libs', action='store_true', + dest='use_device_libs', + help="Don't push .so's") + defaults['use_device_libs'] = False + self.add_option("--gecko-path", action="store", + type="string", dest="geckoPath", + help="the path to a gecko distribution that should " + "be installed on the emulator prior to test") + defaults["geckoPath"] = None + self.add_option("--logdir", action="store", + type="string", dest="logdir", + help="directory to store log files") + defaults["logdir"] = None + self.add_option('--busybox', action='store', + type='string', dest='busybox', + help="Path to busybox binary to install on device") + defaults['busybox'] = None + + defaults["remoteTestRoot"] = DEVICE_TEST_ROOT + defaults['dm_trans'] = 'adb' + defaults['debugger'] = None + defaults['debuggerArgs'] = None + + self.set_defaults(**defaults) + + def verifyRemoteOptions(self, options): + if options.b2g_path is None: + self.error("Need to specify a --b2gpath") + + if options.geckoPath and not options.emulator: + self.error("You must specify --emulator if you specify --gecko-path") + + if options.logdir and not options.emulator: + self.error("You must specify --emulator if you specify --logdir") + return RemoteXPCShellOptions.verifyRemoteOptions(self, options) + +def run_remote_xpcshell(parser, options, args, log): + options = parser.verifyRemoteOptions(options) # Create the Marionette instance kwargs = {} @@ -128,18 +195,16 @@ def run_remote_xpcshell(parser, options, log): if not options.remoteTestRoot: options.remoteTestRoot = dm.deviceRoot - xpcsh = B2GXPCShellRemote(dm, options, log) + xpcsh = B2GXPCShellRemote(dm, options, args, log) # we don't run concurrent tests on mobile options.sequential = True - if options.xpcshell is None: - options.xpcshell = "xpcshell" - try: - if not xpcsh.runTests(testClass=B2GXPCShellTestThread, - mobileArgs=xpcsh.mobileArgs, - **vars(options)): + if not xpcsh.runTests(xpcshell='xpcshell', testdirs=args[0:], + testClass=B2GXPCShellTestThread, + mobileArgs=xpcsh.mobileArgs, + **options.__dict__): sys.exit(1) except: print "Automation Error: Exception caught while running tests" @@ -147,13 +212,13 @@ def run_remote_xpcshell(parser, options, log): sys.exit(1) def main(): - parser = parser_b2g() + parser = B2GOptions() commandline.add_logging_group(parser) - options = parser.parse_args() + options, args = parser.parse_args() log = commandline.setup_logging("Remote XPCShell", options, {"tbpl": sys.stdout}) - run_remote_xpcshell(parser, options, log) + run_remote_xpcshell(parser, options, args, log) # You usually run this like : # python runtestsb2g.py --emulator arm --b2gpath $B2GPATH --manifest $MANIFEST [--xre-path $MOZ_HOST_BIN diff --git a/testing/xpcshell/runxpcshelltests.py b/testing/xpcshell/runxpcshelltests.py index b4e38e67780b..3c527ad64a08 100755 --- a/testing/xpcshell/runxpcshelltests.py +++ b/testing/xpcshell/runxpcshelltests.py @@ -23,7 +23,7 @@ import traceback from collections import deque, namedtuple from distutils import dir_util from multiprocessing import cpu_count -from argparse import ArgumentParser +from optparse import OptionParser from subprocess import Popen, PIPE, STDOUT from tempfile import mkdtemp, gettempdir from threading import ( @@ -40,9 +40,6 @@ except Exception: HAVE_PSUTIL = False from automation import Automation -from xpcshellcommandline import parser_desktop - -SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__))) HARNESS_TIMEOUT = 5 * 60 @@ -65,7 +62,7 @@ if os.path.isdir(mozbase): sys.path.append(os.path.join(mozbase, package)) from manifestparser import TestManifest -from manifestparser.filters import chunk_by_slice, tags, pathprefix +from manifestparser.filters import chunk_by_slice, tags from mozlog import commandline import mozcrash import mozinfo @@ -103,7 +100,7 @@ def markGotSIGINT(signum, stackFrame): class XPCShellTestThread(Thread): def __init__(self, test_object, event, cleanup_dir_list, retry=True, - app_dir_key=None, interactive=False, + tests_root_dir=None, app_dir_key=None, interactive=False, verbose=False, pStdout=None, pStderr=None, keep_going=False, log=None, **kwargs): Thread.__init__(self) @@ -133,6 +130,7 @@ class XPCShellTestThread(Thread): self.failureManifest = kwargs.get('failureManifest') self.stack_fixer_function = kwargs.get('stack_fixer_function') + self.tests_root_dir = tests_root_dir self.app_dir_key = app_dir_key self.interactive = interactive self.verbose = verbose @@ -415,7 +413,7 @@ class XPCShellTestThread(Thread): return (list(sanitize_list(headlist, 'head')), list(sanitize_list(taillist, 'tail'))) - def buildXpcsCmd(self): + def buildXpcsCmd(self, testdir): """ Load the root head.js file as the first file in our test path, before other head, test, and tail files. On a remote system, we overload this to add additional command line arguments, so this gets overloaded. @@ -617,7 +615,7 @@ class XPCShellTestThread(Thread): self.tempDir = self.setupTempDir() self.mozInfoJSPath = self.setupMozinfoJS() - self.buildXpcsCmd() + self.buildXpcsCmd(test_dir) head_files, tail_files = self.getHeadAndTailFiles(self.test_object) cmdH = self.buildCmdHead(head_files, tail_files, self.xpcsCmd) @@ -770,50 +768,30 @@ class XPCShellTests(object): self.harness_timeout = HARNESS_TIMEOUT self.nodeProc = {} - def getTestManifest(self, manifest): - if isinstance(manifest, TestManifest): - return manifest - elif manifest is not None: - manifest = os.path.normpath(os.path.abspath(manifest)) - if os.path.isfile(manifest): - return TestManifest([manifest], strict=True) - else: - ini_path = os.path.join(manifest, "xpcshell.ini") - else: - ini_path = os.path.join(SCRIPT_DIR, "tests", "xpcshell.ini") - - if os.path.exists(ini_path): - return TestManifest([ini_path], strict=True) - else: - print >> sys.stderr, ("Failed to find manifest at %s; use --manifest " - "to set path explicitly." % (ini_path,)) - sys.exit(1) - - def buildTestList(self, test_tags=None, test_paths=None): + def buildTestList(self, test_tags=None): """ read the xpcshell.ini manifest and set self.alltests to be an array of test objects. if we are chunking tests, it will be done here as well """ - - if test_paths is None: - test_paths = [] - - if len(test_paths) == 1 and test_paths[0].endswith(".js"): - self.singleFile = os.path.basename(test_paths[0]) + if isinstance(self.manifest, TestManifest): + mp = self.manifest else: - self.singleFile = None + mp = TestManifest(strict=True) + if self.manifest is None: + for testdir in self.testdirs: + if testdir: + mp.read(os.path.join(testdir, 'xpcshell.ini')) + else: + mp.read(self.manifest) - mp = self.getTestManifest(self.manifest) + self.buildTestPath() filters = [] if test_tags: filters.append(tags(test_tags)) - if test_paths: - filters.append(pathprefix(test_paths)) - if self.singleFile is None and self.totalChunks > 1: filters.append(chunk_by_slice(self.thisChunk, self.totalChunks)) try: @@ -940,6 +918,31 @@ class XPCShellTests(object): pStderr = STDOUT return pStdout, pStderr + def buildTestPath(self): + """ + If we specifiy a testpath, set the self.testPath variable to be the given directory or file. + + |testPath| will be the optional path only, or |None|. + |singleFile| will be the optional test only, or |None|. + """ + self.singleFile = None + if self.testPath is not None: + if self.testPath.endswith('.js'): + # Split into path and file. + if self.testPath.find('/') == -1: + # Test only. + self.singleFile = self.testPath + else: + # Both path and test. + # Reuse |testPath| temporarily. + self.testPath = self.testPath.rsplit('/', 1) + self.singleFile = self.testPath[1] + self.testPath = self.testPath[0] + else: + # Path only. + # Simply remove optional ending separator. + self.testPath = self.testPath.rstrip("/") + def verifyDirPath(self, dirname): """ Simple wrapper to get the absolute path for a given directory name. @@ -1041,17 +1044,16 @@ class XPCShellTests(object): return '%s:%s' % (os.path.basename(test_object['ancestor-manifest']), path) return path - def runTests(self, xpcshell=None, xrePath=None, appPath=None, symbolsPath=None, - manifest=None, testPaths=None, mobileArgs=None, + def runTests(self, xpcshell, xrePath=None, appPath=None, symbolsPath=None, + manifest=None, testdirs=None, testPath=None, mobileArgs=None, interactive=False, verbose=False, keepGoing=False, logfiles=True, thisChunk=1, totalChunks=1, debugger=None, debuggerArgs=None, debuggerInteractive=False, profileName=None, mozInfo=None, sequential=False, shuffle=False, - testingModulesDir=None, pluginsPath=None, + testsRootDir=None, testingModulesDir=None, pluginsPath=None, testClass=XPCShellTestThread, failureManifest=None, log=None, stream=None, jsDebugger=False, jsDebuggerPort=0, - test_tags=None, dump_tests=None, utility_path=None, - rerun_failures=False, failure_manifest=None, **otherOptions): + test_tags=None, dump_tests=None, utility_path=None, **otherOptions): """Run xpcshell tests. |xpcshell|, is the xpcshell executable to use to run the tests. @@ -1061,8 +1063,9 @@ class XPCShellTests(object): breakpad symbols for processing crashes in tests. |manifest|, if provided, is a file containing a list of test directories to run. - |testPaths|, if provided, is a list of paths to files or directories containing - tests to run. + |testdirs|, if provided, is a list of absolute paths of test directories. + No-manifest only option. + |testPath|, if provided, indicates a single path and/or test to run. |pluginsPath|, if provided, custom plugins directory to be returned from the xpcshell dir svc provider for NS_APP_PLUGINS_DIR_LIST. |interactive|, if set to True, indicates to provide an xpcshell prompt @@ -1080,6 +1083,8 @@ class XPCShellTests(object): directory if running only a subset of tests. |mozInfo|, if set, specifies specifies build configuration information, either as a filename containing JSON, or a dict. |shuffle|, if True, execute tests in random order. + |testsRootDir|, absolute path to root directory of all tests. This is used + by xUnit generation to determine the package name of the tests. |testingModulesDir|, if provided, specifies where JS modules reside. xpcshell will register a resource handler mapping this path. |otherOptions| may be present for the convenience of subclasses @@ -1087,6 +1092,9 @@ class XPCShellTests(object): global gotSIGINT + if testdirs is None: + testdirs = [] + # Try to guess modules directory. # This somewhat grotesque hack allows the buildbot machines to find the # modules directory without having to configure the buildbot hosts. This @@ -1099,16 +1107,6 @@ class XPCShellTests(object): if os.path.isdir(possible): testingModulesDir = possible - if rerun_failures: - if os.path.exists(failure_manifest): - rerun_manifest = os.path.join(os.path.dirname(failure_manifest), "rerun.ini") - shutil.copyfile(failure_manifest, rerun_manifest) - os.remove(failure_manifest) - manifest = rerun_manifest - else: - print >> sys.stderr, "No failures were found to re-run." - sys.exit(1) - if testingModulesDir: # The resource loader expects native paths. Depending on how we were # invoked, a UNIX style path may sneak in on Windows. We try to @@ -1137,6 +1135,8 @@ class XPCShellTests(object): self.appPath = appPath self.symbolsPath = symbolsPath self.manifest = manifest + self.testdirs = testdirs + self.testPath = testPath self.dump_tests = dump_tests self.interactive = interactive self.verbose = verbose @@ -1149,7 +1149,11 @@ class XPCShellTests(object): self.testingModulesDir = testingModulesDir self.pluginsPath = pluginsPath self.sequential = sequential - self.failure_manifest = failure_manifest + + if not testdirs and not manifest: + # nothing to test! + self.log.error("Error: No test dirs or test manifest specified!") + return False self.testCount = 0 self.passCount = 0 @@ -1202,7 +1206,7 @@ class XPCShellTests(object): pStdout, pStderr = self.getPipes() - self.buildTestList(test_tags, testPaths) + self.buildTestList(test_tags) if self.singleFile: self.sequential = True @@ -1230,7 +1234,7 @@ class XPCShellTests(object): 'logfiles': self.logfiles, 'xpcshell': self.xpcshell, 'xpcsRunArgs': self.xpcsRunArgs, - 'failureManifest': self.failure_manifest, + 'failureManifest': failureManifest, 'harness_timeout': self.harness_timeout, 'stack_fixer_function': self.stack_fixer_function, } @@ -1275,10 +1279,13 @@ class XPCShellTests(object): if self.singleFile and not path.endswith(self.singleFile): continue + if self.testPath and path.find(self.testPath) == -1: + continue + self.testCount += 1 test = testClass(test_object, self.event, self.cleanup_dir_list, - app_dir_key=appDirKey, + tests_root_dir=testsRootDir, app_dir_key=appDirKey, interactive=interactive, verbose=verbose or test_object.get("verbose") == "true", pStdout=pStdout, pStderr=pStderr, @@ -1370,7 +1377,7 @@ class XPCShellTests(object): self.log.info("Retrying tests that failed when run in parallel.") for test_object in self.try_again_list: test = testClass(test_object, self.event, self.cleanup_dir_list, - retry=False, + retry=False, tests_root_dir=testsRootDir, app_dir_key=appDirKey, interactive=interactive, verbose=verbose, pStdout=pStdout, pStderr=pStderr, keep_going=keepGoing, log=self.log, mobileArgs=mobileArgs, @@ -1423,16 +1430,122 @@ class XPCShellTests(object): self.log.suite_end() return self.failCount == 0 +class XPCShellOptions(OptionParser): + def __init__(self): + """Process command line arguments and call runTests() to do the real work.""" + OptionParser.__init__(self) + self.add_option("--app-path", + type="string", dest="appPath", default=None, + help="application directory (as opposed to XRE directory)") + self.add_option("--interactive", + action="store_true", dest="interactive", default=False, + help="don't automatically run tests, drop to an xpcshell prompt") + self.add_option("--verbose", + action="store_true", dest="verbose", default=False, + help="always print stdout and stderr from tests") + self.add_option("--keep-going", + action="store_true", dest="keepGoing", default=False, + help="continue running tests after test killed with control-C (SIGINT)") + self.add_option("--logfiles", + action="store_true", dest="logfiles", default=True, + help="create log files (default, only used to override --no-logfiles)") + self.add_option("--dump-tests", + type="string", dest="dump_tests", default=None, + help="Specify path to a filename to dump all the tests that will be run") + self.add_option("--manifest", + type="string", dest="manifest", default=None, + help="Manifest of test directories to use") + self.add_option("--no-logfiles", + action="store_false", dest="logfiles", + help="don't create log files") + self.add_option("--sequential", + action="store_true", dest="sequential", default=False, + help="Run all tests sequentially") + self.add_option("--test-path", + type="string", dest="testPath", default=None, + help="single path and/or test filename to test") + self.add_option("--tests-root-dir", + type="string", dest="testsRootDir", default=None, + help="absolute path to directory where all tests are located. this is typically $(objdir)/_tests") + self.add_option("--testing-modules-dir", + dest="testingModulesDir", default=None, + help="Directory where testing modules are located.") + self.add_option("--test-plugin-path", + type="string", dest="pluginsPath", default=None, + help="Path to the location of a plugins directory containing the test plugin or plugins required for tests. " + "By default xpcshell's dir svc provider returns gre/plugins. Use test-plugin-path to add a directory " + "to return for NS_APP_PLUGINS_DIR_LIST when queried.") + self.add_option("--total-chunks", + type = "int", dest = "totalChunks", default=1, + help = "how many chunks to split the tests up into") + self.add_option("--this-chunk", + type = "int", dest = "thisChunk", default=1, + help = "which chunk to run between 1 and --total-chunks") + self.add_option("--profile-name", + type = "string", dest="profileName", default=None, + help="name of application profile being tested") + self.add_option("--build-info-json", + type = "string", dest="mozInfo", default=None, + help="path to a mozinfo.json including information about the build configuration. defaults to looking for mozinfo.json next to the script.") + self.add_option("--shuffle", + action="store_true", dest="shuffle", default=False, + help="Execute tests in random order") + self.add_option("--failure-manifest", dest="failureManifest", + action="store", + help="path to file where failure manifest will be written.") + self.add_option("--xre-path", + action = "store", type = "string", dest = "xrePath", + # individual scripts will set a sane default + default = None, + help = "absolute path to directory containing XRE (probably xulrunner)") + self.add_option("--symbols-path", + action = "store", type = "string", dest = "symbolsPath", + default = None, + help = "absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols") + self.add_option("--debugger", + action = "store", dest = "debugger", + help = "use the given debugger to launch the application") + self.add_option("--debugger-args", + action = "store", dest = "debuggerArgs", + help = "pass the given args to the debugger _before_ " + "the application on the command line") + self.add_option("--debugger-interactive", + action = "store_true", dest = "debuggerInteractive", + help = "prevents the test harness from redirecting " + "stdout and stderr for interactive debuggers") + self.add_option("--jsdebugger", dest="jsDebugger", action="store_true", + help="Waits for a devtools JS debugger to connect before " + "starting the test.") + self.add_option("--jsdebugger-port", type="int", dest="jsDebuggerPort", + default=6000, + help="The port to listen on for a debugger connection if " + "--jsdebugger is specified.") + self.add_option("--tag", + action="append", dest="test_tags", + default=None, + help="filter out tests that don't have the given tag. Can be " + "used multiple times in which case the test must contain " + "at least one of the given tags.") + self.add_option("--utility-path", + action="store", dest="utility_path", + default=None, + help="Path to a directory containing utility programs, such " + "as stack fixer scripts.") def main(): - parser = parser_desktop() + parser = XPCShellOptions() commandline.add_logging_group(parser) - options = parser.parse_args() + options, args = parser.parse_args() + log = commandline.setup_logging("XPCShell", options, {"tbpl": sys.stdout}) - if options.xpcshell is None: - print >> sys.stderr, """Must provide path to xpcshell using --xpcshell""" + if len(args) < 2 and options.manifest is None or \ + (len(args) < 1 and options.manifest is not None): + print >>sys.stderr, """Usage: %s + or: %s --manifest=test.manifest """ % (sys.argv[0], + sys.argv[0]) + sys.exit(1) xpcsh = XPCShellTests(log) @@ -1440,7 +1553,7 @@ def main(): print >>sys.stderr, "Error: You must specify a test filename in interactive mode!" sys.exit(1) - if not xpcsh.runTests(**vars(options)): + if not xpcsh.runTests(args[0], testdirs=args[1:], **options.__dict__): sys.exit(1) if __name__ == '__main__': diff --git a/testing/xpcshell/selftest.py b/testing/xpcshell/selftest.py index 854d32689759..5ed4fe6cf220 100644 --- a/testing/xpcshell/selftest.py +++ b/testing/xpcshell/selftest.py @@ -422,6 +422,7 @@ tail = manifest=self.manifest, mozInfo=mozinfo.info, shuffle=shuffle, + testsRootDir=self.tempdir, verbose=verbose, sequential=True, utility_path=self.utility_path), diff --git a/testing/xpcshell/xpcshellcommandline.py b/testing/xpcshell/xpcshellcommandline.py deleted file mode 100644 index 7152ec9ac524..000000000000 --- a/testing/xpcshell/xpcshellcommandline.py +++ /dev/null @@ -1,202 +0,0 @@ -import argparse - -def add_common_arguments(parser): - parser.add_argument("--app-path", - type=unicode, dest="appPath", default=None, - help="application directory (as opposed to XRE directory)") - parser.add_argument("--interactive", - action="store_true", dest="interactive", default=False, - help="don't automatically run tests, drop to an xpcshell prompt") - parser.add_argument("--verbose", - action="store_true", dest="verbose", default=False, - help="always print stdout and stderr from tests") - parser.add_argument("--keep-going", - action="store_true", dest="keepGoing", default=False, - help="continue running tests after test killed with control-C (SIGINT)") - parser.add_argument("--logfiles", - action="store_true", dest="logfiles", default=True, - help="create log files (default, only used to override --no-logfiles)") - parser.add_argument("--dump-tests", type=str, dest="dump_tests", default=None, - help="Specify path to a filename to dump all the tests that will be run") - parser.add_argument("--manifest", - type=unicode, dest="manifest", default=None, - help="Manifest of test directories to use") - parser.add_argument("--no-logfiles", - action="store_false", dest="logfiles", - help="don't create log files") - parser.add_argument("--sequential", - action="store_true", dest="sequential", default=False, - help="Run all tests sequentially") - parser.add_argument("--testing-modules-dir", - dest="testingModulesDir", default=None, - help="Directory where testing modules are located.") - parser.add_argument("--test-plugin-path", - type=str, dest="pluginsPath", default=None, - help="Path to the location of a plugins directory containing the test plugin or plugins required for tests. " - "By default xpcshell's dir svc provider returns gre/plugins. Use test-plugin-path to add a directory " - "to return for NS_APP_PLUGINS_DIR_LIST when queried.") - parser.add_argument("--total-chunks", - type=int, dest="totalChunks", default=1, - help="how many chunks to split the tests up into") - parser.add_argument("--this-chunk", - type=int, dest="thisChunk", default=1, - help="which chunk to run between 1 and --total-chunks") - parser.add_argument("--profile-name", - type=str, dest="profileName", default=None, - help="name of application profile being tested") - parser.add_argument("--build-info-json", - type=str, dest="mozInfo", default=None, - help="path to a mozinfo.json including information about the build configuration. defaults to looking for mozinfo.json next to the script.") - parser.add_argument("--shuffle", - action="store_true", dest="shuffle", default=False, - help="Execute tests in random order") - parser.add_argument("--xre-path", - action="store", type=str, dest="xrePath", - # individual scripts will set a sane default - default=None, - help="absolute path to directory containing XRE (probably xulrunner)") - parser.add_argument("--symbols-path", - action="store", type=str, dest="symbolsPath", - default=None, - help="absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols") - parser.add_argument("--debugger", - action="store", dest="debugger", - help="use the given debugger to launch the application") - parser.add_argument("--debugger-args", - action="store", dest="debuggerArgs", - help="pass the given args to the debugger _before_ " - "the application on the command line") - parser.add_argument("--debugger-interactive", - action="store_true", dest="debuggerInteractive", - help="prevents the test harness from redirecting " - "stdout and stderr for interactive debuggers") - parser.add_argument("--jsdebugger", dest="jsDebugger", action="store_true", - help="Waits for a devtools JS debugger to connect before " - "starting the test.") - parser.add_argument("--jsdebugger-port", type=int, dest="jsDebuggerPort", - default=6000, - help="The port to listen on for a debugger connection if " - "--jsdebugger is specified.") - parser.add_argument("--tag", - action="append", dest="test_tags", - default=None, - help="filter out tests that don't have the given tag. Can be " - "used multiple times in which case the test must contain " - "at least one of the given tags.") - parser.add_argument("--utility-path", - action="store", dest="utility_path", - default=None, - help="Path to a directory containing utility programs, such " - "as stack fixer scripts.") - parser.add_argument("--xpcshell", - action="store", dest="xpcshell", - default=None, - help="Path to xpcshell binary") - # This argument can be just present, or the path to a manifest file. The - # just-present case is usually used for mach which can provide a default - # path to the failure file from the previous run - parser.add_argument("--rerun-failures", - action="store_true", - help="Rerun failures from the previous run, if any") - parser.add_argument("--failure-manifest", - action="store", - help="Path to a manifest file from which to rerun failures " - "(with --rerun-failure) or in which to record failed tests") - parser.add_argument("testPaths", nargs="*", default=None, - help="Paths of tests to run.") - -def add_remote_arguments(parser): - parser.add_argument("--deviceIP", action="store", type=str, dest="deviceIP", - help="ip address of remote device to test") - - parser.add_argument("--devicePort", action="store", type=str, dest="devicePort", - default=20701, help="port of remote device to test") - - parser.add_argument("--dm_trans", action="store", type=str, dest="dm_trans", - choices=["adb", "sut"], default="sut", - help="the transport to use to communicate with device: [adb|sut]; default=sut") - - parser.add_argument("--objdir", action="store", type=str, dest="objdir", - help="local objdir, containing xpcshell binaries") - - - parser.add_argument("--apk", action="store", type=str, dest="localAPK", - help="local path to Fennec APK") - - - parser.add_argument("--noSetup", action="store_false", dest="setup", default=True, - help="do not copy any files to device (to be used only if device is already setup)") - - parser.add_argument("--local-lib-dir", action="store", type=str, dest="localLib", - help="local path to library directory") - - parser.add_argument("--local-bin-dir", action="store", type=str, dest="localBin", - help="local path to bin directory") - - parser.add_argument("--remoteTestRoot", action="store", type=str, dest="remoteTestRoot", - help="remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)") - -def add_b2g_arguments(parser): - parser.add_argument('--b2gpath', action='store', type=str, dest='b2g_path', - help="Path to B2G repo or qemu dir") - - parser.add_argument('--emupath', action='store', type=str, dest='emu_path', - help="Path to emulator folder (if different " - "from b2gpath") - - parser.add_argument('--no-clean', action='store_false', dest='clean', default=True, - help="Do not clean TESTROOT. Saves [lots of] time") - - parser.add_argument('--emulator', action='store', type=str, dest='emulator', - default="arm", choices=["x86", "arm"], - help="Architecture of emulator to use: x86 or arm") - - parser.add_argument('--no-window', action='store_true', dest='no_window', default=False, - help="Pass --no-window to the emulator") - - parser.add_argument('--adbpath', action='store', type=str, dest='adb_path', - default="adb", help="Path to adb") - - parser.add_argument('--address', action='store', type=str, dest='address', - help="host:port of running Gecko instance to connect to") - - parser.add_argument('--use-device-libs', action='store_true', dest='use_device_libs', - default=None, help="Don't push .so's") - - parser.add_argument("--gecko-path", action="store", type=str, dest="geckoPath", - help="the path to a gecko distribution that should " - "be installed on the emulator prior to test") - - parser.add_argument("--logdir", action="store", type=str, dest="logdir", - help="directory to store log files") - - parser.add_argument('--busybox', action='store', type=str, dest='busybox', - help="Path to busybox binary to install on device") - - parser.set_defaults(remoteTestRoot="/data/local/tests", - dm_trans="adb") - -def parser_desktop(): - parser = argparse.ArgumentParser() - add_common_arguments(parser) - return parser - -def parser_remote(): - parser = argparse.ArgumentParser() - common = parser.add_argument_group("Common Options") - add_common_arguments(common) - remote = parser.add_argument_group("Remote Options") - add_remote_arguments(remote) - - return parser - -def parser_b2g(): - parser = argparse.ArgumentParser() - common = parser.add_argument_group("Common Options") - add_common_arguments(common) - remote = parser.add_argument_group("Remote Options") - add_remote_arguments(remote) - b2g = parser.add_argument_group("B2G Options") - add_b2g_arguments(b2g) - - return parser From 1d6a2029003b548cd71634b9314de8134f81b7b9 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:26 +0900 Subject: [PATCH 025/131] Bug 895274 part.187 Rename NS_QUERY_TEXT_RECT to eQueryTextRect r=smaug --- dom/base/nsDOMWindowUtils.cpp | 4 ++-- dom/base/nsQueryContentEventResult.cpp | 2 +- dom/events/ContentEventHandler.cpp | 4 ++-- dom/events/ContentEventHandler.h | 2 +- dom/events/EventStateManager.cpp | 2 +- dom/events/IMEContentObserver.cpp | 4 ++-- dom/ipc/TabParent.cpp | 2 +- widget/ContentCache.cpp | 8 ++++---- widget/ContentCache.h | 2 +- widget/EventMessageList.h | 2 +- widget/TextEvents.h | 4 ++-- widget/cocoa/TextInputHandler.mm | 2 +- widget/gtk/IMContextWrapper.cpp | 4 ++-- widget/windows/IMMHandler.cpp | 2 +- widget/windows/TSFTextStore.cpp | 8 ++++---- 15 files changed, 26 insertions(+), 26 deletions(-) diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 53d98a817dd7..7219042c216d 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -1936,7 +1936,7 @@ nsDOMWindowUtils::SendQueryContentEvent(uint32_t aType, message = eQueryCaretRect; break; case QUERY_TEXT_RECT: - message = NS_QUERY_TEXT_RECT; + message = eQueryTextRect; break; case QUERY_EDITOR_RECT: message = eQueryEditorRect; @@ -1991,7 +1991,7 @@ nsDOMWindowUtils::SendQueryContentEvent(uint32_t aType, case eQueryCaretRect: queryEvent.InitForQueryCaretRect(aOffset, useNativeLineBreak); break; - case NS_QUERY_TEXT_RECT: + case eQueryTextRect: queryEvent.InitForQueryTextRect(aOffset, aLength, useNativeLineBreak); break; default: diff --git a/dom/base/nsQueryContentEventResult.cpp b/dom/base/nsQueryContentEventResult.cpp index 6f3a8306520d..7ffd2ead03c6 100644 --- a/dom/base/nsQueryContentEventResult.cpp +++ b/dom/base/nsQueryContentEventResult.cpp @@ -58,7 +58,7 @@ nsQueryContentEventResult::GetTentativeCaretOffset(uint32_t* aOffset) static bool IsRectEnabled(EventMessage aEventMessage) { return aEventMessage == eQueryCaretRect || - aEventMessage == NS_QUERY_TEXT_RECT || + aEventMessage == eQueryTextRect || aEventMessage == eQueryEditorRect || aEventMessage == eQueryCharacterAtPoint; } diff --git a/dom/events/ContentEventHandler.cpp b/dom/events/ContentEventHandler.cpp index 73dd49e2dc13..084743070a3c 100644 --- a/dom/events/ContentEventHandler.cpp +++ b/dom/events/ContentEventHandler.cpp @@ -802,7 +802,7 @@ ContentEventHandler::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent) return OnQueryTextContent(aEvent); case eQueryCaretRect: return OnQueryCaretRect(aEvent); - case NS_QUERY_TEXT_RECT: + case eQueryTextRect: return OnQueryTextRect(aEvent); case eQueryEditorRect: return OnQueryEditorRect(aEvent); @@ -1330,7 +1330,7 @@ ContentEventHandler::OnQueryCharacterAtPoint(WidgetQueryContentEvent* aEvent) GetLineBreakType(aEvent)); NS_ENSURE_SUCCESS(rv, rv); - WidgetQueryContentEvent textRect(true, NS_QUERY_TEXT_RECT, aEvent->widget); + WidgetQueryContentEvent textRect(true, eQueryTextRect, aEvent->widget); textRect.InitForQueryTextRect(offset, 1, aEvent->mUseNativeLineBreak); rv = OnQueryTextRect(&textRect); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/events/ContentEventHandler.h b/dom/events/ContentEventHandler.h index a2b1043a6337..2707789e4a9b 100644 --- a/dom/events/ContentEventHandler.h +++ b/dom/events/ContentEventHandler.h @@ -48,7 +48,7 @@ public: nsresult OnQueryTextContent(WidgetQueryContentEvent* aEvent); // eQueryCaretRect event handler nsresult OnQueryCaretRect(WidgetQueryContentEvent* aEvent); - // NS_QUERY_TEXT_RECT event handler + // eQueryTextRect event handler nsresult OnQueryTextRect(WidgetQueryContentEvent* aEvent); // eQueryEditorRect event handler nsresult OnQueryEditorRect(WidgetQueryContentEvent* aEvent); diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index 2e711da4079b..6f2ed8102431 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -784,7 +784,7 @@ EventStateManager::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent) case eQuerySelectedText: case eQueryTextContent: case eQueryCaretRect: - case NS_QUERY_TEXT_RECT: + case eQueryTextRect: case eQueryEditorRect: if (!IsTargetCrossProcess(aEvent)) { break; diff --git a/dom/events/IMEContentObserver.cpp b/dom/events/IMEContentObserver.cpp index 019d5d6c6eb2..4f1fcd847512 100644 --- a/dom/events/IMEContentObserver.cpp +++ b/dom/events/IMEContentObserver.cpp @@ -57,8 +57,8 @@ ToChar(EventMessage aEventMessage) return "eQueryTextContent"; case eQueryCaretRect: return "eQueryCaretRect"; - case NS_QUERY_TEXT_RECT: - return "NS_QUERY_TEXT_RECT"; + case eQueryTextRect: + return "eQueryTextRect"; case eQueryEditorRect: return "eQueryEditorRect"; case eQueryContentState: diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 4685acc5e91b..908b65ddbd03 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -2369,7 +2369,7 @@ TabParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent) return true; } switch (aEvent.mMessage) { - case NS_QUERY_TEXT_RECT: + case eQueryTextRect: case eQueryCaretRect: case eQueryEditorRect: aEvent.mReply.mRect -= GetChildProcessOffset(); diff --git a/widget/ContentCache.cpp b/widget/ContentCache.cpp index 8979bd06fa98..ed79f6a90ac5 100644 --- a/widget/ContentCache.cpp +++ b/widget/ContentCache.cpp @@ -302,7 +302,7 @@ ContentCacheInChild::QueryCharRect(nsIWidget* aWidget, aCharRect.SetEmpty(); nsEventStatus status = nsEventStatus_eIgnore; - WidgetQueryContentEvent textRect(true, NS_QUERY_TEXT_RECT, aWidget); + WidgetQueryContentEvent textRect(true, eQueryTextRect, aWidget); textRect.InitForQueryTextRect(aOffset, 1); aWidget->DispatchEvent(&textRect, status); if (NS_WARN_IF(!textRect.mSucceeded)) { @@ -394,7 +394,7 @@ ContentCacheInChild::CacheTextRects(nsIWidget* aWidget, if (!mSelection.Collapsed()) { nsEventStatus status = nsEventStatus_eIgnore; - WidgetQueryContentEvent textRect(true, NS_QUERY_TEXT_RECT, aWidget); + WidgetQueryContentEvent textRect(true, eQueryTextRect, aWidget); textRect.InitForQueryTextRect(mSelection.StartOffset(), mSelection.Length()); aWidget->DispatchEvent(&textRect, status); @@ -583,10 +583,10 @@ ContentCacheInParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent, this, aEvent.mReply.mOffset, aEvent.mReply.mString.Length())); break; } - case NS_QUERY_TEXT_RECT: + case eQueryTextRect: MOZ_LOG(sContentCacheLog, LogLevel::Info, ("ContentCacheInParent: 0x%p HandleQueryContentEvent(" - "aEvent={ mMessage=NS_QUERY_TEXT_RECT, mInput={ mOffset=%u, " + "aEvent={ mMessage=eQueryTextRect, mInput={ mOffset=%u, " "mLength=%u } }, aWidget=0x%p), mText.Length()=%u", this, aEvent.mInput.mOffset, aEvent.mInput.mLength, aWidget, mText.Length())); diff --git a/widget/ContentCache.h b/widget/ContentCache.h index 29070708c123..96bc3f64e934 100644 --- a/widget/ContentCache.h +++ b/widget/ContentCache.h @@ -293,7 +293,7 @@ public: * knowing the exact length of text. It's up to widget to handle cases when * the returned offset/length are different from the queried offset/length. * - * For NS_QUERY_TEXT_RECT, fail if cached offset/length aren't equals to input. + * For eQueryTextRect, fail if cached offset/length aren't equals to input. * Cocoa widget always queries selected offset, so it works on it. * * For eQueryCaretRect, fail if cached offset isn't equals to input diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 187919d4e8be..b20ca99a3f87 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -226,7 +226,7 @@ NS_EVENT_MESSAGE(eQueryCaretRect, eQueryContentEventFirst + 3) // Query for the bounding rect of a range of characters. This works on any // valid character range given offset and length. Result is relative to top // level widget coordinates -NS_EVENT_MESSAGE(NS_QUERY_TEXT_RECT, eQueryContentEventFirst + 4) +NS_EVENT_MESSAGE(eQueryTextRect, eQueryContentEventFirst + 4) // Query for the bounding rect of the current focused frame. Result is relative // to top level widget coordinates NS_EVENT_MESSAGE(eQueryEditorRect, eQueryContentEventFirst + 5) diff --git a/widget/TextEvents.h b/widget/TextEvents.h index de057227994a..a1486b5a43c8 100644 --- a/widget/TextEvents.h +++ b/widget/TextEvents.h @@ -514,7 +514,7 @@ public: void InitForQueryTextRect(uint32_t aOffset, uint32_t aLength, bool aUseNativeLineBreak = true) { - NS_ASSERTION(mMessage == NS_QUERY_TEXT_RECT, + NS_ASSERTION(mMessage == eQueryTextRect, "wrong initializer is called"); mInput.mOffset = aOffset; mInput.mLength = aLength; @@ -553,7 +553,7 @@ public: { NS_ASSERTION(mMessage == eQuerySelectedText || mMessage == eQueryCaretRect || - mMessage == NS_QUERY_TEXT_RECT, + mMessage == eQueryTextRect, "not querying selection or text rect"); return mReply.mWritingMode; } diff --git a/widget/cocoa/TextInputHandler.mm b/widget/cocoa/TextInputHandler.mm index 68a9b2e997d1..2bfcd7535e21 100644 --- a/widget/cocoa/TextInputHandler.mm +++ b/widget/cocoa/TextInputHandler.mm @@ -3186,7 +3186,7 @@ IMEInputHandler::FirstRectForCharacterRange(NSRange& aRange, LayoutDeviceIntRect r; bool useCaretRect = (aRange.length == 0); if (!useCaretRect) { - WidgetQueryContentEvent charRect(true, NS_QUERY_TEXT_RECT, mWidget); + WidgetQueryContentEvent charRect(true, eQueryTextRect, mWidget); charRect.InitForQueryTextRect(aRange.location, 1); DispatchEvent(charRect); if (charRect.mSucceeded) { diff --git a/widget/gtk/IMContextWrapper.cpp b/widget/gtk/IMContextWrapper.cpp index 23f6606f0cab..234a95699c0a 100644 --- a/widget/gtk/IMContextWrapper.cpp +++ b/widget/gtk/IMContextWrapper.cpp @@ -1811,7 +1811,7 @@ IMContextWrapper::SetCursorPosition(GtkIMContext* aContext) WidgetQueryContentEvent charRect(true, useCaret ? eQueryCaretRect : - NS_QUERY_TEXT_RECT, + eQueryTextRect, mLastFocusedWindow); if (useCaret) { charRect.InitForQueryCaretRect(mSelection.mOffset); @@ -1833,7 +1833,7 @@ IMContextWrapper::SetCursorPosition(GtkIMContext* aContext) if (!charRect.mSucceeded) { MOZ_LOG(gGtkIMLog, LogLevel::Error, ("GTKIM: %p SetCursorPosition(), FAILED, %s was failed", - this, useCaret ? "eQueryCaretRect" : "NS_QUERY_TEXT_RECT")); + this, useCaret ? "eQueryCaretRect" : "eQueryTextRect")); return; } diff --git a/widget/windows/IMMHandler.cpp b/widget/windows/IMMHandler.cpp index b823e2c0ec29..ff007559f82d 100644 --- a/widget/windows/IMMHandler.cpp +++ b/widget/windows/IMMHandler.cpp @@ -2165,7 +2165,7 @@ IMMHandler::GetCharacterRectOfSelectedTextAt(nsWindow* aWindow, // If there is a caret and retrieving offset is same as the caret offset, // we should use the caret rect. if (offset != caretOffset) { - WidgetQueryContentEvent charRect(true, NS_QUERY_TEXT_RECT, aWindow); + WidgetQueryContentEvent charRect(true, eQueryTextRect, aWindow); charRect.InitForQueryTextRect(offset, 1); aWindow->InitEvent(charRect, &point); aWindow->DispatchWindowEvent(&charRect); diff --git a/widget/windows/TSFTextStore.cpp b/widget/windows/TSFTextStore.cpp index 37d3f6de79cf..36aa0a872a65 100644 --- a/widget/windows/TSFTextStore.cpp +++ b/widget/windows/TSFTextStore.cpp @@ -3424,7 +3424,7 @@ TSFTextStore::GetACPFromPoint(TsViewCookie vcView, // offset since there is no inexpensive API to check it strictly. // XXX If we retrieve 2 bounding boxes, one is before the offset and // the other is after the offset, we could resolve the offset. - // However, dispatching 2 NS_QUERY_TEXT_RECT may be expensive. + // However, dispatching 2 eQueryTextRect may be expensive. // So, use tentative offset for now. offset = charAtPt.mReply.mTentativeCaretOffset; @@ -3583,15 +3583,15 @@ TSFTextStore::GetTextExt(TsViewCookie vcView, return TS_E_NOLAYOUT; } - // use NS_QUERY_TEXT_RECT to get rect in system, screen coordinates - WidgetQueryContentEvent event(true, NS_QUERY_TEXT_RECT, mWidget); + // use eQueryTextRect to get rect in system, screen coordinates + WidgetQueryContentEvent event(true, eQueryTextRect, mWidget); mWidget->InitEvent(event); event.InitForQueryTextRect(acpStart, acpEnd - acpStart); DispatchEvent(event); if (!event.mSucceeded) { MOZ_LOG(sTextStoreLog, LogLevel::Error, ("TSF: 0x%p TSFTextStore::GetTextExt() FAILED due to " - "NS_QUERY_TEXT_RECT failure", this)); + "eQueryTextRect failure", this)); return TS_E_INVALIDPOS; // but unexpected failure, maybe. } // IMEs don't like empty rects, fix here From 966f685af3748adf16b653a0b2569d91c24ece00 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:26 +0900 Subject: [PATCH 026/131] Bug 895274 part.188 Rename NS_COMPOSITION_COMMIT_AS_IS to eCompositionCommitAsIs r=smaug --- dom/events/IMEStateManager.cpp | 4 ++-- dom/events/TextComposition.cpp | 14 +++++++------- editor/libeditor/nsEditor.cpp | 2 +- widget/ContentCache.cpp | 4 ++-- widget/EventMessageList.h | 4 ++-- widget/TextEventDispatcher.cpp | 2 +- widget/TextEvents.h | 6 +++--- widget/WidgetEventImpl.cpp | 2 +- widget/android/nsWindow.cpp | 5 ++--- widget/cocoa/TextInputHandler.mm | 2 +- widget/gtk/IMContextWrapper.cpp | 2 +- widget/windows/IMMHandler.cpp | 2 +- 12 files changed, 24 insertions(+), 25 deletions(-) diff --git a/dom/events/IMEStateManager.cpp b/dom/events/IMEStateManager.cpp index 93f472593425..083aaf858d02 100644 --- a/dom/events/IMEStateManager.cpp +++ b/dom/events/IMEStateManager.cpp @@ -145,8 +145,8 @@ GetEventMessageName(EventMessage aMessage) return "NS_COMPOSITION_UPDATE"; case NS_COMPOSITION_CHANGE: return "NS_COMPOSITION_CHANGE"; - case NS_COMPOSITION_COMMIT_AS_IS: - return "NS_COMPOSITION_COMMIT_AS_IS"; + case eCompositionCommitAsIs: + return "eCompositionCommitAsIs"; case NS_COMPOSITION_COMMIT: return "NS_COMPOSITION_COMMIT"; case eSetSelection: diff --git a/dom/events/TextComposition.cpp b/dom/events/TextComposition.cpp index 79458fd5e55d..5713fa0a72b4 100644 --- a/dom/events/TextComposition.cpp +++ b/dom/events/TextComposition.cpp @@ -234,12 +234,12 @@ TextComposition::DispatchCompositionEvent( RemoveControlCharactersFrom(aCompositionEvent->mData, aCompositionEvent->mRanges); } - if (aCompositionEvent->mMessage == NS_COMPOSITION_COMMIT_AS_IS) { + if (aCompositionEvent->mMessage == eCompositionCommitAsIs) { NS_ASSERTION(!aCompositionEvent->mRanges, - "mRanges of NS_COMPOSITION_COMMIT_AS_IS should be null"); + "mRanges of eCompositionCommitAsIs should be null"); aCompositionEvent->mRanges = nullptr; NS_ASSERTION(aCompositionEvent->mData.IsEmpty(), - "mData of NS_COMPOSITION_COMMIT_AS_IS should be empty string"); + "mData of eCompositionCommitAsIs should be empty string"); if (mLastData == IDEOGRAPHIC_SPACE) { // If the last data is an ideographic space (FullWidth space), it must be // a placeholder character of some Chinese IME. So, committing with @@ -286,7 +286,7 @@ TextComposition::DispatchCompositionEvent( switch (aCompositionEvent->mMessage) { case NS_COMPOSITION_END: case NS_COMPOSITION_CHANGE: - case NS_COMPOSITION_COMMIT_AS_IS: + case eCompositionCommitAsIs: case NS_COMPOSITION_COMMIT: committingData = &aCompositionEvent->mData; break; @@ -490,7 +490,7 @@ TextComposition::RequestToCommit(nsIWidget* aWidget, bool aDiscard) // Otherwise, synthesize the commit in content. nsAutoString data(aDiscard ? EmptyString() : lastData); if (data == mLastData) { - DispatchCompositionEventRunnable(NS_COMPOSITION_COMMIT_AS_IS, EmptyString(), + DispatchCompositionEventRunnable(eCompositionCommitAsIs, EmptyString(), true); } else { DispatchCompositionEventRunnable(NS_COMPOSITION_COMMIT, data, true); @@ -626,10 +626,10 @@ TextComposition::CompositionEventDispatcher::Run() break; } case NS_COMPOSITION_CHANGE: - case NS_COMPOSITION_COMMIT_AS_IS: + case eCompositionCommitAsIs: case NS_COMPOSITION_COMMIT: { WidgetCompositionEvent compEvent(true, mEventMessage, widget); - if (mEventMessage != NS_COMPOSITION_COMMIT_AS_IS) { + if (mEventMessage != eCompositionCommitAsIs) { compEvent.mData = mData; } compEvent.mFlags.mIsSynthesizedForTests = diff --git a/editor/libeditor/nsEditor.cpp b/editor/libeditor/nsEditor.cpp index 5aaff664e6f2..8835252bb03e 100644 --- a/editor/libeditor/nsEditor.cpp +++ b/editor/libeditor/nsEditor.cpp @@ -5163,7 +5163,7 @@ nsEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent) case NS_COMPOSITION_END: case NS_COMPOSITION_UPDATE: case NS_COMPOSITION_CHANGE: - case NS_COMPOSITION_COMMIT_AS_IS: + case eCompositionCommitAsIs: // Don't allow composition events whose internal event are not // WidgetCompositionEvent. widgetGUIEvent = aEvent->GetInternalNSEvent()->AsCompositionEvent(); diff --git a/widget/ContentCache.cpp b/widget/ContentCache.cpp index ed79f6a90ac5..2e6f53b1b6b3 100644 --- a/widget/ContentCache.cpp +++ b/widget/ContentCache.cpp @@ -35,8 +35,8 @@ GetEventMessageName(EventMessage aMessage) return "NS_COMPOSITION_UPDATE"; case NS_COMPOSITION_CHANGE: return "NS_COMPOSITION_CHANGE"; - case NS_COMPOSITION_COMMIT_AS_IS: - return "NS_COMPOSITION_COMMIT_AS_IS"; + case eCompositionCommitAsIs: + return "eCompositionCommitAsIs"; case NS_COMPOSITION_COMMIT: return "NS_COMPOSITION_COMMIT"; case eSetSelection: diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index b20ca99a3f87..61e10e1e31d8 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -161,13 +161,13 @@ NS_EVENT_MESSAGE(NS_COMPOSITION_UPDATE, NS_COMPOSITION_EVENT_START + 2) // composition string isn't changed but the ranges are changed. This causes // a DOM "text" event which is a non-standard DOM event. NS_EVENT_MESSAGE(NS_COMPOSITION_CHANGE, NS_COMPOSITION_EVENT_START + 3) -// NS_COMPOSITION_COMMIT_AS_IS is the message for representing a commit of +// eCompositionCommitAsIs is the message for representing a commit of // composition string. TextComposition will commit composition with the // last data. TextComposition will dispatch this event to the DOM tree as // NS_COMPOSITION_CHANGE without clause information. After that, // NS_COMPOSITION_END will be dispatched automatically. // Its mData and mRanges should be empty and nullptr. -NS_EVENT_MESSAGE(NS_COMPOSITION_COMMIT_AS_IS, NS_COMPOSITION_EVENT_START + 4) +NS_EVENT_MESSAGE(eCompositionCommitAsIs, NS_COMPOSITION_EVENT_START + 4) // NS_COMPOSITION_COMMIT is the message for representing a commit of // composition string with its mData value. TextComposition will dispatch this // event to the DOM tree as NS_COMPOSITION_CHANGE without clause information. diff --git a/widget/TextEventDispatcher.cpp b/widget/TextEventDispatcher.cpp index 01e71daa24dd..efe49ea3ba24 100644 --- a/widget/TextEventDispatcher.cpp +++ b/widget/TextEventDispatcher.cpp @@ -269,7 +269,7 @@ TextEventDispatcher::CommitComposition(nsEventStatus& aStatus, mIsComposing = false; EventMessage message = aCommitString ? NS_COMPOSITION_COMMIT : - NS_COMPOSITION_COMMIT_AS_IS; + eCompositionCommitAsIs; WidgetCompositionEvent compositionCommitEvent(true, message, widget); InitEvent(compositionCommitEvent); if (message == NS_COMPOSITION_COMMIT) { diff --git a/widget/TextEvents.h b/widget/TextEvents.h index a1486b5a43c8..0cf7ef8600ed 100644 --- a/widget/TextEvents.h +++ b/widget/TextEvents.h @@ -436,20 +436,20 @@ public: { return mMessage == NS_COMPOSITION_CHANGE || mMessage == NS_COMPOSITION_COMMIT || - mMessage == NS_COMPOSITION_COMMIT_AS_IS; + mMessage == eCompositionCommitAsIs; } bool CausesDOMCompositionEndEvent() const { return mMessage == NS_COMPOSITION_END || mMessage == NS_COMPOSITION_COMMIT || - mMessage == NS_COMPOSITION_COMMIT_AS_IS; + mMessage == eCompositionCommitAsIs; } bool IsFollowedByCompositionEnd() const { return mOriginalMessage == NS_COMPOSITION_COMMIT || - mOriginalMessage == NS_COMPOSITION_COMMIT_AS_IS; + mOriginalMessage == eCompositionCommitAsIs; } }; diff --git a/widget/WidgetEventImpl.cpp b/widget/WidgetEventImpl.cpp index b309a86622ee..ba4a77df17d0 100644 --- a/widget/WidgetEventImpl.cpp +++ b/widget/WidgetEventImpl.cpp @@ -140,7 +140,7 @@ WidgetEvent::HasIMEEventMessage() const case NS_COMPOSITION_END: case NS_COMPOSITION_UPDATE: case NS_COMPOSITION_CHANGE: - case NS_COMPOSITION_COMMIT_AS_IS: + case eCompositionCommitAsIs: case NS_COMPOSITION_COMMIT: return true; default: diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 7b6df4126943..8120e905c74a 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -1686,8 +1686,7 @@ nsWindow::RemoveIMEComposition() nsRefPtr kungFuDeathGrip(this); AutoIMEMask selMask(mIMEMaskSelectionUpdate); - WidgetCompositionEvent compositionCommitEvent(true, - NS_COMPOSITION_COMMIT_AS_IS, + WidgetCompositionEvent compositionCommitEvent(true, eCompositionCommitAsIs, this); InitEvent(compositionCommitEvent, nullptr); DispatchEvent(&compositionCommitEvent); @@ -1864,7 +1863,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) // Don't end composition when composing text. if (ae->Action() != AndroidGeckoEvent::IME_COMPOSE_TEXT) { WidgetCompositionEvent compositionCommitEvent( - true, NS_COMPOSITION_COMMIT_AS_IS, this); + true, eCompositionCommitAsIs, this); InitEvent(compositionCommitEvent, nullptr); DispatchEvent(&compositionCommitEvent); } diff --git a/widget/cocoa/TextInputHandler.mm b/widget/cocoa/TextInputHandler.mm index 2bfcd7535e21..638daa53ba02 100644 --- a/widget/cocoa/TextInputHandler.mm +++ b/widget/cocoa/TextInputHandler.mm @@ -2740,7 +2740,7 @@ IMEInputHandler::DispatchCompositionCommitEvent(const nsAString* aCommitString) nsRefPtr kungFuDeathGrip(this); EventMessage message = - aCommitString ? NS_COMPOSITION_COMMIT : NS_COMPOSITION_COMMIT_AS_IS; + aCommitString ? NS_COMPOSITION_COMMIT : eCompositionCommitAsIs; WidgetCompositionEvent compositionCommitEvent(true, message, mWidget); compositionCommitEvent.time = PR_IntervalNow(); if (aCommitString) { diff --git a/widget/gtk/IMContextWrapper.cpp b/widget/gtk/IMContextWrapper.cpp index 234a95699c0a..97c0f4547e4e 100644 --- a/widget/gtk/IMContextWrapper.cpp +++ b/widget/gtk/IMContextWrapper.cpp @@ -1440,7 +1440,7 @@ IMContextWrapper::DispatchCompositionCommitEvent( nsRefPtr lastFocusedWindow(mLastFocusedWindow); EventMessage message = aCommitString ? NS_COMPOSITION_COMMIT : - NS_COMPOSITION_COMMIT_AS_IS; + eCompositionCommitAsIs; mCompositionState = eCompositionState_NotComposing; mCompositionStart = UINT32_MAX; mCompositionTargetRange.Clear(); diff --git a/widget/windows/IMMHandler.cpp b/widget/windows/IMMHandler.cpp index ff007559f82d..903aa676ad89 100644 --- a/widget/windows/IMMHandler.cpp +++ b/widget/windows/IMMHandler.cpp @@ -1525,7 +1525,7 @@ IMMHandler::HandleEndComposition(nsWindow* aWindow, } EventMessage message = - aCommitString ? NS_COMPOSITION_COMMIT : NS_COMPOSITION_COMMIT_AS_IS; + aCommitString ? NS_COMPOSITION_COMMIT : eCompositionCommitAsIs; WidgetCompositionEvent compositionCommitEvent(true, message, aWindow); nsIntPoint point(0, 0); aWindow->InitEvent(compositionCommitEvent, &point); From ca0525d0bcd8c5f9c3f00bf11cba20b94709d2fa Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:26 +0900 Subject: [PATCH 027/131] Bug 895274 part.189 Rename NS_COMPOSITION_EVENT_START to eCompositionEventFirst r=smaug --- widget/EventMessageList.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 61e10e1e31d8..fa960dc5022c 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -145,35 +145,35 @@ NS_EVENT_MESSAGE(eLegacyMutationEventLast, eLegacyCharacterDataModified) NS_EVENT_MESSAGE(eUnidentifiedEvent, 2000) // composition events -NS_EVENT_MESSAGE(NS_COMPOSITION_EVENT_START, 2200) -NS_EVENT_MESSAGE(NS_COMPOSITION_START, NS_COMPOSITION_EVENT_START) +NS_EVENT_MESSAGE(eCompositionEventFirst, 2200) +NS_EVENT_MESSAGE(NS_COMPOSITION_START, eCompositionEventFirst) // NS_COMPOSITION_END is the message for DOM compositionend event. // This event should NOT be dispatched from widget if NS_COMPOSITION_COMMIT // is available. -NS_EVENT_MESSAGE(NS_COMPOSITION_END, NS_COMPOSITION_EVENT_START + 1) +NS_EVENT_MESSAGE(NS_COMPOSITION_END, eCompositionEventFirst + 1) // NS_COMPOSITION_UPDATE is the message for DOM compositionupdate event. // This event should NOT be dispatched from widget since it will be dispatched // by mozilla::TextComposition automatically if NS_COMPOSITION_CHANGE event // will change composition string. -NS_EVENT_MESSAGE(NS_COMPOSITION_UPDATE, NS_COMPOSITION_EVENT_START + 2) +NS_EVENT_MESSAGE(NS_COMPOSITION_UPDATE, eCompositionEventFirst + 2) // NS_COMPOSITION_CHANGE is the message for representing a change of // composition string. This should be dispatched from widget even if // composition string isn't changed but the ranges are changed. This causes // a DOM "text" event which is a non-standard DOM event. -NS_EVENT_MESSAGE(NS_COMPOSITION_CHANGE, NS_COMPOSITION_EVENT_START + 3) +NS_EVENT_MESSAGE(NS_COMPOSITION_CHANGE, eCompositionEventFirst + 3) // eCompositionCommitAsIs is the message for representing a commit of // composition string. TextComposition will commit composition with the // last data. TextComposition will dispatch this event to the DOM tree as // NS_COMPOSITION_CHANGE without clause information. After that, // NS_COMPOSITION_END will be dispatched automatically. // Its mData and mRanges should be empty and nullptr. -NS_EVENT_MESSAGE(eCompositionCommitAsIs, NS_COMPOSITION_EVENT_START + 4) +NS_EVENT_MESSAGE(eCompositionCommitAsIs, eCompositionEventFirst + 4) // NS_COMPOSITION_COMMIT is the message for representing a commit of // composition string with its mData value. TextComposition will dispatch this // event to the DOM tree as NS_COMPOSITION_CHANGE without clause information. // After that, NS_COMPOSITION_END will be dispatched automatically. // Its mRanges should be nullptr. -NS_EVENT_MESSAGE(NS_COMPOSITION_COMMIT, NS_COMPOSITION_EVENT_START + 5) +NS_EVENT_MESSAGE(NS_COMPOSITION_COMMIT, eCompositionEventFirst + 5) // Following events are defined for deprecated DOM events which are using // InternalUIEvent class. From 0f2bfad9b1883610eefab3707eb64561ee1f35d8 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:27 +0900 Subject: [PATCH 028/131] Bug 895274 part.190 Rename NS_COMPOSITION_START to eCompositionStart r=smaug --- dom/events/EventNameList.h | 2 +- dom/events/EventStateManager.cpp | 2 +- dom/events/IMEStateManager.cpp | 10 +++++----- dom/events/TextComposition.cpp | 6 +++--- editor/libeditor/nsEditor.cpp | 2 +- editor/libeditor/nsEditorEventListener.cpp | 2 +- widget/ContentCache.cpp | 6 +++--- widget/EventMessageList.h | 2 +- widget/TextEventDispatcher.cpp | 2 +- widget/WidgetEventImpl.cpp | 2 +- widget/android/nsWindow.cpp | 6 ++---- widget/cocoa/TextInputHandler.mm | 4 ++-- widget/gtk/IMContextWrapper.cpp | 4 ++-- widget/windows/IMMHandler.cpp | 2 +- widget/windows/TSFTextStore.cpp | 4 ++-- 15 files changed, 27 insertions(+), 29 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 5f92325fcc84..f905fa5cb6e3 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -676,7 +676,7 @@ NON_IDL_EVENT(text, EventNameType_XUL, eCompositionEventClass) NON_IDL_EVENT(compositionstart, - NS_COMPOSITION_START, + eCompositionStart, EventNameType_XUL, eCompositionEventClass) NON_IDL_EVENT(compositionupdate, diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index 6f2ed8102431..4c190bd04734 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -759,7 +759,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext, case eContentCommandScroll: DoContentCommandScrollEvent(aEvent->AsContentCommandEvent()); break; - case NS_COMPOSITION_START: + case eCompositionStart: if (aEvent->mFlags.mIsTrusted) { // If the event is trusted event, set the selected text to data of // composition event. diff --git a/dom/events/IMEStateManager.cpp b/dom/events/IMEStateManager.cpp index 083aaf858d02..361eba46f53d 100644 --- a/dom/events/IMEStateManager.cpp +++ b/dom/events/IMEStateManager.cpp @@ -137,8 +137,8 @@ static const char* GetEventMessageName(EventMessage aMessage) { switch (aMessage) { - case NS_COMPOSITION_START: - return "NS_COMPOSITION_START"; + case eCompositionStart: + return "eCompositionStart"; case NS_COMPOSITION_END: return "NS_COMPOSITION_END"; case NS_COMPOSITION_UPDATE: @@ -1163,7 +1163,7 @@ IMEStateManager::DispatchCompositionEvent( MOZ_LOG(sISMLog, LogLevel::Debug, ("ISM: IMEStateManager::DispatchCompositionEvent(), " "adding new TextComposition to the array")); - MOZ_ASSERT(aCompositionEvent->mMessage == NS_COMPOSITION_START); + MOZ_ASSERT(aCompositionEvent->mMessage == eCompositionStart); composition = new TextComposition(aPresContext, aEventTargetNode, tabParent, aCompositionEvent); @@ -1171,7 +1171,7 @@ IMEStateManager::DispatchCompositionEvent( } #ifdef DEBUG else { - MOZ_ASSERT(aCompositionEvent->mMessage != NS_COMPOSITION_START); + MOZ_ASSERT(aCompositionEvent->mMessage != eCompositionStart); } #endif // #ifdef DEBUG @@ -1277,7 +1277,7 @@ IMEStateManager::OnCompositionEventDiscarded( // Ignore compositionstart for now because sTextCompositions may not have // been created yet. - if (aCompositionEvent->mMessage == NS_COMPOSITION_START) { + if (aCompositionEvent->mMessage == eCompositionStart) { return; } diff --git a/dom/events/TextComposition.cpp b/dom/events/TextComposition.cpp index 5713fa0a72b4..cedaf6ba10d1 100644 --- a/dom/events/TextComposition.cpp +++ b/dom/events/TextComposition.cpp @@ -412,7 +412,7 @@ TextComposition::NotityUpdateComposition( // When compositon start, notify the rect of first offset character. // When not compositon start, notify the rect of selected composition // string if compositionchange event. - if (aCompositionEvent->mMessage == NS_COMPOSITION_START) { + if (aCompositionEvent->mMessage == eCompositionStart) { nsCOMPtr widget = mPresContext->GetRootWidget(); // Update composition start offset WidgetQueryContentEvent selectedTextEvent(true, eQuerySelectedText, widget); @@ -611,8 +611,8 @@ TextComposition::CompositionEventDispatcher::Run() nsRefPtr presContext = mTextComposition->mPresContext; nsEventStatus status = nsEventStatus_eIgnore; switch (mEventMessage) { - case NS_COMPOSITION_START: { - WidgetCompositionEvent compStart(true, NS_COMPOSITION_START, widget); + case eCompositionStart: { + WidgetCompositionEvent compStart(true, eCompositionStart, widget); WidgetQueryContentEvent selectedText(true, eQuerySelectedText, widget); ContentEventHandler handler(presContext); handler.OnQuerySelectedText(&selectedText); diff --git a/editor/libeditor/nsEditor.cpp b/editor/libeditor/nsEditor.cpp index 8835252bb03e..920b3a63d0db 100644 --- a/editor/libeditor/nsEditor.cpp +++ b/editor/libeditor/nsEditor.cpp @@ -5159,7 +5159,7 @@ nsEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent) // If events are not created with proper event interface, their message // are initialized with eUnidentifiedEvent. Let's ignore such event. return false; - case NS_COMPOSITION_START: + case eCompositionStart: case NS_COMPOSITION_END: case NS_COMPOSITION_UPDATE: case NS_COMPOSITION_CHANGE: diff --git a/editor/libeditor/nsEditorEventListener.cpp b/editor/libeditor/nsEditorEventListener.cpp index d5a997101d2b..2f384fb31bb9 100644 --- a/editor/libeditor/nsEditorEventListener.cpp +++ b/editor/libeditor/nsEditorEventListener.cpp @@ -463,7 +463,7 @@ nsEditorEventListener::HandleEvent(nsIDOMEvent* aEvent) case NS_COMPOSITION_CHANGE: return HandleText(aEvent); // compositionstart - case NS_COMPOSITION_START: + case eCompositionStart: return HandleStartComposition(aEvent); // compositionend case NS_COMPOSITION_END: diff --git a/widget/ContentCache.cpp b/widget/ContentCache.cpp index 2e6f53b1b6b3..51266827d730 100644 --- a/widget/ContentCache.cpp +++ b/widget/ContentCache.cpp @@ -27,8 +27,8 @@ static const char* GetEventMessageName(EventMessage aMessage) { switch (aMessage) { - case NS_COMPOSITION_START: - return "NS_COMPOSITION_START"; + case eCompositionStart: + return "eCompositionStart"; case NS_COMPOSITION_END: return "NS_COMPOSITION_END"; case NS_COMPOSITION_UPDATE: @@ -858,7 +858,7 @@ ContentCacheInParent::OnCompositionEvent(const WidgetCompositionEvent& aEvent) GetBoolName(mRequestedToCommitOrCancelComposition))); if (!aEvent.CausesDOMTextEvent()) { - MOZ_ASSERT(aEvent.mMessage == NS_COMPOSITION_START); + MOZ_ASSERT(aEvent.mMessage == eCompositionStart); mIsComposing = !aEvent.CausesDOMCompositionEndEvent(); mCompositionStart = mSelection.StartOffset(); // XXX What's this case?? diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index fa960dc5022c..0dbf49ea101e 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -146,7 +146,7 @@ NS_EVENT_MESSAGE(eUnidentifiedEvent, 2000) // composition events NS_EVENT_MESSAGE(eCompositionEventFirst, 2200) -NS_EVENT_MESSAGE(NS_COMPOSITION_START, eCompositionEventFirst) +NS_EVENT_MESSAGE(eCompositionStart, eCompositionEventFirst) // NS_COMPOSITION_END is the message for DOM compositionend event. // This event should NOT be dispatched from widget if NS_COMPOSITION_COMMIT // is available. diff --git a/widget/TextEventDispatcher.cpp b/widget/TextEventDispatcher.cpp index efe49ea3ba24..6c657ebca050 100644 --- a/widget/TextEventDispatcher.cpp +++ b/widget/TextEventDispatcher.cpp @@ -191,7 +191,7 @@ TextEventDispatcher::StartComposition(nsEventStatus& aStatus) } mIsComposing = true; - WidgetCompositionEvent compositionStartEvent(true, NS_COMPOSITION_START, + WidgetCompositionEvent compositionStartEvent(true, eCompositionStart, mWidget); InitEvent(compositionStartEvent); rv = DispatchEvent(mWidget, compositionStartEvent, aStatus); diff --git a/widget/WidgetEventImpl.cpp b/widget/WidgetEventImpl.cpp index ba4a77df17d0..e157c1e5ccde 100644 --- a/widget/WidgetEventImpl.cpp +++ b/widget/WidgetEventImpl.cpp @@ -136,7 +136,7 @@ bool WidgetEvent::HasIMEEventMessage() const { switch (mMessage) { - case NS_COMPOSITION_START: + case eCompositionStart: case NS_COMPOSITION_END: case NS_COMPOSITION_UPDATE: case NS_COMPOSITION_CHANGE: diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 8120e905c74a..b6e3149aef5d 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -1827,8 +1827,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) } { - WidgetCompositionEvent event( - true, NS_COMPOSITION_START, this); + WidgetCompositionEvent event(true, eCompositionStart, this); InitEvent(event, nullptr); DispatchEvent(&event); } @@ -1983,8 +1982,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) } { - WidgetCompositionEvent event( - true, NS_COMPOSITION_START, this); + WidgetCompositionEvent event(true, eCompositionStart, this); InitEvent(event, nullptr); DispatchEvent(&event); } diff --git a/widget/cocoa/TextInputHandler.mm b/widget/cocoa/TextInputHandler.mm index 638daa53ba02..24641f6ab5ab 100644 --- a/widget/cocoa/TextInputHandler.mm +++ b/widget/cocoa/TextInputHandler.mm @@ -2813,7 +2813,7 @@ IMEInputHandler::InsertTextAsCommittingComposition( // XXXmnakano Probably, we shouldn't emulate composition in this case. // I think that we should just fire DOM3 textInput event if we implement it. - WidgetCompositionEvent compStart(true, NS_COMPOSITION_START, mWidget); + WidgetCompositionEvent compStart(true, eCompositionStart, mWidget); InitCompositionEvent(compStart); DispatchEvent(compStart); @@ -2903,7 +2903,7 @@ IMEInputHandler::SetMarkedText(NSAttributedString* aAttrString, mMarkedRange.location = SelectedRange().location; - WidgetCompositionEvent compStart(true, NS_COMPOSITION_START, mWidget); + WidgetCompositionEvent compStart(true, eCompositionStart, mWidget); InitCompositionEvent(compStart); DispatchEvent(compStart); diff --git a/widget/gtk/IMContextWrapper.cpp b/widget/gtk/IMContextWrapper.cpp index 97c0f4547e4e..6cda8e667eb0 100644 --- a/widget/gtk/IMContextWrapper.cpp +++ b/widget/gtk/IMContextWrapper.cpp @@ -915,7 +915,7 @@ IMContextWrapper::OnSelectionChange(nsWindow* aCaller, // The focused editor might have placeholder text with normal text node. // In such case, the text node must be removed from a compositionstart - // event handler. So, we're dispatching NS_COMPOSITION_START, + // event handler. So, we're dispatching eCompositionStart, // we should ignore selection change notification. if (mCompositionState == eCompositionState_CompositionStartDispatched) { if (NS_WARN_IF(!mSelection.IsValid())) { @@ -1303,7 +1303,7 @@ IMContextWrapper::DispatchCompositionStart(GtkIMContext* aContext) ("GTKIM: %p DispatchCompositionStart(), FAILED, mCompositionStart=%u", this, mCompositionStart)); mCompositionState = eCompositionState_CompositionStartDispatched; - WidgetCompositionEvent compEvent(true, NS_COMPOSITION_START, + WidgetCompositionEvent compEvent(true, eCompositionStart, mLastFocusedWindow); InitEvent(compEvent); nsCOMPtr kungFuDeathGrip = mLastFocusedWindow; diff --git a/widget/windows/IMMHandler.cpp b/widget/windows/IMMHandler.cpp index 903aa676ad89..abe3bf1d98bf 100644 --- a/widget/windows/IMMHandler.cpp +++ b/widget/windows/IMMHandler.cpp @@ -1250,7 +1250,7 @@ IMMHandler::HandleStartComposition(nsWindow* aWindow, mCompositionStart = selection.mOffset; mCursorPosition = NO_IME_CARET; - WidgetCompositionEvent event(true, NS_COMPOSITION_START, aWindow); + WidgetCompositionEvent event(true, eCompositionStart, aWindow); nsIntPoint point(0, 0); aWindow->InitEvent(event, &point); aWindow->DispatchWindowEvent(&event); diff --git a/widget/windows/TSFTextStore.cpp b/widget/windows/TSFTextStore.cpp index 36aa0a872a65..f39e99dba1e9 100644 --- a/widget/windows/TSFTextStore.cpp +++ b/widget/windows/TSFTextStore.cpp @@ -1705,10 +1705,10 @@ TSFTextStore::FlushPendingActions() MOZ_LOG(sTextStoreLog, LogLevel::Debug, ("TSF: 0x%p TSFTextStore::FlushPendingActions() " "dispatching compositionstart event...", this)); - WidgetCompositionEvent compositionStart(true, NS_COMPOSITION_START, + WidgetCompositionEvent compositionStart(true, eCompositionStart, mWidget); mWidget->InitEvent(compositionStart); - // NS_COMPOSITION_START always causes NOTIFY_IME_OF_COMPOSITION_UPDATE. + // eCompositionStart always causes NOTIFY_IME_OF_COMPOSITION_UPDATE. // Therefore, we should wait to clear the locked content until it's // notified. mDeferClearingLockedContent = true; From ebdc7bd69bab37aaa2401781dd9ca4cd649e279e Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:27 +0900 Subject: [PATCH 029/131] Bug 895274 part.191 Rename NS_COMPOSITION_END to eCompositionEnd r=smaug --- dom/events/EventNameList.h | 2 +- dom/events/IMEStateManager.cpp | 4 ++-- dom/events/TextComposition.cpp | 6 +++--- editor/libeditor/nsEditor.cpp | 2 +- editor/libeditor/nsEditorEventListener.cpp | 2 +- widget/ContentCache.cpp | 4 ++-- widget/EventMessageList.h | 8 ++++---- widget/TextEvents.h | 2 +- widget/WidgetEventImpl.cpp | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index f905fa5cb6e3..2f533f96ef01 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -684,7 +684,7 @@ NON_IDL_EVENT(compositionupdate, EventNameType_XUL, eCompositionEventClass) NON_IDL_EVENT(compositionend, - NS_COMPOSITION_END, + eCompositionEnd, EventNameType_XUL, eCompositionEventClass) NON_IDL_EVENT(command, diff --git a/dom/events/IMEStateManager.cpp b/dom/events/IMEStateManager.cpp index 361eba46f53d..31134f998bd0 100644 --- a/dom/events/IMEStateManager.cpp +++ b/dom/events/IMEStateManager.cpp @@ -139,8 +139,8 @@ GetEventMessageName(EventMessage aMessage) switch (aMessage) { case eCompositionStart: return "eCompositionStart"; - case NS_COMPOSITION_END: - return "NS_COMPOSITION_END"; + case eCompositionEnd: + return "eCompositionEnd"; case NS_COMPOSITION_UPDATE: return "NS_COMPOSITION_UPDATE"; case NS_COMPOSITION_CHANGE: diff --git a/dom/events/TextComposition.cpp b/dom/events/TextComposition.cpp index cedaf6ba10d1..5d611bf39808 100644 --- a/dom/events/TextComposition.cpp +++ b/dom/events/TextComposition.cpp @@ -284,7 +284,7 @@ TextComposition::DispatchCompositionEvent( if (!aIsSynthesized && (mIsRequestingCommit || mIsRequestingCancel)) { nsString* committingData = nullptr; switch (aCompositionEvent->mMessage) { - case NS_COMPOSITION_END: + case eCompositionEnd: case NS_COMPOSITION_CHANGE: case eCompositionCommitAsIs: case NS_COMPOSITION_COMMIT: @@ -366,8 +366,8 @@ TextComposition::DispatchCompositionEvent( if (aCompositionEvent->CausesDOMCompositionEndEvent()) { // Dispatch a compositionend event if it's necessary. - if (aCompositionEvent->mMessage != NS_COMPOSITION_END) { - CloneAndDispatchAs(aCompositionEvent, NS_COMPOSITION_END); + if (aCompositionEvent->mMessage != eCompositionEnd) { + CloneAndDispatchAs(aCompositionEvent, eCompositionEnd); } MOZ_ASSERT(!mIsComposing, "Why is the editor still composing?"); MOZ_ASSERT(!HasEditor(), "Why does the editor still keep to hold this?"); diff --git a/editor/libeditor/nsEditor.cpp b/editor/libeditor/nsEditor.cpp index 920b3a63d0db..e414af986580 100644 --- a/editor/libeditor/nsEditor.cpp +++ b/editor/libeditor/nsEditor.cpp @@ -5160,7 +5160,7 @@ nsEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent) // are initialized with eUnidentifiedEvent. Let's ignore such event. return false; case eCompositionStart: - case NS_COMPOSITION_END: + case eCompositionEnd: case NS_COMPOSITION_UPDATE: case NS_COMPOSITION_CHANGE: case eCompositionCommitAsIs: diff --git a/editor/libeditor/nsEditorEventListener.cpp b/editor/libeditor/nsEditorEventListener.cpp index 2f384fb31bb9..00664cee8c68 100644 --- a/editor/libeditor/nsEditorEventListener.cpp +++ b/editor/libeditor/nsEditorEventListener.cpp @@ -466,7 +466,7 @@ nsEditorEventListener::HandleEvent(nsIDOMEvent* aEvent) case eCompositionStart: return HandleStartComposition(aEvent); // compositionend - case NS_COMPOSITION_END: + case eCompositionEnd: HandleEndComposition(aEvent); return NS_OK; default: diff --git a/widget/ContentCache.cpp b/widget/ContentCache.cpp index 51266827d730..e44657ba5367 100644 --- a/widget/ContentCache.cpp +++ b/widget/ContentCache.cpp @@ -29,8 +29,8 @@ GetEventMessageName(EventMessage aMessage) switch (aMessage) { case eCompositionStart: return "eCompositionStart"; - case NS_COMPOSITION_END: - return "NS_COMPOSITION_END"; + case eCompositionEnd: + return "eCompositionEnd"; case NS_COMPOSITION_UPDATE: return "NS_COMPOSITION_UPDATE"; case NS_COMPOSITION_CHANGE: diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 0dbf49ea101e..7d91e3efc02e 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -147,10 +147,10 @@ NS_EVENT_MESSAGE(eUnidentifiedEvent, 2000) // composition events NS_EVENT_MESSAGE(eCompositionEventFirst, 2200) NS_EVENT_MESSAGE(eCompositionStart, eCompositionEventFirst) -// NS_COMPOSITION_END is the message for DOM compositionend event. +// eCompositionEnd is the message for DOM compositionend event. // This event should NOT be dispatched from widget if NS_COMPOSITION_COMMIT // is available. -NS_EVENT_MESSAGE(NS_COMPOSITION_END, eCompositionEventFirst + 1) +NS_EVENT_MESSAGE(eCompositionEnd, eCompositionEventFirst + 1) // NS_COMPOSITION_UPDATE is the message for DOM compositionupdate event. // This event should NOT be dispatched from widget since it will be dispatched // by mozilla::TextComposition automatically if NS_COMPOSITION_CHANGE event @@ -165,13 +165,13 @@ NS_EVENT_MESSAGE(NS_COMPOSITION_CHANGE, eCompositionEventFirst + 3) // composition string. TextComposition will commit composition with the // last data. TextComposition will dispatch this event to the DOM tree as // NS_COMPOSITION_CHANGE without clause information. After that, -// NS_COMPOSITION_END will be dispatched automatically. +// eCompositionEnd will be dispatched automatically. // Its mData and mRanges should be empty and nullptr. NS_EVENT_MESSAGE(eCompositionCommitAsIs, eCompositionEventFirst + 4) // NS_COMPOSITION_COMMIT is the message for representing a commit of // composition string with its mData value. TextComposition will dispatch this // event to the DOM tree as NS_COMPOSITION_CHANGE without clause information. -// After that, NS_COMPOSITION_END will be dispatched automatically. +// After that, eCompositionEnd will be dispatched automatically. // Its mRanges should be nullptr. NS_EVENT_MESSAGE(NS_COMPOSITION_COMMIT, eCompositionEventFirst + 5) diff --git a/widget/TextEvents.h b/widget/TextEvents.h index 0cf7ef8600ed..a97720f52189 100644 --- a/widget/TextEvents.h +++ b/widget/TextEvents.h @@ -441,7 +441,7 @@ public: bool CausesDOMCompositionEndEvent() const { - return mMessage == NS_COMPOSITION_END || + return mMessage == eCompositionEnd || mMessage == NS_COMPOSITION_COMMIT || mMessage == eCompositionCommitAsIs; } diff --git a/widget/WidgetEventImpl.cpp b/widget/WidgetEventImpl.cpp index e157c1e5ccde..2c09069a89cb 100644 --- a/widget/WidgetEventImpl.cpp +++ b/widget/WidgetEventImpl.cpp @@ -137,7 +137,7 @@ WidgetEvent::HasIMEEventMessage() const { switch (mMessage) { case eCompositionStart: - case NS_COMPOSITION_END: + case eCompositionEnd: case NS_COMPOSITION_UPDATE: case NS_COMPOSITION_CHANGE: case eCompositionCommitAsIs: From 1e538fa11e84352af1698938e010f812760c9bed Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:27 +0900 Subject: [PATCH 030/131] Bug 895274 part.192 Rename NS_COMPOSITION_UPDATE to eCompositionUpdate r=smaug --- dom/events/EventNameList.h | 2 +- dom/events/IMEStateManager.cpp | 6 +++--- dom/events/TextComposition.cpp | 4 ++-- editor/libeditor/nsEditor.cpp | 2 +- widget/ContentCache.cpp | 4 ++-- widget/EventMessageList.h | 4 ++-- widget/WidgetEventImpl.cpp | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 2f533f96ef01..4f634367304b 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -680,7 +680,7 @@ NON_IDL_EVENT(compositionstart, EventNameType_XUL, eCompositionEventClass) NON_IDL_EVENT(compositionupdate, - NS_COMPOSITION_UPDATE, + eCompositionUpdate, EventNameType_XUL, eCompositionEventClass) NON_IDL_EVENT(compositionend, diff --git a/dom/events/IMEStateManager.cpp b/dom/events/IMEStateManager.cpp index 31134f998bd0..51842e702e6a 100644 --- a/dom/events/IMEStateManager.cpp +++ b/dom/events/IMEStateManager.cpp @@ -141,8 +141,8 @@ GetEventMessageName(EventMessage aMessage) return "eCompositionStart"; case eCompositionEnd: return "eCompositionEnd"; - case NS_COMPOSITION_UPDATE: - return "NS_COMPOSITION_UPDATE"; + case eCompositionUpdate: + return "eCompositionUpdate"; case NS_COMPOSITION_CHANGE: return "NS_COMPOSITION_CHANGE"; case eCompositionCommitAsIs: @@ -1147,7 +1147,7 @@ IMEStateManager::DispatchCompositionEvent( return; } - MOZ_ASSERT(aCompositionEvent->mMessage != NS_COMPOSITION_UPDATE, + MOZ_ASSERT(aCompositionEvent->mMessage != eCompositionUpdate, "compositionupdate event shouldn't be dispatched manually"); EnsureTextCompositionArray(); diff --git a/dom/events/TextComposition.cpp b/dom/events/TextComposition.cpp index 5d611bf39808..764aa9a101e3 100644 --- a/dom/events/TextComposition.cpp +++ b/dom/events/TextComposition.cpp @@ -93,7 +93,7 @@ TextComposition::MaybeDispatchCompositionUpdate( if (mLastData == aCompositionEvent->mData) { return true; } - CloneAndDispatchAs(aCompositionEvent, NS_COMPOSITION_UPDATE); + CloneAndDispatchAs(aCompositionEvent, eCompositionUpdate); return IsValidStateForComposition(aCompositionEvent->widget); } @@ -120,7 +120,7 @@ TextComposition::CloneAndDispatchAs( nsEventStatus dummyStatus = nsEventStatus_eConsumeNoDefault; nsEventStatus* status = aStatus ? aStatus : &dummyStatus; - if (aMessage == NS_COMPOSITION_UPDATE) { + if (aMessage == eCompositionUpdate) { mLastData = compositionEvent.mData; } EventDispatcher::Dispatch(mNode, mPresContext, diff --git a/editor/libeditor/nsEditor.cpp b/editor/libeditor/nsEditor.cpp index e414af986580..301b55a8e6dd 100644 --- a/editor/libeditor/nsEditor.cpp +++ b/editor/libeditor/nsEditor.cpp @@ -5161,7 +5161,7 @@ nsEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent) return false; case eCompositionStart: case eCompositionEnd: - case NS_COMPOSITION_UPDATE: + case eCompositionUpdate: case NS_COMPOSITION_CHANGE: case eCompositionCommitAsIs: // Don't allow composition events whose internal event are not diff --git a/widget/ContentCache.cpp b/widget/ContentCache.cpp index e44657ba5367..3e8d7b5ef1e3 100644 --- a/widget/ContentCache.cpp +++ b/widget/ContentCache.cpp @@ -31,8 +31,8 @@ GetEventMessageName(EventMessage aMessage) return "eCompositionStart"; case eCompositionEnd: return "eCompositionEnd"; - case NS_COMPOSITION_UPDATE: - return "NS_COMPOSITION_UPDATE"; + case eCompositionUpdate: + return "eCompositionUpdate"; case NS_COMPOSITION_CHANGE: return "NS_COMPOSITION_CHANGE"; case eCompositionCommitAsIs: diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 7d91e3efc02e..f38f98d02e33 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -151,11 +151,11 @@ NS_EVENT_MESSAGE(eCompositionStart, eCompositionEventFirst) // This event should NOT be dispatched from widget if NS_COMPOSITION_COMMIT // is available. NS_EVENT_MESSAGE(eCompositionEnd, eCompositionEventFirst + 1) -// NS_COMPOSITION_UPDATE is the message for DOM compositionupdate event. +// eCompositionUpdate is the message for DOM compositionupdate event. // This event should NOT be dispatched from widget since it will be dispatched // by mozilla::TextComposition automatically if NS_COMPOSITION_CHANGE event // will change composition string. -NS_EVENT_MESSAGE(NS_COMPOSITION_UPDATE, eCompositionEventFirst + 2) +NS_EVENT_MESSAGE(eCompositionUpdate, eCompositionEventFirst + 2) // NS_COMPOSITION_CHANGE is the message for representing a change of // composition string. This should be dispatched from widget even if // composition string isn't changed but the ranges are changed. This causes diff --git a/widget/WidgetEventImpl.cpp b/widget/WidgetEventImpl.cpp index 2c09069a89cb..273a3a1463dc 100644 --- a/widget/WidgetEventImpl.cpp +++ b/widget/WidgetEventImpl.cpp @@ -138,7 +138,7 @@ WidgetEvent::HasIMEEventMessage() const switch (mMessage) { case eCompositionStart: case eCompositionEnd: - case NS_COMPOSITION_UPDATE: + case eCompositionUpdate: case NS_COMPOSITION_CHANGE: case eCompositionCommitAsIs: case NS_COMPOSITION_COMMIT: From ed4dac1ca62e33637c4d887b9b8557fa54cf7c9b Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:27 +0900 Subject: [PATCH 031/131] Bug 895274 part.193 Rename NS_COMPOSITION_CHANGE to eCompositionChange r=smaug --- dom/events/EventNameList.h | 2 +- dom/events/IMEStateManager.cpp | 4 ++-- dom/events/TextComposition.cpp | 18 +++++++++--------- editor/libeditor/nsEditor.cpp | 4 ++-- editor/libeditor/nsEditorEventListener.cpp | 2 +- editor/libeditor/nsPlaintextEditor.cpp | 4 ++-- widget/ContentCache.cpp | 6 +++--- widget/EventMessageList.h | 10 +++++----- widget/TextEventDispatcher.cpp | 2 +- widget/TextEventDispatcher.h | 4 ++-- widget/TextEvents.h | 2 +- widget/WidgetEventImpl.cpp | 2 +- widget/android/nsWindow.cpp | 4 ++-- widget/cocoa/TextInputHandler.mm | 2 +- widget/gtk/IMContextWrapper.cpp | 2 +- widget/gtk/IMContextWrapper.h | 2 +- widget/gtk/nsWindow.cpp | 2 +- widget/tests/TestWinTSF.cpp | 2 +- widget/windows/IMMHandler.cpp | 2 +- widget/windows/IMMHandler.h | 2 +- widget/windows/TSFTextStore.cpp | 12 ++++++------ widget/windows/TSFTextStore.h | 2 +- 22 files changed, 46 insertions(+), 46 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 4f634367304b..59db861c7efe 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -672,7 +672,7 @@ NON_IDL_EVENT(speakerforcedchange, // This shouldn't be used by web/xul apps. "compositionupdate" should be // used instead. NON_IDL_EVENT(text, - NS_COMPOSITION_CHANGE, + eCompositionChange, EventNameType_XUL, eCompositionEventClass) NON_IDL_EVENT(compositionstart, diff --git a/dom/events/IMEStateManager.cpp b/dom/events/IMEStateManager.cpp index 51842e702e6a..07741835852e 100644 --- a/dom/events/IMEStateManager.cpp +++ b/dom/events/IMEStateManager.cpp @@ -143,8 +143,8 @@ GetEventMessageName(EventMessage aMessage) return "eCompositionEnd"; case eCompositionUpdate: return "eCompositionUpdate"; - case NS_COMPOSITION_CHANGE: - return "NS_COMPOSITION_CHANGE"; + case eCompositionChange: + return "eCompositionChange"; case eCompositionCommitAsIs: return "eCompositionCommitAsIs"; case NS_COMPOSITION_COMMIT: diff --git a/dom/events/TextComposition.cpp b/dom/events/TextComposition.cpp index 764aa9a101e3..35e114241374 100644 --- a/dom/events/TextComposition.cpp +++ b/dom/events/TextComposition.cpp @@ -285,7 +285,7 @@ TextComposition::DispatchCompositionEvent( nsString* committingData = nullptr; switch (aCompositionEvent->mMessage) { case eCompositionEnd: - case NS_COMPOSITION_CHANGE: + case eCompositionChange: case eCompositionCommitAsIs: case NS_COMPOSITION_COMMIT: committingData = &aCompositionEvent->mData; @@ -309,20 +309,20 @@ TextComposition::DispatchCompositionEvent( bool dispatchDOMTextEvent = aCompositionEvent->CausesDOMTextEvent(); // When mIsComposing is false but the committing string is different from - // the last data (E.g., previous NS_COMPOSITION_CHANGE event made the + // the last data (E.g., previous eCompositionChange event made the // composition string empty or didn't have clause information), we don't // need to dispatch redundant DOM text event. if (dispatchDOMTextEvent && - aCompositionEvent->mMessage != NS_COMPOSITION_CHANGE && + aCompositionEvent->mMessage != eCompositionChange && !mIsComposing && mLastData == aCompositionEvent->mData) { dispatchEvent = dispatchDOMTextEvent = false; } - // widget may dispatch redundant NS_COMPOSITION_CHANGE event + // widget may dispatch redundant eCompositionChange event // which modifies neither composition string, clauses nor caret // position. In such case, we shouldn't dispatch DOM events. if (dispatchDOMTextEvent && - aCompositionEvent->mMessage == NS_COMPOSITION_CHANGE && + aCompositionEvent->mMessage == eCompositionChange && mLastData == aCompositionEvent->mData && mRanges && aCompositionEvent->mRanges && mRanges->Equals(*aCompositionEvent->mRanges)) { @@ -337,13 +337,13 @@ TextComposition::DispatchCompositionEvent( if (dispatchEvent) { // If the composition event should cause a DOM text event, we should - // overwrite the event message as NS_COMPOSITION_CHANGE because due to + // overwrite the event message as eCompositionChange because due to // the limitation of mapping between event messages and DOM event types, // we cannot map multiple event messages to a DOM event type. if (dispatchDOMTextEvent && - aCompositionEvent->mMessage != NS_COMPOSITION_CHANGE) { + aCompositionEvent->mMessage != eCompositionChange) { aCompositionEvent->mFlags = - CloneAndDispatchAs(aCompositionEvent, NS_COMPOSITION_CHANGE, + CloneAndDispatchAs(aCompositionEvent, eCompositionChange, aStatus, aCallBack); } else { EventDispatcher::Dispatch(mNode, mPresContext, @@ -625,7 +625,7 @@ TextComposition::CompositionEventDispatcher::Run() mIsSynthesizedEvent); break; } - case NS_COMPOSITION_CHANGE: + case eCompositionChange: case eCompositionCommitAsIs: case NS_COMPOSITION_COMMIT: { WidgetCompositionEvent compEvent(true, mEventMessage, widget); diff --git a/editor/libeditor/nsEditor.cpp b/editor/libeditor/nsEditor.cpp index 301b55a8e6dd..e1a04303e29b 100644 --- a/editor/libeditor/nsEditor.cpp +++ b/editor/libeditor/nsEditor.cpp @@ -254,7 +254,7 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIContent *aRoot, // recreated with same content. Therefore, we need to forget mIMETextNode, // but we need to keep storing mIMETextOffset and mIMETextLength becuase // they are necessary to restore IME selection and replacing composing string - // when this receives NS_COMPOSITION_CHANGE event next time. + // when this receives eCompositionChange event next time. if (mIMETextNode && !mIMETextNode->IsInComposedDoc()) { mIMETextNode = nullptr; } @@ -5162,7 +5162,7 @@ nsEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent) case eCompositionStart: case eCompositionEnd: case eCompositionUpdate: - case NS_COMPOSITION_CHANGE: + case eCompositionChange: case eCompositionCommitAsIs: // Don't allow composition events whose internal event are not // WidgetCompositionEvent. diff --git a/editor/libeditor/nsEditorEventListener.cpp b/editor/libeditor/nsEditorEventListener.cpp index 00664cee8c68..e3010bff30d4 100644 --- a/editor/libeditor/nsEditorEventListener.cpp +++ b/editor/libeditor/nsEditorEventListener.cpp @@ -460,7 +460,7 @@ nsEditorEventListener::HandleEvent(nsIDOMEvent* aEvent) case eBlur: return Blur(aEvent); // text - case NS_COMPOSITION_CHANGE: + case eCompositionChange: return HandleText(aEvent); // compositionstart case eCompositionStart: diff --git a/editor/libeditor/nsPlaintextEditor.cpp b/editor/libeditor/nsPlaintextEditor.cpp index 45a7b35bc763..6cf6f0f70012 100644 --- a/editor/libeditor/nsPlaintextEditor.cpp +++ b/editor/libeditor/nsPlaintextEditor.cpp @@ -845,8 +845,8 @@ nsPlaintextEditor::UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent) WidgetCompositionEvent* compositionChangeEvent = aDOMTextEvent->GetInternalNSEvent()->AsCompositionEvent(); NS_ENSURE_TRUE(compositionChangeEvent, NS_ERROR_INVALID_ARG); - MOZ_ASSERT(compositionChangeEvent->mMessage == NS_COMPOSITION_CHANGE, - "The internal event should be NS_COMPOSITION_CHANGE"); + MOZ_ASSERT(compositionChangeEvent->mMessage == eCompositionChange, + "The internal event should be eCompositionChange"); EnsureComposition(compositionChangeEvent); diff --git a/widget/ContentCache.cpp b/widget/ContentCache.cpp index 3e8d7b5ef1e3..8923c6e3c7a4 100644 --- a/widget/ContentCache.cpp +++ b/widget/ContentCache.cpp @@ -33,8 +33,8 @@ GetEventMessageName(EventMessage aMessage) return "eCompositionEnd"; case eCompositionUpdate: return "eCompositionUpdate"; - case NS_COMPOSITION_CHANGE: - return "NS_COMPOSITION_CHANGE"; + case eCompositionChange: + return "eCompositionChange"; case eCompositionCommitAsIs: return "eCompositionCommitAsIs"; case NS_COMPOSITION_COMMIT: @@ -875,7 +875,7 @@ ContentCacheInParent::OnCompositionEvent(const WidgetCompositionEvent& aEvent) // TextComposition must handle following events correctly! // During REQUEST_TO_COMMIT_COMPOSITION or REQUEST_TO_CANCEL_COMPOSITION, - // widget usually sends a NS_COMPOSITION_CHANGE event to finalize or + // widget usually sends a eCompositionChange event to finalize or // clear the composition, respectively. // Because the event will not reach content in time, we intercept it // here and pass the text as the DidRequestToCommitOrCancelComposition() diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index f38f98d02e33..4db5b29a3122 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -153,24 +153,24 @@ NS_EVENT_MESSAGE(eCompositionStart, eCompositionEventFirst) NS_EVENT_MESSAGE(eCompositionEnd, eCompositionEventFirst + 1) // eCompositionUpdate is the message for DOM compositionupdate event. // This event should NOT be dispatched from widget since it will be dispatched -// by mozilla::TextComposition automatically if NS_COMPOSITION_CHANGE event +// by mozilla::TextComposition automatically if eCompositionChange event // will change composition string. NS_EVENT_MESSAGE(eCompositionUpdate, eCompositionEventFirst + 2) -// NS_COMPOSITION_CHANGE is the message for representing a change of +// eCompositionChange is the message for representing a change of // composition string. This should be dispatched from widget even if // composition string isn't changed but the ranges are changed. This causes // a DOM "text" event which is a non-standard DOM event. -NS_EVENT_MESSAGE(NS_COMPOSITION_CHANGE, eCompositionEventFirst + 3) +NS_EVENT_MESSAGE(eCompositionChange, eCompositionEventFirst + 3) // eCompositionCommitAsIs is the message for representing a commit of // composition string. TextComposition will commit composition with the // last data. TextComposition will dispatch this event to the DOM tree as -// NS_COMPOSITION_CHANGE without clause information. After that, +// eCompositionChange without clause information. After that, // eCompositionEnd will be dispatched automatically. // Its mData and mRanges should be empty and nullptr. NS_EVENT_MESSAGE(eCompositionCommitAsIs, eCompositionEventFirst + 4) // NS_COMPOSITION_COMMIT is the message for representing a commit of // composition string with its mData value. TextComposition will dispatch this -// event to the DOM tree as NS_COMPOSITION_CHANGE without clause information. +// event to the DOM tree as eCompositionChange without clause information. // After that, eCompositionEnd will be dispatched automatically. // Its mRanges should be nullptr. NS_EVENT_MESSAGE(NS_COMPOSITION_COMMIT, eCompositionEventFirst + 5) diff --git a/widget/TextEventDispatcher.cpp b/widget/TextEventDispatcher.cpp index 6c657ebca050..8d29836b6438 100644 --- a/widget/TextEventDispatcher.cpp +++ b/widget/TextEventDispatcher.cpp @@ -541,7 +541,7 @@ TextEventDispatcher::PendingComposition::Flush(TextEventDispatcher* aDispatcher, nsRefPtr kungFuDeathGrip(aDispatcher); nsCOMPtr widget(aDispatcher->mWidget); - WidgetCompositionEvent compChangeEvent(true, NS_COMPOSITION_CHANGE, widget); + WidgetCompositionEvent compChangeEvent(true, eCompositionChange, widget); aDispatcher->InitEvent(compChangeEvent); compChangeEvent.mData = mString; if (mClauses) { diff --git a/widget/TextEventDispatcher.h b/widget/TextEventDispatcher.h index 0d64468a8b75..08bf15bd14ca 100644 --- a/widget/TextEventDispatcher.h +++ b/widget/TextEventDispatcher.h @@ -112,7 +112,7 @@ public: /** * SetPendingCompositionString() sets new composition string which will be - * dispatched with NS_COMPOSITION_CHANGE event by calling Flush(). + * dispatched with eCompositionChange event by calling Flush(). * * @param aString New composition string. */ @@ -255,7 +255,7 @@ private: nsWeakPtr mListener; // mPendingComposition stores new composition string temporarily. - // These values will be used for dispatching NS_COMPOSITION_CHANGE event + // These values will be used for dispatching eCompositionChange event // in Flush(). When Flush() is called, the members will be cleared // automatically. class PendingComposition diff --git a/widget/TextEvents.h b/widget/TextEvents.h index a97720f52189..15b0c9999a6b 100644 --- a/widget/TextEvents.h +++ b/widget/TextEvents.h @@ -434,7 +434,7 @@ public: bool CausesDOMTextEvent() const { - return mMessage == NS_COMPOSITION_CHANGE || + return mMessage == eCompositionChange || mMessage == NS_COMPOSITION_COMMIT || mMessage == eCompositionCommitAsIs; } diff --git a/widget/WidgetEventImpl.cpp b/widget/WidgetEventImpl.cpp index 273a3a1463dc..fe5de838e20f 100644 --- a/widget/WidgetEventImpl.cpp +++ b/widget/WidgetEventImpl.cpp @@ -139,7 +139,7 @@ WidgetEvent::HasIMEEventMessage() const case eCompositionStart: case eCompositionEnd: case eCompositionUpdate: - case NS_COMPOSITION_CHANGE: + case eCompositionChange: case eCompositionCommitAsIs: case NS_COMPOSITION_COMMIT: return true; diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index b6e3149aef5d..de9e1301b1dc 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -1844,7 +1844,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) } { - WidgetCompositionEvent event(true, NS_COMPOSITION_CHANGE, this); + WidgetCompositionEvent event(true, eCompositionChange, this); InitEvent(event, nullptr); event.mData = ae->Characters(); @@ -1946,7 +1946,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) const auto composition(GetIMEComposition()); MOZ_ASSERT(!composition || !composition->IsEditorHandlingEvent()); - WidgetCompositionEvent event(true, NS_COMPOSITION_CHANGE, this); + WidgetCompositionEvent event(true, eCompositionChange, this); InitEvent(event, nullptr); event.mRanges = new TextRangeArray(); diff --git a/widget/cocoa/TextInputHandler.mm b/widget/cocoa/TextInputHandler.mm index 24641f6ab5ab..8ea5821b7387 100644 --- a/widget/cocoa/TextInputHandler.mm +++ b/widget/cocoa/TextInputHandler.mm @@ -2714,7 +2714,7 @@ IMEInputHandler::DispatchCompositionChangeEvent(const nsString& aText, nsRefPtr kungFuDeathGrip(this); - WidgetCompositionEvent compositionChangeEvent(true, NS_COMPOSITION_CHANGE, + WidgetCompositionEvent compositionChangeEvent(true, eCompositionChange, mWidget); compositionChangeEvent.time = PR_IntervalNow(); compositionChangeEvent.mData = aText; diff --git a/widget/gtk/IMContextWrapper.cpp b/widget/gtk/IMContextWrapper.cpp index 6cda8e667eb0..69c1f7302485 100644 --- a/widget/gtk/IMContextWrapper.cpp +++ b/widget/gtk/IMContextWrapper.cpp @@ -1364,7 +1364,7 @@ IMContextWrapper::DispatchCompositionChangeEvent( } } - WidgetCompositionEvent compositionChangeEvent(true, NS_COMPOSITION_CHANGE, + WidgetCompositionEvent compositionChangeEvent(true, eCompositionChange, mLastFocusedWindow); InitEvent(compositionChangeEvent); diff --git a/widget/gtk/IMContextWrapper.h b/widget/gtk/IMContextWrapper.h index f1933b39d8ca..aa3a745d2e64 100644 --- a/widget/gtk/IMContextWrapper.h +++ b/widget/gtk/IMContextWrapper.h @@ -257,7 +257,7 @@ protected: // trying to delete the surrounding text. bool mIsDeletingSurrounding; // mLayoutChanged is true after OnLayoutChange() is called. This is reset - // when NS_COMPOSITION_CHANGE is being dispatched. + // when eCompositionChange is being dispatched. bool mLayoutChanged; // mSetCursorPositionOnKeyEvent true when caret rect or position is updated // with no composition. If true, we update candidate window position diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 168c6d0271c8..b438a7334d0a 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -3079,7 +3079,7 @@ nsWindow::OnKeyPressEvent(GdkEventKey *aEvent) } else { WidgetCompositionEvent compositionChangeEvent( - true, NS_COMPOSITION_CHANGE, this); + true, eCompositionChange, this); char16_t textString[3]; textString[0] = H_SURROGATE(event.charCode); textString[1] = L_SURROGATE(event.charCode); diff --git a/widget/tests/TestWinTSF.cpp b/widget/tests/TestWinTSF.cpp index 0bb71c55d910..70d44bb13e9f 100644 --- a/widget/tests/TestWinTSF.cpp +++ b/widget/tests/TestWinTSF.cpp @@ -1965,7 +1965,7 @@ TestApp::TestText(void) * Bug in eQueryTextContent handler * nsTextStore::SetText not calling SetSelection or InsertTextAtSelection * Bug in SetSelection or InsertTextAtSelection - * eSetSelection bug or NS_COMPOSITION_* / NS_COMPOSITION_CHANGE bug + * eSetSelection bug or eComposition* / eCompositionChange bug */ if (!mMgr->GetFocusedStore()) { diff --git a/widget/windows/IMMHandler.cpp b/widget/windows/IMMHandler.cpp index abe3bf1d98bf..5d92c9df5708 100644 --- a/widget/windows/IMMHandler.cpp +++ b/widget/windows/IMMHandler.cpp @@ -1897,7 +1897,7 @@ IMMHandler::DispatchCompositionChangeEvent(nsWindow* aWindow, nsIntPoint point(0, 0); - WidgetCompositionEvent event(true, NS_COMPOSITION_CHANGE, aWindow); + WidgetCompositionEvent event(true, eCompositionChange, aWindow); aWindow->InitEvent(event, &point); diff --git a/widget/windows/IMMHandler.h b/widget/windows/IMMHandler.h index ba6a1c3f403f..a37a6ebdd72d 100644 --- a/widget/windows/IMMHandler.h +++ b/widget/windows/IMMHandler.h @@ -353,7 +353,7 @@ protected: bool GetTargetClauseRange(uint32_t *aOffset, uint32_t *aLength = nullptr); /** - * DispatchCompositionChangeEvent() dispatches NS_COMPOSITION_CHANGE event + * DispatchCompositionChangeEvent() dispatches eCompositionChange event * with clause information (it'll be retrieved by CreateTextRangeArray()). * I.e., this should be called only during composing. If a composition is * being committed, only HandleCompositionEnd() should be called. diff --git a/widget/windows/TSFTextStore.cpp b/widget/windows/TSFTextStore.cpp index f39e99dba1e9..d002f3b7661a 100644 --- a/widget/windows/TSFTextStore.cpp +++ b/widget/windows/TSFTextStore.cpp @@ -1763,7 +1763,7 @@ TSFTextStore::FlushPendingActions() MOZ_LOG(sTextStoreLog, LogLevel::Debug, ("TSF: 0x%p TSFTextStore::FlushPendingActions(), " "dispatching compositionchange event...", this)); - WidgetCompositionEvent compositionChange(true, NS_COMPOSITION_CHANGE, + WidgetCompositionEvent compositionChange(true, eCompositionChange, mWidget); mWidget->InitEvent(compositionChange); compositionChange.mData = action.mData; @@ -1775,7 +1775,7 @@ TSFTextStore::FlushPendingActions() action.mRanges->AppendElement(wholeRange); } compositionChange.mRanges = action.mRanges; - // When the NS_COMPOSITION_CHANGE causes a DOM text event, + // When the eCompositionChange causes a DOM text event, // the IME will be notified of NOTIFY_IME_OF_COMPOSITION_UPDATE. In // such case, we should not clear the locked content until we notify // the IME of the composition update. @@ -2476,7 +2476,7 @@ TSFTextStore::RecordCompositionUpdateAction() // the attribute, we have to find out all the ranges that have distinct // attribute values. Then we query for what the value represents through // the display attribute manager and translate that to TextRange to be - // sent in NS_COMPOSITION_CHANGE + // sent in eCompositionChange nsRefPtr attrPropetry; HRESULT hr = mContext->GetProperty(GUID_PROP_ATTRIBUTE, @@ -2525,7 +2525,7 @@ TSFTextStore::RecordCompositionUpdateAction() TextRange newRange; // No matter if we have display attribute info or not, - // we always pass in at least one range to NS_COMPOSITION_CHANGE + // we always pass in at least one range to eCompositionChange newRange.mStartOffset = 0; newRange.mEndOffset = action->mData.Length(); newRange.mRangeType = NS_TEXTRANGE_RAWINPUT; @@ -5435,8 +5435,8 @@ TSFTextStore::Content::ReplaceTextWith(LONG aStart, if (mComposition.IsComposing()) { // Emulate text insertion during compositions, because during a // composition, editor expects the whole composition string to - // be sent in NS_COMPOSITION_CHANGE, not just the inserted part. - // The actual NS_COMPOSITION_CHANGE will be sent in SetSelection + // be sent in eCompositionChange, not just the inserted part. + // The actual eCompositionChange will be sent in SetSelection // or OnUpdateComposition. MOZ_ASSERT(aStart >= mComposition.mStart); MOZ_ASSERT(aStart + aLength <= mComposition.EndOffset()); diff --git a/widget/windows/TSFTextStore.h b/widget/windows/TSFTextStore.h index 05f7e1ee33a5..0912b88e05e5 100644 --- a/widget/windows/TSFTextStore.h +++ b/widget/windows/TSFTextStore.h @@ -335,7 +335,7 @@ protected: // Current copy of the active composition string. Only mString is // changed during a InsertTextAtSelection call if we have a composition. // mString acts as a buffer until OnUpdateComposition is called - // and mString is flushed to editor through NS_COMPOSITION_CHANGE. + // and mString is flushed to editor through eCompositionChange. // This way all changes are updated in batches to avoid // inconsistencies/artifacts. nsString mString; From 888b2103ea5550c2911506dcab67843435529c04 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:27 +0900 Subject: [PATCH 032/131] Bug 895274 part.194 Rename NS_COMPOSITION_COMMIT to eCompositionCommit r=smaug --- dom/events/IMEStateManager.cpp | 4 ++-- dom/events/TextComposition.cpp | 10 +++++----- widget/ContentCache.cpp | 4 ++-- widget/EventMessageList.h | 6 +++--- widget/PuppetWidget.cpp | 3 +-- widget/TextEventDispatcher.cpp | 4 ++-- widget/TextEvents.h | 6 +++--- widget/WidgetEventImpl.cpp | 2 +- widget/android/nsWindow.cpp | 2 +- widget/cocoa/TextInputHandler.mm | 2 +- widget/gtk/IMContextWrapper.cpp | 4 ++-- widget/windows/IMMHandler.cpp | 2 +- widget/windows/TSFTextStore.cpp | 4 ++-- 13 files changed, 26 insertions(+), 27 deletions(-) diff --git a/dom/events/IMEStateManager.cpp b/dom/events/IMEStateManager.cpp index 07741835852e..1a116851df2f 100644 --- a/dom/events/IMEStateManager.cpp +++ b/dom/events/IMEStateManager.cpp @@ -147,8 +147,8 @@ GetEventMessageName(EventMessage aMessage) return "eCompositionChange"; case eCompositionCommitAsIs: return "eCompositionCommitAsIs"; - case NS_COMPOSITION_COMMIT: - return "NS_COMPOSITION_COMMIT"; + case eCompositionCommit: + return "eCompositionCommit"; case eSetSelection: return "eSetSelection"; default: diff --git a/dom/events/TextComposition.cpp b/dom/events/TextComposition.cpp index 35e114241374..b8c3d8d757c1 100644 --- a/dom/events/TextComposition.cpp +++ b/dom/events/TextComposition.cpp @@ -248,9 +248,9 @@ TextComposition::DispatchCompositionEvent( } else { aCompositionEvent->mData = mLastData; } - } else if (aCompositionEvent->mMessage == NS_COMPOSITION_COMMIT) { + } else if (aCompositionEvent->mMessage == eCompositionCommit) { NS_ASSERTION(!aCompositionEvent->mRanges, - "mRanges of NS_COMPOSITION_COMMIT should be null"); + "mRanges of eCompositionCommit should be null"); aCompositionEvent->mRanges = nullptr; } @@ -287,7 +287,7 @@ TextComposition::DispatchCompositionEvent( case eCompositionEnd: case eCompositionChange: case eCompositionCommitAsIs: - case NS_COMPOSITION_COMMIT: + case eCompositionCommit: committingData = &aCompositionEvent->mData; break; default: @@ -493,7 +493,7 @@ TextComposition::RequestToCommit(nsIWidget* aWidget, bool aDiscard) DispatchCompositionEventRunnable(eCompositionCommitAsIs, EmptyString(), true); } else { - DispatchCompositionEventRunnable(NS_COMPOSITION_COMMIT, data, true); + DispatchCompositionEventRunnable(eCompositionCommit, data, true); } return NS_OK; } @@ -627,7 +627,7 @@ TextComposition::CompositionEventDispatcher::Run() } case eCompositionChange: case eCompositionCommitAsIs: - case NS_COMPOSITION_COMMIT: { + case eCompositionCommit: { WidgetCompositionEvent compEvent(true, mEventMessage, widget); if (mEventMessage != eCompositionCommitAsIs) { compEvent.mData = mData; diff --git a/widget/ContentCache.cpp b/widget/ContentCache.cpp index 8923c6e3c7a4..4b67b35ec428 100644 --- a/widget/ContentCache.cpp +++ b/widget/ContentCache.cpp @@ -37,8 +37,8 @@ GetEventMessageName(EventMessage aMessage) return "eCompositionChange"; case eCompositionCommitAsIs: return "eCompositionCommitAsIs"; - case NS_COMPOSITION_COMMIT: - return "NS_COMPOSITION_COMMIT"; + case eCompositionCommit: + return "eCompositionCommit"; case eSetSelection: return "eSetSelection"; default: diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 4db5b29a3122..35945b5510c9 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -148,7 +148,7 @@ NS_EVENT_MESSAGE(eUnidentifiedEvent, 2000) NS_EVENT_MESSAGE(eCompositionEventFirst, 2200) NS_EVENT_MESSAGE(eCompositionStart, eCompositionEventFirst) // eCompositionEnd is the message for DOM compositionend event. -// This event should NOT be dispatched from widget if NS_COMPOSITION_COMMIT +// This event should NOT be dispatched from widget if eCompositionCommit // is available. NS_EVENT_MESSAGE(eCompositionEnd, eCompositionEventFirst + 1) // eCompositionUpdate is the message for DOM compositionupdate event. @@ -168,12 +168,12 @@ NS_EVENT_MESSAGE(eCompositionChange, eCompositionEventFirst + 3) // eCompositionEnd will be dispatched automatically. // Its mData and mRanges should be empty and nullptr. NS_EVENT_MESSAGE(eCompositionCommitAsIs, eCompositionEventFirst + 4) -// NS_COMPOSITION_COMMIT is the message for representing a commit of +// eCompositionCommit is the message for representing a commit of // composition string with its mData value. TextComposition will dispatch this // event to the DOM tree as eCompositionChange without clause information. // After that, eCompositionEnd will be dispatched automatically. // Its mRanges should be nullptr. -NS_EVENT_MESSAGE(NS_COMPOSITION_COMMIT, eCompositionEventFirst + 5) +NS_EVENT_MESSAGE(eCompositionCommit, eCompositionEventFirst + 5) // Following events are defined for deprecated DOM events which are using // InternalUIEvent class. diff --git a/widget/PuppetWidget.cpp b/widget/PuppetWidget.cpp index 8b009139e03f..3236b2a74a6a 100644 --- a/widget/PuppetWidget.cpp +++ b/widget/PuppetWidget.cpp @@ -575,8 +575,7 @@ PuppetWidget::IMEEndComposition(bool aCancel) nsEventStatus status; bool noCompositionEvent = true; - WidgetCompositionEvent compositionCommitEvent(true, NS_COMPOSITION_COMMIT, - this); + WidgetCompositionEvent compositionCommitEvent(true, eCompositionCommit, this); InitEvent(compositionCommitEvent, nullptr); // SendEndIMEComposition is always called since ResetInputState // should always be called even if we aren't composing something. diff --git a/widget/TextEventDispatcher.cpp b/widget/TextEventDispatcher.cpp index 8d29836b6438..adc450cfdd98 100644 --- a/widget/TextEventDispatcher.cpp +++ b/widget/TextEventDispatcher.cpp @@ -268,11 +268,11 @@ TextEventDispatcher::CommitComposition(nsEventStatus& aStatus, // End current composition and make this free for other IMEs. mIsComposing = false; - EventMessage message = aCommitString ? NS_COMPOSITION_COMMIT : + EventMessage message = aCommitString ? eCompositionCommit : eCompositionCommitAsIs; WidgetCompositionEvent compositionCommitEvent(true, message, widget); InitEvent(compositionCommitEvent); - if (message == NS_COMPOSITION_COMMIT) { + if (message == eCompositionCommit) { compositionCommitEvent.mData = *aCommitString; } rv = DispatchEvent(widget, compositionCommitEvent, aStatus); diff --git a/widget/TextEvents.h b/widget/TextEvents.h index 15b0c9999a6b..44dab1b62943 100644 --- a/widget/TextEvents.h +++ b/widget/TextEvents.h @@ -435,20 +435,20 @@ public: bool CausesDOMTextEvent() const { return mMessage == eCompositionChange || - mMessage == NS_COMPOSITION_COMMIT || + mMessage == eCompositionCommit || mMessage == eCompositionCommitAsIs; } bool CausesDOMCompositionEndEvent() const { return mMessage == eCompositionEnd || - mMessage == NS_COMPOSITION_COMMIT || + mMessage == eCompositionCommit || mMessage == eCompositionCommitAsIs; } bool IsFollowedByCompositionEnd() const { - return mOriginalMessage == NS_COMPOSITION_COMMIT || + return mOriginalMessage == eCompositionCommit || mOriginalMessage == eCompositionCommitAsIs; } }; diff --git a/widget/WidgetEventImpl.cpp b/widget/WidgetEventImpl.cpp index fe5de838e20f..381982250f50 100644 --- a/widget/WidgetEventImpl.cpp +++ b/widget/WidgetEventImpl.cpp @@ -141,7 +141,7 @@ WidgetEvent::HasIMEEventMessage() const case eCompositionUpdate: case eCompositionChange: case eCompositionCommitAsIs: - case NS_COMPOSITION_COMMIT: + case eCompositionCommit: return true; default: return false; diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index de9e1301b1dc..fa0957be5bc7 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -2053,7 +2053,7 @@ nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification) nsRefPtr kungFuDeathGrip(this); WidgetCompositionEvent compositionCommitEvent( - true, NS_COMPOSITION_COMMIT, this); + true, eCompositionCommit, this); InitEvent(compositionCommitEvent, nullptr); // Dispatch it with empty mData value for canceling the // composition diff --git a/widget/cocoa/TextInputHandler.mm b/widget/cocoa/TextInputHandler.mm index 8ea5821b7387..839699dd5cad 100644 --- a/widget/cocoa/TextInputHandler.mm +++ b/widget/cocoa/TextInputHandler.mm @@ -2740,7 +2740,7 @@ IMEInputHandler::DispatchCompositionCommitEvent(const nsAString* aCommitString) nsRefPtr kungFuDeathGrip(this); EventMessage message = - aCommitString ? NS_COMPOSITION_COMMIT : eCompositionCommitAsIs; + aCommitString ? eCompositionCommit : eCompositionCommitAsIs; WidgetCompositionEvent compositionCommitEvent(true, message, mWidget); compositionCommitEvent.time = PR_IntervalNow(); if (aCommitString) { diff --git a/widget/gtk/IMContextWrapper.cpp b/widget/gtk/IMContextWrapper.cpp index 69c1f7302485..cf0d68b03540 100644 --- a/widget/gtk/IMContextWrapper.cpp +++ b/widget/gtk/IMContextWrapper.cpp @@ -1439,7 +1439,7 @@ IMContextWrapper::DispatchCompositionCommitEvent( nsRefPtr lastFocusedWindow(mLastFocusedWindow); - EventMessage message = aCommitString ? NS_COMPOSITION_COMMIT : + EventMessage message = aCommitString ? eCompositionCommit : eCompositionCommitAsIs; mCompositionState = eCompositionState_NotComposing; mCompositionStart = UINT32_MAX; @@ -1449,7 +1449,7 @@ IMContextWrapper::DispatchCompositionCommitEvent( WidgetCompositionEvent compositionCommitEvent(true, message, mLastFocusedWindow); InitEvent(compositionCommitEvent); - if (message == NS_COMPOSITION_COMMIT) { + if (message == eCompositionCommit) { compositionCommitEvent.mData = *aCommitString; } diff --git a/widget/windows/IMMHandler.cpp b/widget/windows/IMMHandler.cpp index 5d92c9df5708..35ac6f723987 100644 --- a/widget/windows/IMMHandler.cpp +++ b/widget/windows/IMMHandler.cpp @@ -1525,7 +1525,7 @@ IMMHandler::HandleEndComposition(nsWindow* aWindow, } EventMessage message = - aCommitString ? NS_COMPOSITION_COMMIT : eCompositionCommitAsIs; + aCommitString ? eCompositionCommit : eCompositionCommitAsIs; WidgetCompositionEvent compositionCommitEvent(true, message, aWindow); nsIntPoint point(0, 0); aWindow->InitEvent(compositionCommitEvent, &point); diff --git a/widget/windows/TSFTextStore.cpp b/widget/windows/TSFTextStore.cpp index d002f3b7661a..6e34a456634a 100644 --- a/widget/windows/TSFTextStore.cpp +++ b/widget/windows/TSFTextStore.cpp @@ -1798,11 +1798,11 @@ TSFTextStore::FlushPendingActions() MOZ_LOG(sTextStoreLog, LogLevel::Debug, ("TSF: 0x%p TSFTextStore::FlushPendingActions(), " "dispatching compositioncommit event...", this)); - WidgetCompositionEvent compositionCommit(true, NS_COMPOSITION_COMMIT, + WidgetCompositionEvent compositionCommit(true, eCompositionCommit, mWidget); mWidget->InitEvent(compositionCommit); compositionCommit.mData = action.mData; - // When the NS_COMPOSITION_COMMIT causes a DOM text event, + // When the eCompositionCommit causes a DOM text event, // the IME will be notified of NOTIFY_IME_OF_COMPOSITION_UPDATE. In // such case, we should not clear the locked content until we notify // the IME of the composition update. From 8cfcb56a6bc5f6a9fee16794e3d795e901c8fcf9 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:27 +0900 Subject: [PATCH 033/131] Bug 895274 part.195 Rename NS_SMIL_TIME_EVENT_START to eSMILEventFist r=smaug --- widget/EventMessageList.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 35945b5510c9..d79a81a71c95 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -331,10 +331,10 @@ NS_EVENT_MESSAGE(eAnimationStart, eAnimationEventFirst) NS_EVENT_MESSAGE(eAnimationEnd, eAnimationEventFirst + 1) NS_EVENT_MESSAGE(eAnimationIteration, eAnimationEventFirst + 2) -NS_EVENT_MESSAGE(NS_SMIL_TIME_EVENT_START, 4300) -NS_EVENT_MESSAGE(NS_SMIL_BEGIN, NS_SMIL_TIME_EVENT_START) -NS_EVENT_MESSAGE(NS_SMIL_END, NS_SMIL_TIME_EVENT_START + 1) -NS_EVENT_MESSAGE(NS_SMIL_REPEAT, NS_SMIL_TIME_EVENT_START + 2) +NS_EVENT_MESSAGE(eSMILEventFirst, 4300) +NS_EVENT_MESSAGE(NS_SMIL_BEGIN, eSMILEventFirst) +NS_EVENT_MESSAGE(NS_SMIL_END, eSMILEventFirst + 1) +NS_EVENT_MESSAGE(NS_SMIL_REPEAT, eSMILEventFirst + 2) NS_EVENT_MESSAGE(NS_WEBAUDIO_EVENT_START, 4350) NS_EVENT_MESSAGE(NS_AUDIO_PROCESS, NS_WEBAUDIO_EVENT_START) From 61767487d7c4a232f919004cb637f7ef487db833 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:27 +0900 Subject: [PATCH 034/131] Bug 895274 part.196 Rename NS_SMIL_BEGIN to eSMILBeginEvent r=smaug --- dom/events/EventNameList.h | 4 ++-- dom/smil/nsSMILTimedElement.cpp | 4 ++-- widget/EventMessageList.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 59db861c7efe..04b52679d75e 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -774,12 +774,12 @@ NON_IDL_EVENT(zoom, // Only map the ID to the real event name when MESSAGE_TO_EVENT is defined. #ifndef MESSAGE_TO_EVENT NON_IDL_EVENT(begin, - NS_SMIL_BEGIN, + eSMILBeginEvent, EventNameType_SMIL, eBasicEventClass) #endif NON_IDL_EVENT(beginEvent, - NS_SMIL_BEGIN, + eSMILBeginEvent, EventNameType_None, eSMILTimeEventClass) // Only map the ID to the real event name when MESSAGE_TO_EVENT is defined. diff --git a/dom/smil/nsSMILTimedElement.cpp b/dom/smil/nsSMILTimedElement.cpp index 2858c21e08c2..a2f459145c57 100644 --- a/dom/smil/nsSMILTimedElement.cpp +++ b/dom/smil/nsSMILTimedElement.cpp @@ -643,7 +643,7 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, bool aEndOnly) mClient->Activate(mCurrentInterval->Begin()->Time().GetMillis()); } if (mSeekState == SEEK_NOT_SEEKING) { - FireTimeEventAsync(NS_SMIL_BEGIN, 0); + FireTimeEventAsync(eSMILBeginEvent, 0); } if (HasPlayed()) { Reset(); // Apply restart behaviour @@ -1525,7 +1525,7 @@ nsSMILTimedElement::DoPostSeek() case SEEK_FORWARD_FROM_INACTIVE: case SEEK_BACKWARD_FROM_INACTIVE: if (mElementState == STATE_ACTIVE) { - FireTimeEventAsync(NS_SMIL_BEGIN, 0); + FireTimeEventAsync(eSMILBeginEvent, 0); } break; diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index d79a81a71c95..1cd85eed0de1 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -332,7 +332,7 @@ NS_EVENT_MESSAGE(eAnimationEnd, eAnimationEventFirst + 1) NS_EVENT_MESSAGE(eAnimationIteration, eAnimationEventFirst + 2) NS_EVENT_MESSAGE(eSMILEventFirst, 4300) -NS_EVENT_MESSAGE(NS_SMIL_BEGIN, eSMILEventFirst) +NS_EVENT_MESSAGE(eSMILBeginEvent, eSMILEventFirst) NS_EVENT_MESSAGE(NS_SMIL_END, eSMILEventFirst + 1) NS_EVENT_MESSAGE(NS_SMIL_REPEAT, eSMILEventFirst + 2) From 12fcfc409f3aa2330216001a91b7b8e87e87b415 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:27 +0900 Subject: [PATCH 035/131] Bug 895274 part.197 Rename NS_SMIL_END to eSMILEndEvent r=smaug --- dom/events/EventNameList.h | 4 ++-- dom/smil/nsSMILTimedElement.cpp | 4 ++-- widget/EventMessageList.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 04b52679d75e..0e448cdb3117 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -785,12 +785,12 @@ NON_IDL_EVENT(beginEvent, // Only map the ID to the real event name when MESSAGE_TO_EVENT is defined. #ifndef MESSAGE_TO_EVENT NON_IDL_EVENT(end, - NS_SMIL_END, + eSMILEndEvent, EventNameType_SMIL, eBasicEventClass) #endif NON_IDL_EVENT(endEvent, - NS_SMIL_END, + eSMILEndEvent, EventNameType_None, eSMILTimeEventClass) // Only map the ID to the real event name when MESSAGE_TO_EVENT is defined. diff --git a/dom/smil/nsSMILTimedElement.cpp b/dom/smil/nsSMILTimedElement.cpp index a2f459145c57..b547b5b64237 100644 --- a/dom/smil/nsSMILTimedElement.cpp +++ b/dom/smil/nsSMILTimedElement.cpp @@ -679,7 +679,7 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, bool aEndOnly) } mCurrentInterval->FixEnd(); if (mSeekState == SEEK_NOT_SEEKING) { - FireTimeEventAsync(NS_SMIL_END, 0); + FireTimeEventAsync(eSMILEndEvent, 0); } mCurrentRepeatIteration = 0; mOldIntervals.AppendElement(mCurrentInterval.forget()); @@ -1518,7 +1518,7 @@ nsSMILTimedElement::DoPostSeek() case SEEK_FORWARD_FROM_ACTIVE: case SEEK_BACKWARD_FROM_ACTIVE: if (mElementState != STATE_ACTIVE) { - FireTimeEventAsync(NS_SMIL_END, 0); + FireTimeEventAsync(eSMILEndEvent, 0); } break; diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 1cd85eed0de1..36507dfd163d 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -333,7 +333,7 @@ NS_EVENT_MESSAGE(eAnimationIteration, eAnimationEventFirst + 2) NS_EVENT_MESSAGE(eSMILEventFirst, 4300) NS_EVENT_MESSAGE(eSMILBeginEvent, eSMILEventFirst) -NS_EVENT_MESSAGE(NS_SMIL_END, eSMILEventFirst + 1) +NS_EVENT_MESSAGE(eSMILEndEvent, eSMILEventFirst + 1) NS_EVENT_MESSAGE(NS_SMIL_REPEAT, eSMILEventFirst + 2) NS_EVENT_MESSAGE(NS_WEBAUDIO_EVENT_START, 4350) From 0c9e878f6b5924cea07aa42d5d695da2ed3d1d6b Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:28 +0900 Subject: [PATCH 036/131] Bug 895274 part.198 Rename NS_SMIL_REPEAT to eSMILRepeatEvent r=smaug --- dom/events/EventNameList.h | 4 ++-- dom/smil/nsSMILTimedElement.cpp | 2 +- widget/EventMessageList.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 0e448cdb3117..21fda799d88d 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -796,12 +796,12 @@ NON_IDL_EVENT(endEvent, // Only map the ID to the real event name when MESSAGE_TO_EVENT is defined. #ifndef MESSAGE_TO_EVENT NON_IDL_EVENT(repeat, - NS_SMIL_REPEAT, + eSMILRepeatEvent, EventNameType_SMIL, eBasicEventClass) #endif NON_IDL_EVENT(repeatEvent, - NS_SMIL_REPEAT, + eSMILRepeatEvent, EventNameType_None, eSMILTimeEventClass) diff --git a/dom/smil/nsSMILTimedElement.cpp b/dom/smil/nsSMILTimedElement.cpp index b547b5b64237..082a5f906c20 100644 --- a/dom/smil/nsSMILTimedElement.cpp +++ b/dom/smil/nsSMILTimedElement.cpp @@ -727,7 +727,7 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, bool aEndOnly) mCurrentRepeatIteration != prevRepeatIteration && mCurrentRepeatIteration && mSeekState == SEEK_NOT_SEEKING) { - FireTimeEventAsync(NS_SMIL_REPEAT, + FireTimeEventAsync(eSMILRepeatEvent, static_cast(mCurrentRepeatIteration)); } } diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 36507dfd163d..8bf84b550913 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -334,7 +334,7 @@ NS_EVENT_MESSAGE(eAnimationIteration, eAnimationEventFirst + 2) NS_EVENT_MESSAGE(eSMILEventFirst, 4300) NS_EVENT_MESSAGE(eSMILBeginEvent, eSMILEventFirst) NS_EVENT_MESSAGE(eSMILEndEvent, eSMILEventFirst + 1) -NS_EVENT_MESSAGE(NS_SMIL_REPEAT, eSMILEventFirst + 2) +NS_EVENT_MESSAGE(eSMILRepeatEvent, eSMILEventFirst + 2) NS_EVENT_MESSAGE(NS_WEBAUDIO_EVENT_START, 4350) NS_EVENT_MESSAGE(NS_AUDIO_PROCESS, NS_WEBAUDIO_EVENT_START) From 84915ebeecea0cff174b2e9e38fbb2a4375d2a86 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:28 +0900 Subject: [PATCH 037/131] Bug 895274 part.199 Rename NS_GAMEPAD_DISCONNECTED to eGamepadDisconnected r=smaug --- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 21fda799d88d..7e7128401963 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -833,7 +833,7 @@ NON_IDL_EVENT(gamepadconnected, EventNameType_None, eBasicEventClass) NON_IDL_EVENT(gamepaddisconnected, - NS_GAMEPAD_DISCONNECTED, + eGamepadDisconnected, EventNameType_None, eBasicEventClass) #endif diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 8bf84b550913..9bfbd5683ba1 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -419,7 +419,7 @@ NS_EVENT_MESSAGE(NS_GAMEPAD_BUTTONDOWN, NS_GAMEPAD_START) NS_EVENT_MESSAGE(NS_GAMEPAD_BUTTONUP, NS_GAMEPAD_START + 1) NS_EVENT_MESSAGE(NS_GAMEPAD_AXISMOVE, NS_GAMEPAD_START + 2) NS_EVENT_MESSAGE(NS_GAMEPAD_CONNECTED, NS_GAMEPAD_START + 3) -NS_EVENT_MESSAGE(NS_GAMEPAD_DISCONNECTED, NS_GAMEPAD_START + 4) +NS_EVENT_MESSAGE(eGamepadDisconnected, NS_GAMEPAD_START + 4) // Keep this defined to the same value as the event above NS_EVENT_MESSAGE(NS_GAMEPAD_END, NS_GAMEPAD_START + 4) #endif From 4d206ef1a31e5ee0cd2f2637517bee0531aca6f4 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:28 +0900 Subject: [PATCH 038/131] Bug 895274 part.200 Rename NS_GAMEPAD_CONNECTED to eGamepadConnected r=smaug --- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 7e7128401963..0420d8da83e8 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -829,7 +829,7 @@ NON_IDL_EVENT(gamepadaxismove, EventNameType_None, eBasicEventClass) NON_IDL_EVENT(gamepadconnected, - NS_GAMEPAD_CONNECTED, + eGamepadConnected, EventNameType_None, eBasicEventClass) NON_IDL_EVENT(gamepaddisconnected, diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 9bfbd5683ba1..7190fa32609a 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -418,7 +418,7 @@ NS_EVENT_MESSAGE(NS_GAMEPAD_START, 6000) NS_EVENT_MESSAGE(NS_GAMEPAD_BUTTONDOWN, NS_GAMEPAD_START) NS_EVENT_MESSAGE(NS_GAMEPAD_BUTTONUP, NS_GAMEPAD_START + 1) NS_EVENT_MESSAGE(NS_GAMEPAD_AXISMOVE, NS_GAMEPAD_START + 2) -NS_EVENT_MESSAGE(NS_GAMEPAD_CONNECTED, NS_GAMEPAD_START + 3) +NS_EVENT_MESSAGE(eGamepadConnected, NS_GAMEPAD_START + 3) NS_EVENT_MESSAGE(eGamepadDisconnected, NS_GAMEPAD_START + 4) // Keep this defined to the same value as the event above NS_EVENT_MESSAGE(NS_GAMEPAD_END, NS_GAMEPAD_START + 4) From 7ded5a13409f2008ff61416597c9c9408c05cab2 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:28 +0900 Subject: [PATCH 039/131] Bug 895274 part.201 Rename NS_GAMEPAD_BUTTONDOWN to eGamepadButtonDown r=smaug --- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 0420d8da83e8..7651fb75a740 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -817,7 +817,7 @@ NON_IDL_EVENT(MozScrolledAreaChanged, #ifdef MOZ_GAMEPAD NON_IDL_EVENT(gamepadbuttondown, - NS_GAMEPAD_BUTTONDOWN, + eGamepadButtonDown, EventNameType_None, eBasicEventClass) NON_IDL_EVENT(gamepadbuttonup, diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 7190fa32609a..1be9538c23f4 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -415,7 +415,7 @@ NS_EVENT_MESSAGE(NS_SPEAKERMANAGER_SPEAKERFORCEDCHANGE, NS_SPEAKERMANAGER_EVENT_ #ifdef MOZ_GAMEPAD // Gamepad input events NS_EVENT_MESSAGE(NS_GAMEPAD_START, 6000) -NS_EVENT_MESSAGE(NS_GAMEPAD_BUTTONDOWN, NS_GAMEPAD_START) +NS_EVENT_MESSAGE(eGamepadButtonDown, NS_GAMEPAD_START) NS_EVENT_MESSAGE(NS_GAMEPAD_BUTTONUP, NS_GAMEPAD_START + 1) NS_EVENT_MESSAGE(NS_GAMEPAD_AXISMOVE, NS_GAMEPAD_START + 2) NS_EVENT_MESSAGE(eGamepadConnected, NS_GAMEPAD_START + 3) From 1914a3b112bf1a3053115339b5e5a47148ce9460 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:28 +0900 Subject: [PATCH 040/131] Bug 895274 part.202 Rename NS_GAMEPAD_BUTTONUP to eGamepadButtonUp r=smaug --- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 7651fb75a740..1da280e27fc8 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -821,7 +821,7 @@ NON_IDL_EVENT(gamepadbuttondown, EventNameType_None, eBasicEventClass) NON_IDL_EVENT(gamepadbuttonup, - NS_GAMEPAD_BUTTONUP, + eGamepadButtonUp, EventNameType_None, eBasicEventClass) NON_IDL_EVENT(gamepadaxismove, diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 1be9538c23f4..721e5982e817 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -416,7 +416,7 @@ NS_EVENT_MESSAGE(NS_SPEAKERMANAGER_SPEAKERFORCEDCHANGE, NS_SPEAKERMANAGER_EVENT_ // Gamepad input events NS_EVENT_MESSAGE(NS_GAMEPAD_START, 6000) NS_EVENT_MESSAGE(eGamepadButtonDown, NS_GAMEPAD_START) -NS_EVENT_MESSAGE(NS_GAMEPAD_BUTTONUP, NS_GAMEPAD_START + 1) +NS_EVENT_MESSAGE(eGamepadButtonUp, NS_GAMEPAD_START + 1) NS_EVENT_MESSAGE(NS_GAMEPAD_AXISMOVE, NS_GAMEPAD_START + 2) NS_EVENT_MESSAGE(eGamepadConnected, NS_GAMEPAD_START + 3) NS_EVENT_MESSAGE(eGamepadDisconnected, NS_GAMEPAD_START + 4) From 1049c7be288bee445f6537c2d47952956e8917a2 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:28 +0900 Subject: [PATCH 041/131] Bug 895274 part.203 Rename NS_GAMEPAD_AXISMOVE to eGamepadAxisMove r=smaug --- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 1da280e27fc8..3946bf909b37 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -825,7 +825,7 @@ NON_IDL_EVENT(gamepadbuttonup, EventNameType_None, eBasicEventClass) NON_IDL_EVENT(gamepadaxismove, - NS_GAMEPAD_AXISMOVE, + eGamepadAxisMove, EventNameType_None, eBasicEventClass) NON_IDL_EVENT(gamepadconnected, diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 721e5982e817..f0609f0f1aca 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -417,7 +417,7 @@ NS_EVENT_MESSAGE(NS_SPEAKERMANAGER_SPEAKERFORCEDCHANGE, NS_SPEAKERMANAGER_EVENT_ NS_EVENT_MESSAGE(NS_GAMEPAD_START, 6000) NS_EVENT_MESSAGE(eGamepadButtonDown, NS_GAMEPAD_START) NS_EVENT_MESSAGE(eGamepadButtonUp, NS_GAMEPAD_START + 1) -NS_EVENT_MESSAGE(NS_GAMEPAD_AXISMOVE, NS_GAMEPAD_START + 2) +NS_EVENT_MESSAGE(eGamepadAxisMove, NS_GAMEPAD_START + 2) NS_EVENT_MESSAGE(eGamepadConnected, NS_GAMEPAD_START + 3) NS_EVENT_MESSAGE(eGamepadDisconnected, NS_GAMEPAD_START + 4) // Keep this defined to the same value as the event above From 3b99f4a9ec198f0e5dfc086234d6cecbd5733233 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:28 +0900 Subject: [PATCH 042/131] Bug 895274 part.204 Rename NS_GAMEPAD_START to eGamepadEventFirst r=smaug --- dom/events/EventListenerManager.cpp | 2 +- widget/EventMessageList.h | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index f4e981b66437..508314d839fd 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -383,7 +383,7 @@ EventListenerManager::AddEventListenerInternal( window->SetHasMouseEnterLeaveEventListeners(); } #ifdef MOZ_GAMEPAD - } else if (aEventMessage >= NS_GAMEPAD_START && + } else if (aEventMessage >= eGamepadEventFirst && aEventMessage <= NS_GAMEPAD_END) { nsPIDOMWindow* window = GetInnerWindowForTarget(); if (window) { diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index f0609f0f1aca..77e8b5e103d9 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -414,14 +414,13 @@ NS_EVENT_MESSAGE(NS_SPEAKERMANAGER_SPEAKERFORCEDCHANGE, NS_SPEAKERMANAGER_EVENT_ #ifdef MOZ_GAMEPAD // Gamepad input events -NS_EVENT_MESSAGE(NS_GAMEPAD_START, 6000) -NS_EVENT_MESSAGE(eGamepadButtonDown, NS_GAMEPAD_START) -NS_EVENT_MESSAGE(eGamepadButtonUp, NS_GAMEPAD_START + 1) -NS_EVENT_MESSAGE(eGamepadAxisMove, NS_GAMEPAD_START + 2) -NS_EVENT_MESSAGE(eGamepadConnected, NS_GAMEPAD_START + 3) -NS_EVENT_MESSAGE(eGamepadDisconnected, NS_GAMEPAD_START + 4) -// Keep this defined to the same value as the event above -NS_EVENT_MESSAGE(NS_GAMEPAD_END, NS_GAMEPAD_START + 4) +NS_EVENT_MESSAGE(eGamepadEventFirst, 6000) +NS_EVENT_MESSAGE(eGamepadButtonDown, eGamepadEventFirst) +NS_EVENT_MESSAGE(eGamepadButtonUp, eGamepadEventFirst + 1) +NS_EVENT_MESSAGE(eGamepadAxisMove, eGamepadEventFirst + 2) +NS_EVENT_MESSAGE(eGamepadConnected, eGamepadEventFirst + 3) +NS_EVENT_MESSAGE(eGamepadDisconnected, eGamepadEventFirst + 4) +NS_EVENT_MESSAGE(NS_GAMEPAD_END, eGamepadDisconnected) #endif // input and beforeinput events. From 82117e2ac85f0586b93d0f483980594b53dce939 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 11 Sep 2015 21:21:28 +0900 Subject: [PATCH 043/131] Bug 895274 part.205 Rename NS_GAMEPAD_END to eGamepadEventLast r=smaug --- dom/events/EventListenerManager.cpp | 2 +- widget/EventMessageList.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index 508314d839fd..7ddba2ccfe28 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -384,7 +384,7 @@ EventListenerManager::AddEventListenerInternal( } #ifdef MOZ_GAMEPAD } else if (aEventMessage >= eGamepadEventFirst && - aEventMessage <= NS_GAMEPAD_END) { + aEventMessage <= eGamepadEventLast) { nsPIDOMWindow* window = GetInnerWindowForTarget(); if (window) { window->SetHasGamepadEventListener(); diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 77e8b5e103d9..05285027f0a2 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -420,7 +420,7 @@ NS_EVENT_MESSAGE(eGamepadButtonUp, eGamepadEventFirst + 1) NS_EVENT_MESSAGE(eGamepadAxisMove, eGamepadEventFirst + 2) NS_EVENT_MESSAGE(eGamepadConnected, eGamepadEventFirst + 3) NS_EVENT_MESSAGE(eGamepadDisconnected, eGamepadEventFirst + 4) -NS_EVENT_MESSAGE(NS_GAMEPAD_END, eGamepadDisconnected) +NS_EVENT_MESSAGE(eGamepadEventLast, eGamepadDisconnected) #endif // input and beforeinput events. From 35f1f1cf1d94801d38df42e0499acd49d7030efa Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Fri, 11 Sep 2015 14:27:22 +0200 Subject: [PATCH 044/131] Bug 1201459: IonMonkey - Fix typepolicy of MFilterTypeSet with MIRType_Float32, r=bbouvier,nbp --- js/src/jit-test/tests/ion/bug1201459.js | 5 +++++ js/src/jit/IonAnalysis.cpp | 3 +++ js/src/jit/MIR.cpp | 24 ++++++++++++++++++++++++ js/src/jit/MIR.h | 4 ++++ js/src/jit/TypePolicy.cpp | 24 ++++++++++++++++++++++++ 5 files changed, 60 insertions(+) create mode 100644 js/src/jit-test/tests/ion/bug1201459.js diff --git a/js/src/jit-test/tests/ion/bug1201459.js b/js/src/jit-test/tests/ion/bug1201459.js new file mode 100644 index 000000000000..841045d9fa06 --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1201459.js @@ -0,0 +1,5 @@ +// |jit-test| error:ReferenceError +function f() { + (x ? Math.fround(0) : x ? a : x) && b; +} +f(Math.fround); diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 04cd1f3e30e5..f72eeb106e7b 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -1166,6 +1166,9 @@ TypeAnalyzer::insertConversions() adjustPhiInputs(phi); } } + + // AdjustInputs can add/remove/mutate instructions before and after the + // current instruction. Only increment the iterator after it is finished. for (MInstructionIterator iter(block->begin()); iter != block->end(); iter++) { if (!adjustInputs(*iter)) return false; diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 00dc31d884f8..9c25237611fe 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -608,6 +608,30 @@ MDefinition::justReplaceAllUsesWith(MDefinition* dom) dom->uses_.takeElements(uses_); } +void +MDefinition::justReplaceAllUsesWithExcept(MDefinition* dom) +{ + MOZ_ASSERT(dom != nullptr); + MOZ_ASSERT(dom != this); + + // Move all uses to new dom. Save the use of the dominating instruction. + MUse *exceptUse = nullptr; + for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ++i) { + if (i->consumer() != dom) { + i->setProducerUnchecked(dom); + } else { + MOZ_ASSERT(!exceptUse); + exceptUse = *i; + } + } + dom->uses_.takeElements(uses_); + + // Restore the use to the original definition. + dom->uses_.remove(exceptUse); + exceptUse->setProducerUnchecked(this); + uses_.pushFront(exceptUse); +} + void MDefinition::optimizeOutAllUses(TempAllocator& alloc) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index bca416979bde..1d67b0b6081f 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -739,6 +739,10 @@ class MDefinition : public MNode // Like replaceAllUsesWith, but doesn't set UseRemoved on |this|'s operands. void justReplaceAllUsesWith(MDefinition* dom); + // Like justReplaceAllUsesWith, but doesn't replace its own use to the + // dominating instruction (which would introduce a circular dependency). + void justReplaceAllUsesWithExcept(MDefinition* dom); + // Replace the current instruction by an optimized-out constant in all uses // of the current instruction. Note, that optimized-out constant should not // be observed, and thus they should not flow in any computation. diff --git a/js/src/jit/TypePolicy.cpp b/js/src/jit/TypePolicy.cpp index 87d2f9a69d11..3b30923111f7 100644 --- a/js/src/jit/TypePolicy.cpp +++ b/js/src/jit/TypePolicy.cpp @@ -1080,6 +1080,30 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) MIRType inputType = ins->getOperand(0)->type(); MIRType outputType = ins->type(); + // Special case when output is a Float32, but input isn't. + if (outputType == MIRType_Float32 && inputType != MIRType_Float32) { + // Create a MToFloat32 to add between the MFilterTypeSet and + // its uses. + MInstruction* replace = MToFloat32::New(alloc, ins); + ins->justReplaceAllUsesWithExcept(replace); + ins->block()->insertAfter(ins, replace); + + // Reset the type to not MIRType_Float32 + // Note: setResultType shouldn't happen in TypePolicies, + // Here it is fine, since there is just one use we just + // added ourself. And the resulting type after MToFloat32 + // equals the original type. + ins->setResultType(ins->resultTypeSet()->getKnownMIRType()); + outputType = ins->type(); + + // Do the type analysis + if (!replace->typePolicy()->adjustInputs(alloc, replace)) + return false; + + // Fall through to let the MFilterTypeSet adjust its input based + // on its new type. + } + // Input and output type are already in accordance. if (inputType == outputType) return true; From 47268649ef72b22b018adf8b67d5ca1570077364 Mon Sep 17 00:00:00 2001 From: Yura Zenevich Date: Thu, 10 Sep 2015 11:45:33 -0400 Subject: [PATCH 045/131] Bug 1201595 - improving a11y checks reliability and error messaging. r=ato --- .../tests/unit/test_accessibility.py | 4 +- testing/marionette/driver.js | 2 +- testing/marionette/elements.js | 9 +- testing/marionette/listener.js | 85 ++++++++++--------- 4 files changed, 53 insertions(+), 47 deletions(-) diff --git a/testing/marionette/client/marionette/tests/unit/test_accessibility.py b/testing/marionette/client/marionette/tests/unit/test_accessibility.py index ebd5c154418d..ea9544d57d42 100644 --- a/testing/marionette/client/marionette/tests/unit/test_accessibility.py +++ b/testing/marionette/client/marionette/tests/unit/test_accessibility.py @@ -97,7 +97,7 @@ class TestAccessibility(MarionetteTestCase): lambda button: self.assertRaises(ElementNotAccessibleException, button.tap)) self.run_element_test(self.falsy_elements, - lambda button: self.assertRaises(ElementNotAccessibleException, + lambda button: self.assertRaises(ElementNotVisibleException, button.tap)) def test_single_tap_raises_no_exceptions(self): @@ -120,7 +120,7 @@ class TestAccessibility(MarionetteTestCase): lambda button: self.assertRaises(ElementNotAccessibleException, button.click)) self.run_element_test(self.falsy_elements, - lambda button: self.assertRaises(ElementNotAccessibleException, + lambda button: self.assertRaises(ElementNotVisibleException, button.click)) def test_click_raises_no_exceptions(self): diff --git a/testing/marionette/driver.js b/testing/marionette/driver.js index ae458e2e54ae..ede82cc07740 100644 --- a/testing/marionette/driver.js +++ b/testing/marionette/driver.js @@ -1803,7 +1803,7 @@ GeckoDriver.prototype.singleTap = function(cmd, resp) { case Context.CONTENT: this.addFrameCloseListener("tap"); - yield this.listener.singleTap({id: id, corx: x, cory: y}); + yield this.listener.singleTap(id, x, y); break; } }; diff --git a/testing/marionette/elements.js b/testing/marionette/elements.js index bc35cbbe2a6f..c3779ff82b9e 100644 --- a/testing/marionette/elements.js +++ b/testing/marionette/elements.js @@ -98,7 +98,8 @@ Accessibility.prototype = { getAccessibleObject(element, mustHaveAccessible = false) { let acc = this.accessibleRetrieval.getAccessibleFor(element); if (!acc && mustHaveAccessible) { - this.handleErrorMessage('Element does not have an accessible object'); + this.handleErrorMessage('Element does not have an accessible object', + element); } return acc; }, @@ -178,11 +179,15 @@ Accessibility.prototype = { /** * Send an error message or log the error message in the log * @param String message + * @param DOMElement element that caused an error */ - handleErrorMessage(message) { + handleErrorMessage(message, element) { if (!message) { return; } + if (element) { + message += ` -> id: ${element.id}, tagName: ${element.tagName}, className: ${element.className}\n`; + } if (this.strict) { throw new ElementNotAccessibleError(message); } diff --git a/testing/marionette/listener.js b/testing/marionette/listener.js index 2401c62723c5..c3d6fed20b31 100644 --- a/testing/marionette/listener.js +++ b/testing/marionette/listener.js @@ -215,6 +215,7 @@ let isElementDisplayedFn = dispatch(isElementDisplayed); let getElementValueOfCssPropertyFn = dispatch(getElementValueOfCssProperty); let switchToShadowRootFn = dispatch(switchToShadowRoot); let getCookiesFn = dispatch(getCookies); +let singleTapFn = dispatch(singleTap); /** * Start all message listeners @@ -225,7 +226,7 @@ function startListeners() { addMessageListenerId("Marionette:executeScript", executeScript); addMessageListenerId("Marionette:executeAsyncScript", executeAsyncScript); addMessageListenerId("Marionette:executeJSScript", executeJSScript); - addMessageListenerId("Marionette:singleTap", singleTap); + addMessageListenerId("Marionette:singleTap", singleTapFn); addMessageListenerId("Marionette:actionChain", actionChain); addMessageListenerId("Marionette:multiAction", multiAction); addMessageListenerId("Marionette:get", get); @@ -329,7 +330,7 @@ function deleteSession(msg) { removeMessageListenerId("Marionette:executeScript", executeScript); removeMessageListenerId("Marionette:executeAsyncScript", executeAsyncScript); removeMessageListenerId("Marionette:executeJSScript", executeJSScript); - removeMessageListenerId("Marionette:singleTap", singleTap); + removeMessageListenerId("Marionette:singleTap", singleTapFn); removeMessageListenerId("Marionette:actionChain", actionChain); removeMessageListenerId("Marionette:multiAction", multiAction); removeMessageListenerId("Marionette:get", get); @@ -914,34 +915,27 @@ function checkVisible(el, x, y) { /** * Function that perform a single tap */ -function singleTap(msg) { - let command_id = msg.json.command_id; - try { - let el = elementManager.getKnownElement(msg.json.id, curContainer); - let acc = accessibility.getAccessibleObject(el, true); - // after this block, the element will be scrolled into view - let visible = checkVisible(el, msg.json.corx, msg.json.cory); - checkVisibleAccessibility(acc, visible); - if (!visible) { - sendError(new ElementNotVisibleError("Element is not currently visible and may not be manipulated"), command_id); - return; - } - checkActionableAccessibility(acc); - if (!curContainer.frame.document.createTouch) { - actions.mouseEventsOnly = true; - } - let c = coordinates(el, msg.json.corx, msg.json.cory); - if (!actions.mouseEventsOnly) { - let touchId = actions.nextTouchId++; - let touch = createATouch(el, c.x, c.y, touchId); - emitTouchEvent('touchstart', touch); - emitTouchEvent('touchend', touch); - } - actions.mouseTap(el.ownerDocument, c.x, c.y); - sendOk(command_id); - } catch (e) { - sendError(e, command_id); +function singleTap(id, corx, cory) { + let el = elementManager.getKnownElement(id, curContainer); + // after this block, the element will be scrolled into view + let visible = checkVisible(el, corx, cory); + if (!visible) { + throw new ElementNotVisibleError("Element is not currently visible and may not be manipulated"); } + let acc = accessibility.getAccessibleObject(el, true); + checkVisibleAccessibility(acc, el, visible); + checkActionableAccessibility(acc, el); + if (!curContainer.frame.document.createTouch) { + actions.mouseEventsOnly = true; + } + let c = coordinates(el, corx, cory); + if (!actions.mouseEventsOnly) { + let touchId = actions.nextTouchId++; + let touch = createATouch(el, c.x, c.y, touchId); + emitTouchEvent('touchstart', touch); + emitTouchEvent('touchend', touch); + } + actions.mouseTap(el.ownerDocument, c.x, c.y); } /** @@ -969,16 +963,17 @@ function checkEnabledAccessibility(accesible, element, enabled) { } else if (!enabled && !disabledAccessibility) { message = 'Element is disabled but enabled via the accessibility API'; } - accessibility.handleErrorMessage(message); + accessibility.handleErrorMessage(message, element); } /** * Check if the element's visible state corresponds to its accessibility API * visibility * @param nsIAccessible object + * @param WebElement corresponding to nsIAccessible object * @param Boolean visible element's visibility state */ -function checkVisibleAccessibility(accesible, visible) { +function checkVisibleAccessibility(accesible, element, visible) { if (!accesible) { return; } @@ -991,14 +986,15 @@ function checkVisibleAccessibility(accesible, visible) { message = 'Element is currently only visible via the accessibility API ' + 'and can be manipulated by it'; } - accessibility.handleErrorMessage(message); + accessibility.handleErrorMessage(message, element); } /** * Check if it is possible to activate an element with the accessibility API * @param nsIAccessible object + * @param WebElement corresponding to nsIAccessible object */ -function checkActionableAccessibility(accesible) { +function checkActionableAccessibility(accesible, element) { if (!accesible) { return; } @@ -1013,16 +1009,17 @@ function checkActionableAccessibility(accesible) { } else if (!accessibility.matchState(accesible, 'STATE_FOCUSABLE')) { message = 'Element is not focusable via the accessibility API'; } - accessibility.handleErrorMessage(message); + accessibility.handleErrorMessage(message, element); } /** * Check if element's selected state corresponds to its accessibility API * selected state. * @param nsIAccessible object + * @param WebElement corresponding to nsIAccessible object * @param Boolean selected element's selected state */ -function checkSelectedAccessibility(accessible, selected) { +function checkSelectedAccessibility(accessible, element, selected) { if (!accessible) { return; } @@ -1039,7 +1036,7 @@ function checkSelectedAccessibility(accessible, selected) { } else if (!selected && selectedAccessibility) { message = 'Element is not selected but selected via the accessibility API'; } - accessibility.handleErrorMessage(message); + accessibility.handleErrorMessage(message, element); } @@ -1448,15 +1445,16 @@ function getActiveElement() { */ function clickElement(id) { let el = elementManager.getKnownElement(id, curContainer); - let acc = accessibility.getAccessibleObject(el, true); let visible = checkVisible(el); - checkVisibleAccessibility(acc, visible); if (!visible) { throw new ElementNotVisibleError("Element is not visible"); } - checkActionableAccessibility(acc); + let acc = accessibility.getAccessibleObject(el, true); + checkVisibleAccessibility(acc, el, visible); + if (utils.isElementEnabled(el)) { checkEnabledAccessibility(acc, el, true); + checkActionableAccessibility(acc, el); utils.synthesizeMouseAtCenter(el, {}, el.ownerDocument.defaultView); } else { throw new InvalidElementStateError("Element is not Enabled"); @@ -1516,7 +1514,8 @@ function getElementTagName(id) { function isElementDisplayed(id) { let el = elementManager.getKnownElement(id, curContainer); let displayed = utils.isElementDisplayed(el); - checkVisibleAccessibility(accessibility.getAccessibleObject(el), displayed); + checkVisibleAccessibility( + accessibility.getAccessibleObject(el), el, displayed); return displayed; } @@ -1584,7 +1583,8 @@ function isElementEnabled(id) { function isElementSelected(id) { let el = elementManager.getKnownElement(id, curContainer); let selected = utils.isElementSelected(el); - checkSelectedAccessibility(accessibility.getAccessibleObject(el), selected); + checkSelectedAccessibility( + accessibility.getAccessibleObject(el), el, selected); return selected; } @@ -1599,7 +1599,8 @@ function sendKeysToElement(msg) { let el = elementManager.getKnownElement(msg.json.id, curContainer); // Element should be actionable from the accessibility standpoint to be able // to send keys to it. - checkActionableAccessibility(accessibility.getAccessibleObject(el, true)); + checkActionableAccessibility( + accessibility.getAccessibleObject(el, true), el); if (el.type == "file") { let p = val.join(""); fileInputElement = el; From 9fcfcb0de7aa59221865055f88ad5fc9efd02709 Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Fri, 11 Sep 2015 15:24:46 +0200 Subject: [PATCH 046/131] Bug 1127270: Only acquire a hold on the compositor thread once the channel for a parent actor has been succesfully connected. r=nical --- gfx/layers/ipc/CompositorParent.cpp | 3 ++- gfx/layers/ipc/ImageBridgeParent.cpp | 7 ++++++- gfx/layers/ipc/ImageBridgeParent.h | 3 +++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 147e293462fd..b48aac4b7cbb 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -1636,7 +1636,6 @@ class CrossProcessCompositorParent final : public PCompositorParent, public: explicit CrossProcessCompositorParent(Transport* aTransport) : mTransport(aTransport) - , mCompositorThreadHolder(sCompositorThreadHolder) , mNotifyAfterRemotePaint(false) { MOZ_ASSERT(NS_IsMainThread()); @@ -1726,6 +1725,8 @@ public: TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd); +protected: + void OnChannelConnected(int32_t pid) override { mCompositorThreadHolder = sCompositorThreadHolder; } private: // Private destructor, to discourage deletion outside of Release(): virtual ~CrossProcessCompositorParent(); diff --git a/gfx/layers/ipc/ImageBridgeParent.cpp b/gfx/layers/ipc/ImageBridgeParent.cpp index 1b488c2f863c..af990683416b 100644 --- a/gfx/layers/ipc/ImageBridgeParent.cpp +++ b/gfx/layers/ipc/ImageBridgeParent.cpp @@ -58,7 +58,6 @@ ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop, : mMessageLoop(aLoop) , mTransport(aTransport) , mSetChildThreadPriority(false) - , mCompositorThreadHolder(GetCompositorThreadHolder()) { MOZ_ASSERT(NS_IsMainThread()); sMainLoop = MessageLoop::current(); @@ -385,6 +384,12 @@ ImageBridgeParent::CloneToplevel(const InfallibleTArray& aFds return nullptr; } +void +ImageBridgeParent::OnChannelConnected(int32_t aPid) +{ + mCompositorThreadHolder = GetCompositorThreadHolder(); +} + bool ImageBridgeParent::IsSameProcess() const { return OtherPid() == base::GetCurrentProcId(); diff --git a/gfx/layers/ipc/ImageBridgeParent.h b/gfx/layers/ipc/ImageBridgeParent.h index bf9c9e4ebf4b..9cfba1a20bae 100644 --- a/gfx/layers/ipc/ImageBridgeParent.h +++ b/gfx/layers/ipc/ImageBridgeParent.h @@ -151,6 +151,9 @@ public: base::ProcessHandle aPeerProcess, mozilla::ipc::ProtocolCloneContext* aCtx) override; +protected: + void OnChannelConnected(int32_t pid) override; + private: void DeferredDestroy(); MessageLoop* mMessageLoop; From e8cfbc97113d7c9a493ad3cd0a90c4de38a0dddb Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Fri, 11 Sep 2015 15:59:48 +0200 Subject: [PATCH 047/131] Bug 1176240: IonMonkey: Try to fold phis containing MFilterTypeSet, r=nbp --- js/src/jit/MIR.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ js/src/jit/MIR.h | 1 + 2 files changed, 44 insertions(+) diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 9c25237611fe..4fdde4801ba4 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -1738,6 +1738,46 @@ MPhi::operandIfRedundant() return first; } +MDefinition* +MPhi::foldsFilterTypeSet() +{ + // Fold phi with as operands a combination of 'subject' and + // MFilterTypeSet(subject) to 'subject'. + + if (inputs_.length() == 0) + return nullptr; + + MDefinition* subject = getOperand(0); + if (subject->isFilterTypeSet()) + subject = subject->toFilterTypeSet()->input(); + + // Not same type, don't fold. + if (subject->type() != type()) + return nullptr; + + // Phi is better typed (has typeset). Don't fold. + if (resultTypeSet() && !subject->resultTypeSet()) + return nullptr; + + // Phi is better typed (according to typeset). Don't fold. + if (subject->resultTypeSet() && resultTypeSet()) { + if (!subject->resultTypeSet()->isSubset(resultTypeSet())) + return nullptr; + } + + for (size_t i = 1, e = numOperands(); i < e; i++) { + MDefinition* op = getOperand(i); + if (op == subject) + continue; + if (op->isFilterTypeSet() && op->toFilterTypeSet()->input() == subject) + continue; + + return nullptr; + } + + return subject; +} + MDefinition* MPhi::foldsTo(TempAllocator& alloc) { @@ -1747,6 +1787,9 @@ MPhi::foldsTo(TempAllocator& alloc) if (MDefinition* def = foldsTernary()) return def; + if (MDefinition* def = foldsFilterTypeSet()) + return def; + return this; } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 1d67b0b6081f..bfcf8f21139c 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -6902,6 +6902,7 @@ class MPhi final MDefinition* foldsTo(TempAllocator& alloc) override; MDefinition* foldsTernary(); + MDefinition* foldsFilterTypeSet(); bool congruentTo(const MDefinition* ins) const override; From 6d957289cf7ccc37f8f3798b51ade98cb126d6e2 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Wed, 26 Aug 2015 17:37:48 -0500 Subject: [PATCH 048/131] Bug 1182665 - Add gfxPlatform::GetScreenSize() and use nsIScreen for gfxPlatform::GetScreenDepth() r=nical --- gfx/thebes/gfxAndroidPlatform.cpp | 14 +------------- gfx/thebes/gfxAndroidPlatform.h | 2 -- gfx/thebes/gfxPlatform.cpp | 24 +++++++++++++++++------- gfx/thebes/gfxPlatform.h | 11 ++++++++++- gfx/thebes/gfxPlatformGtk.cpp | 18 ------------------ gfx/thebes/gfxPlatformGtk.h | 2 -- gfx/thebes/gfxQtPlatform.cpp | 10 ++-------- gfx/thebes/gfxQtPlatform.h | 2 -- gfx/thebes/gfxWindowsPlatform.cpp | 20 -------------------- gfx/thebes/gfxWindowsPlatform.h | 2 -- 10 files changed, 30 insertions(+), 75 deletions(-) diff --git a/gfx/thebes/gfxAndroidPlatform.cpp b/gfx/thebes/gfxAndroidPlatform.cpp index 215946c2f365..def0438f9b6f 100644 --- a/gfx/thebes/gfxAndroidPlatform.cpp +++ b/gfx/thebes/gfxAndroidPlatform.cpp @@ -100,13 +100,7 @@ gfxAndroidPlatform::gfxAndroidPlatform() RegisterStrongMemoryReporter(new FreetypeReporter()); - nsCOMPtr screenMgr = do_GetService("@mozilla.org/gfx/screenmanager;1"); - nsCOMPtr screen; - screenMgr->GetPrimaryScreen(getter_AddRefs(screen)); - mScreenDepth = 24; - screen->GetColorDepth(&mScreenDepth); - - mOffscreenFormat = mScreenDepth == 16 + mOffscreenFormat = GetScreenDepth() == 16 ? gfxImageFormat::RGB16_565 : gfxImageFormat::RGB24; @@ -418,12 +412,6 @@ gfxAndroidPlatform::RequiresLinearZoom() return gfxPlatform::RequiresLinearZoom(); } -int -gfxAndroidPlatform::GetScreenDepth() const -{ - return mScreenDepth; -} - bool gfxAndroidPlatform::UseAcceleratedSkiaCanvas() { diff --git a/gfx/thebes/gfxAndroidPlatform.h b/gfx/thebes/gfxAndroidPlatform.h index b87b0a222b64..3b93b0cd7d39 100644 --- a/gfx/thebes/gfxAndroidPlatform.h +++ b/gfx/thebes/gfxAndroidPlatform.h @@ -80,8 +80,6 @@ public: FT_Library GetFTLibrary(); - virtual int GetScreenDepth() const; - virtual bool CanRenderContentToDataSurface() const override { return true; } diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index b696e7b0f105..698b488fb21e 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -506,6 +506,7 @@ gfxPlatform::Init() InitLayersAccelerationPrefs(); InitLayersIPC(); + gPlatform->PopulateScreenInfo(); gPlatform->ComputeTileSize(); nsresult rv; @@ -1051,6 +1052,22 @@ gfxPlatform::ComputeTileSize() SetTileSize(w, h); } +void +gfxPlatform::PopulateScreenInfo() +{ + nsCOMPtr manager = do_GetService("@mozilla.org/gfx/screenmanager;1"); + MOZ_ASSERT(manager, "failed to get nsIScreenManager"); + + nsCOMPtr screen; + manager->GetPrimaryScreen(getter_AddRefs(screen)); + MOZ_ASSERT(screen, "failed to get primary screen"); + + screen->GetColorDepth(&mScreenDepth); + + int left, top; + screen->GetRect(&left, &top, &mScreenSize.width, &mScreenSize.height); +} + bool gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget) { @@ -2081,13 +2098,6 @@ gfxPlatform::GetLog(eGfxLog aWhichLog) return nullptr; } -int -gfxPlatform::GetScreenDepth() const -{ - NS_WARNING("GetScreenDepth not implemented on this platform -- returning 0!"); - return 0; -} - mozilla::gfx::SurfaceFormat gfxPlatform::Optimal2DFormatForContent(gfxContentType aContent) { diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index b992a6f98a8c..9e3e9415e6f3 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -568,7 +568,8 @@ public: */ static PRLogModuleInfo* GetLog(eGfxLog aWhichLog); - virtual int GetScreenDepth() const; + int GetScreenDepth() const { return mScreenDepth; } + mozilla::gfx::IntSize GetScreenSize() const { return mScreenSize; } /** * Return the layer debugging options to use browser-wide. @@ -762,6 +763,11 @@ private: */ void ComputeTileSize(); + /** + * This uses nsIScreenManager to determine the screen size and color depth + */ + void PopulateScreenInfo(); + nsRefPtr mScreenReferenceSurface; nsTArray mCJKPrefLangs; nsCOMPtr mSRGBOverrideObserver; @@ -789,6 +795,9 @@ private: // Backend that we are compositing with. NONE, if no compositor has been // created yet. mozilla::layers::LayersBackend mCompositorBackend; + + int32_t mScreenDepth; + mozilla::gfx::IntSize mScreenSize; }; #endif /* GFX_PLATFORM_H */ diff --git a/gfx/thebes/gfxPlatformGtk.cpp b/gfx/thebes/gfxPlatformGtk.cpp index 9c8642a151e4..dc1bde896dfe 100644 --- a/gfx/thebes/gfxPlatformGtk.cpp +++ b/gfx/thebes/gfxPlatformGtk.cpp @@ -363,24 +363,6 @@ gfxPlatformGtk::GetOffscreenFormat() return gfxImageFormat::RGB24; } -static int sDepth = 0; - -int -gfxPlatformGtk::GetScreenDepth() const -{ - if (!sDepth) { - GdkScreen *screen = gdk_screen_get_default(); - if (screen) { - sDepth = gdk_visual_get_depth(gdk_visual_get_system()); - } else { - sDepth = 24; - } - - } - - return sDepth; -} - void gfxPlatformGtk::GetPlatformCMSOutputProfile(void *&mem, size_t &size) { diff --git a/gfx/thebes/gfxPlatformGtk.h b/gfx/thebes/gfxPlatformGtk.h index 6f5fa09d0ed2..9adac7f39bb5 100644 --- a/gfx/thebes/gfxPlatformGtk.h +++ b/gfx/thebes/gfxPlatformGtk.h @@ -122,8 +122,6 @@ public: virtual gfxImageFormat GetOffscreenFormat() override; - virtual int GetScreenDepth() const override; - bool SupportsApzWheelInput() const override { return true; } diff --git a/gfx/thebes/gfxQtPlatform.cpp b/gfx/thebes/gfxQtPlatform.cpp index f0efd8f66594..272a6996e742 100644 --- a/gfx/thebes/gfxQtPlatform.cpp +++ b/gfx/thebes/gfxQtPlatform.cpp @@ -53,8 +53,8 @@ gfxQtPlatform::gfxQtPlatform() if (!sFontconfigUtils) sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils(); - mScreenDepth = qApp->primaryScreen()->depth(); - if (mScreenDepth == 16) { + int32_t depth = GetScreenDepth(); + if (depth == 16) { sOffscreenFormat = gfxImageFormat::RGB16_565; } uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA); @@ -195,12 +195,6 @@ gfxQtPlatform::GetOffscreenFormat() return sOffscreenFormat; } -int -gfxQtPlatform::GetScreenDepth() const -{ - return mScreenDepth; -} - already_AddRefed gfxQtPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont* aFont) { diff --git a/gfx/thebes/gfxQtPlatform.h b/gfx/thebes/gfxQtPlatform.h index 5a209d422808..fad09180df53 100644 --- a/gfx/thebes/gfxQtPlatform.h +++ b/gfx/thebes/gfxQtPlatform.h @@ -82,8 +82,6 @@ public: static Screen* GetXScreen(QWindow* aWindow = 0); #endif - virtual int GetScreenDepth() const override; - bool AccelerateLayersByDefault() override { return true; } diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 090adba4e20e..6e32380b7eef 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -1595,26 +1595,6 @@ gfxWindowsPlatform::IsOptimus() return knowIsOptimus; } -int -gfxWindowsPlatform::GetScreenDepth() const -{ - // if the system doesn't have all displays with the same - // pixel format, just return 24 and move on with life. - if (!GetSystemMetrics(SM_SAMEDISPLAYFORMAT)) - return 24; - - HDC hdc = GetDC(nullptr); - if (!hdc) - return 24; - - int depth = GetDeviceCaps(hdc, BITSPIXEL) * - GetDeviceCaps(hdc, PLANES); - - ReleaseDC(nullptr, hdc); - - return depth; -} - IDXGIAdapter1* gfxWindowsPlatform::GetDXGIAdapter() { diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index c5dc0efd8dcd..51773691f504 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -139,8 +139,6 @@ public: RENDER_MODE_MAX }; - int GetScreenDepth() const; - RenderMode GetRenderMode() { return mRenderMode; } void SetRenderMode(RenderMode rmode) { mRenderMode = rmode; } From 226e891da2e0ee60064f8b8c89b456da3a7fb46e Mon Sep 17 00:00:00 2001 From: James Willcox Date: Wed, 26 Aug 2015 15:25:40 -0500 Subject: [PATCH 049/131] Bug 1182665 - Use a direct JNI call to determine screen size in nsScreenManagerAndroid r=jchen --- mobile/android/base/GeckoAppShell.java | 13 +++++++++++++ widget/android/GeneratedJNIWrappers.cpp | 8 ++++++++ widget/android/GeneratedJNIWrappers.h | 17 +++++++++++++++++ widget/android/bindings/AndroidRect-classes.txt | 2 ++ widget/android/bindings/Makefile.in | 1 + widget/android/bindings/moz.build | 3 ++- widget/android/nsScreenManagerAndroid.cpp | 15 ++++++++------- 7 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 widget/android/bindings/AndroidRect-classes.txt diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 2094c05a0f9c..fb514ad4876c 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -81,6 +81,7 @@ import android.graphics.RectF; import android.graphics.SurfaceTexture; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.hardware.display.DisplayManager; import android.hardware.Sensor; import android.hardware.SensorEventListener; import android.hardware.SensorManager; @@ -107,6 +108,7 @@ import android.util.Base64; import android.util.DisplayMetrics; import android.util.Log; import android.view.ContextThemeWrapper; +import android.view.Display; import android.view.HapticFeedbackConstants; import android.view.Surface; import android.view.SurfaceView; @@ -2671,4 +2673,15 @@ public class GeckoAppShell } return 0; } + + @WrapForJNI + static Rect getScreenSize() { + DisplayManager dm = (DisplayManager)getContext().getSystemService(Context.DISPLAY_SERVICE); + if (dm == null) { + return new Rect(0, 0, 0, 0); + } + + Display disp = dm.getDisplay(Display.DEFAULT_DISPLAY); + return new Rect(0, 0, disp.getWidth(), disp.getHeight()); + } } diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index 7664ce8deaf4..285cf4c8372b 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -393,6 +393,14 @@ auto GeckoAppShell::GetScreenOrientationWrapper() -> int16_t return mozilla::jni::Method::Call(nullptr, nullptr); } +constexpr char GeckoAppShell::GetScreenSize_t::name[]; +constexpr char GeckoAppShell::GetScreenSize_t::signature[]; + +auto GeckoAppShell::GetScreenSize() -> mozilla::jni::Object::LocalRef +{ + return mozilla::jni::Method::Call(nullptr, nullptr); +} + constexpr char GeckoAppShell::GetShowPasswordSetting_t::name[]; constexpr char GeckoAppShell::GetShowPasswordSetting_t::signature[]; diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index b77c60d5f434..1523c7588d70 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -944,6 +944,23 @@ public: static auto GetScreenOrientationWrapper() -> int16_t; +public: + struct GetScreenSize_t { + typedef GeckoAppShell Owner; + typedef mozilla::jni::Object::LocalRef ReturnType; + typedef mozilla::jni::Object::Param SetterType; + typedef mozilla::jni::Args<> Args; + static constexpr char name[] = "getScreenSize"; + static constexpr char signature[] = + "()Landroid/graphics/Rect;"; + static const bool isStatic = true; + static const bool isMultithreaded = false; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + + static auto GetScreenSize() -> mozilla::jni::Object::LocalRef; + public: struct GetShowPasswordSetting_t { typedef GeckoAppShell Owner; diff --git a/widget/android/bindings/AndroidRect-classes.txt b/widget/android/bindings/AndroidRect-classes.txt new file mode 100644 index 000000000000..cbacca81e1a4 --- /dev/null +++ b/widget/android/bindings/AndroidRect-classes.txt @@ -0,0 +1,2 @@ +android.graphics.Rect +android.graphics.RectF diff --git a/widget/android/bindings/Makefile.in b/widget/android/bindings/Makefile.in index c42ce48862d1..644c2e19688a 100644 --- a/widget/android/bindings/Makefile.in +++ b/widget/android/bindings/Makefile.in @@ -24,6 +24,7 @@ sdk_processor := \ # We'd like these to be defined in a future GENERATED_EXPORTS list. bindings_exports_FILES := \ + AndroidRect.h \ Bundle.h \ MediaCodec.h \ SurfaceTexture.h \ diff --git a/widget/android/bindings/moz.build b/widget/android/bindings/moz.build index 622e4f6394a6..a70bf79ac61a 100644 --- a/widget/android/bindings/moz.build +++ b/widget/android/bindings/moz.build @@ -7,9 +7,10 @@ # List of stems to generate .cpp and .h files for. To add a stem, add it to # this list and ensure that $(stem)-classes.txt exists in this directory. generated = [ + 'AndroidRect', 'Bundle', 'MediaCodec', - 'SurfaceTexture', + 'SurfaceTexture' ] SOURCES += ['!%s.cpp' % stem for stem in generated] diff --git a/widget/android/nsScreenManagerAndroid.cpp b/widget/android/nsScreenManagerAndroid.cpp index 4cc09728299b..9a8b3651fe79 100644 --- a/widget/android/nsScreenManagerAndroid.cpp +++ b/widget/android/nsScreenManagerAndroid.cpp @@ -8,6 +8,9 @@ #include "nsScreenManagerAndroid.h" #include "nsWindow.h" #include "AndroidBridge.h" +#include "GeneratedJNIWrappers.h" +#include "AndroidRect.h" +#include using namespace mozilla; @@ -29,13 +32,11 @@ nsScreenAndroid::GetId(uint32_t *outId) NS_IMETHODIMP nsScreenAndroid::GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) { - gfxIntSize sz = nsWindow::GetAndroidScreenBounds(); - - *outLeft = 0; - *outTop = 0; - - *outWidth = sz.width; - *outHeight = sz.height; + widget::sdk::Rect::LocalRef rect = widget::GeckoAppShell::GetScreenSize(); + rect->Left(outLeft); + rect->Top(outTop); + rect->Width(outWidth); + rect->Height(outHeight); return NS_OK; } From a80e13e6fe121b2450b551e76a1d582748ed53d4 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Fri, 28 Aug 2015 11:20:05 -0500 Subject: [PATCH 050/131] Bug 1182665 - Add gfxPlatform::CanUseDoubleBufferedContent() r=nical --- gfx/layers/client/ContentClient.cpp | 22 +--------------------- gfx/thebes/gfxPlatform.cpp | 28 ++++++++++++++++++++++++++++ gfx/thebes/gfxPlatform.h | 5 +++++ 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp index 1efa41da06af..4d02a90e0faa 100644 --- a/gfx/layers/client/ContentClient.cpp +++ b/gfx/layers/client/ContentClient.cpp @@ -69,27 +69,7 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder) return nullptr; } - bool useDoubleBuffering = false; - -#ifdef XP_WIN - if (backend == LayersBackend::LAYERS_D3D11) { - useDoubleBuffering = !!gfxWindowsPlatform::GetPlatform()->GetD3D10Device(); - } else -#endif -#ifdef MOZ_WIDGET_GTK - // We can't use double buffering when using image content with - // Xrender support on Linux, as ContentHostDoubleBuffered is not - // suited for direct uploads to the server. - if (!gfxPlatformGtk::GetPlatform()->UseImageOffscreenSurfaces() || - !gfxPlatformGtk::GetPlatform()->UseXRender()) -#endif - { - useDoubleBuffering = (LayerManagerComposite::SupportsDirectTexturing() && - backend != LayersBackend::LAYERS_D3D9) || - backend == LayersBackend::LAYERS_BASIC; - } - - if (useDoubleBuffering || PR_GetEnv("MOZ_FORCE_DOUBLE_BUFFERING")) { + if (gfxPlatform::GetPlatform()->CanUseDoubleBufferedContent(backend)) { return MakeAndAddRef(aForwarder); } return MakeAndAddRef(aForwarder); diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 698b488fb21e..9fbb056decdd 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -9,6 +9,7 @@ #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/SharedBufferManagerChild.h" #include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter +#include "mozilla/layers/LayerManagerComposite.h" #include "mozilla/Logging.h" #include "mozilla/Services.h" @@ -2301,6 +2302,33 @@ gfxPlatform::DisableBufferRotation() sBufferRotationCheckPref = false; } +bool +gfxPlatform::CanUseDoubleBufferedContent(LayersBackend aBackend) const +{ + bool useDoubleBuffering = false; + +#ifdef XP_WIN + if (aBackend == LayersBackend::LAYERS_D3D11) { + useDoubleBuffering = !!gfxWindowsPlatform::GetPlatform()->GetD3D10Device(); + } else +#endif +#ifdef MOZ_WIDGET_GTK + // We can't use double buffering when using image content with + // Xrender support on Linux, as ContentHostDoubleBuffered is not + // suited for direct uploads to the server. + if (!gfxPlatformGtk::GetPlatform()->UseImageOffscreenSurfaces() || + !gfxPlatformGtk::GetPlatform()->UseXRender()) +#endif + { + useDoubleBuffering = (LayerManagerComposite::SupportsDirectTexturing() && + aBackend != LayersBackend::LAYERS_D3D9) || + aBackend == LayersBackend::LAYERS_BASIC; + } + + return useDoubleBuffering || PR_GetEnv("MOZ_FORCE_DOUBLE_BUFFERING"); +} + + already_AddRefed gfxPlatform::GetScaledFontForFontWithCairoSkia(DrawTarget* aTarget, gfxFont* aFont) { diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 9e3e9415e6f3..156b50ed56ca 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -496,6 +496,11 @@ public: static bool BufferRotationEnabled(); static void DisableBufferRotation(); + /** + * Check to see if we should use double buffered content client + */ + bool CanUseDoubleBufferedContent(mozilla::layers::LayersBackend aBackend) const; + /** * Are we going to try color management? */ From ec43fd4643434b149b6159556aa382453e4c35a4 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Wed, 26 Aug 2015 17:33:16 -0500 Subject: [PATCH 051/131] Bug 1182665 - Adjust tile sizes depending on the screen size r=nical --- dom/ipc/ScreenManagerParent.cpp | 4 +++ gfx/thebes/gfxPlatform.cpp | 42 +++++++++----------------- mobile/android/base/GeckoAppShell.java | 7 +---- widget/gtk/nsScreenManagerGtk.cpp | 5 +++ 4 files changed, 25 insertions(+), 33 deletions(-) diff --git a/dom/ipc/ScreenManagerParent.cpp b/dom/ipc/ScreenManagerParent.cpp index 058709edeadf..ecf5a595b3be 100644 --- a/dom/ipc/ScreenManagerParent.cpp +++ b/dom/ipc/ScreenManagerParent.cpp @@ -169,6 +169,10 @@ ScreenManagerParent::RecvScreenForBrowser(const TabId& aTabId, bool ScreenManagerParent::ExtractScreenDetails(nsIScreen* aScreen, ScreenDetails &aDetails) { + if (!aScreen) { + return false; + } + uint32_t id; nsresult rv = aScreen->GetId(&id); NS_ENSURE_SUCCESS(rv, false); diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 9fbb056decdd..f76b8082e754 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -53,6 +53,7 @@ #include "gfxGraphiteShaper.h" #include "gfx2DGlue.h" #include "gfxGradientCache.h" +#include "gfxUtils.h" // for NextPowerOfTwo #include "nsUnicodeRange.h" #include "nsServiceManagerUtils.h" @@ -387,6 +388,7 @@ gfxPlatform::gfxPlatform() , mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureBackendInfo) , mApzSupportCollector(this, &gfxPlatform::GetApzSupportInfo) , mCompositorBackend(layers::LayersBackend::LAYERS_NONE) + , mScreenDepth(0) { mAllowDownloadableFonts = UNINITIALIZED_VALUE; mFallbackUsesCmaps = UNINITIALIZED_VALUE; @@ -1014,42 +1016,25 @@ gfxPlatform::ComputeTileSize() int32_t w = gfxPrefs::LayersTileWidth(); int32_t h = gfxPrefs::LayersTileHeight(); - // TODO We may want to take the screen size into consideration here. if (gfxPrefs::LayersTilesAdjust()) { + gfx::IntSize screenSize = GetScreenSize(); + if (screenSize.width > 0) { + w = h = std::max(std::min(NextPowerOfTwo(screenSize.width) / 2, 1024), 256); + } + #ifdef MOZ_WIDGET_GONK - int32_t format = android::PIXEL_FORMAT_RGBA_8888; android::sp alloc = - new android::GraphicBuffer(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight(), - format, - android::GraphicBuffer::USAGE_SW_READ_OFTEN | - android::GraphicBuffer::USAGE_SW_WRITE_OFTEN | - android::GraphicBuffer::USAGE_HW_TEXTURE); + new android::GraphicBuffer(w, h, android::PIXEL_FORMAT_RGBA_8888, + android::GraphicBuffer::USAGE_SW_READ_OFTEN | + android::GraphicBuffer::USAGE_SW_WRITE_OFTEN | + android::GraphicBuffer::USAGE_HW_TEXTURE); if (alloc.get()) { w = alloc->getStride(); // We want the tiles to be gralloc stride aligned. - // No need to adjust the height here. } #endif } -#ifdef XP_MACOSX - // Use double sized tiles for HiDPI screens. - nsCOMPtr screenManager = - do_GetService("@mozilla.org/gfx/screenmanager;1"); - if (screenManager) { - nsCOMPtr primaryScreen; - screenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen)); - double scaleFactor = 1.0; - if (primaryScreen) { - primaryScreen->GetContentsScaleFactor(&scaleFactor); - } - if (scaleFactor > 1.0) { - w *= 2; - h *= 2; - } - } -#endif - SetTileSize(w, h); } @@ -1061,7 +1046,10 @@ gfxPlatform::PopulateScreenInfo() nsCOMPtr screen; manager->GetPrimaryScreen(getter_AddRefs(screen)); - MOZ_ASSERT(screen, "failed to get primary screen"); + if (!screen) { + // This can happen in xpcshell, for instance + return; + } screen->GetColorDepth(&mScreenDepth); diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index fb514ad4876c..b8e9feaaa587 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -2676,12 +2676,7 @@ public class GeckoAppShell @WrapForJNI static Rect getScreenSize() { - DisplayManager dm = (DisplayManager)getContext().getSystemService(Context.DISPLAY_SERVICE); - if (dm == null) { - return new Rect(0, 0, 0, 0); - } - - Display disp = dm.getDisplay(Display.DEFAULT_DISPLAY); + Display disp = getGeckoInterface().getActivity().getWindowManager().getDefaultDisplay(); return new Rect(0, 0, disp.getWidth(), disp.getHeight()); } } diff --git a/widget/gtk/nsScreenManagerGtk.cpp b/widget/gtk/nsScreenManagerGtk.cpp index 8d8d8424d868..236748553d46 100644 --- a/widget/gtk/nsScreenManagerGtk.cpp +++ b/widget/gtk/nsScreenManagerGtk.cpp @@ -99,6 +99,11 @@ nsScreenManagerGtk :: EnsureInit() return NS_OK; mRootWindow = gdk_get_default_root_window(); + if (!mRootWindow) { + // Sometimes we don't initial X (e.g., xpcshell) + return NS_OK; + } + g_object_ref(mRootWindow); // GDK_PROPERTY_CHANGE_MASK ==> PropertyChangeMask, for PropertyNotify From ba7c467b33cdc4d2590ffa85fdd392a36a75e4a5 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Thu, 3 Sep 2015 11:43:09 -0500 Subject: [PATCH 052/131] Bug 1201541 - Use SingleTiledContentClient for non-scrollable layers on Android r=mattwoodrow --- gfx/layers/client/ClientTiledPaintedLayer.cpp | 9 +-------- layout/base/FrameLayerBuilder.cpp | 3 --- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/gfx/layers/client/ClientTiledPaintedLayer.cpp b/gfx/layers/client/ClientTiledPaintedLayer.cpp index 8de49052dd43..c9b59e00b9f4 100644 --- a/gfx/layers/client/ClientTiledPaintedLayer.cpp +++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp @@ -411,12 +411,9 @@ ClientTiledPaintedLayer::RenderLayer() void *data = ClientManager()->GetPaintedLayerCallbackData(); if (!mContentClient) { -#if defined(MOZ_B2G) || defined(XP_MACOSX) if (mCreationHint == LayerManager::NONE) { mContentClient = new SingleTiledContentClient(this, ClientManager()); - } else -#endif - { + } else { mContentClient = new MultiTiledContentClient(this, ClientManager()); } @@ -560,7 +557,6 @@ ClientTiledPaintedLayer::RenderLayer() bool ClientTiledPaintedLayer::IsOptimizedFor(LayerManager::PaintedLayerCreationHint aHint) { -#if defined(MOZ_B2G) || defined(XP_MACOSX) // The only creation hint is whether the layer is scrollable or not, and this // is only respected on B2G and OSX, where it's used to determine whether to // use a tiled content client or not. @@ -568,9 +564,6 @@ ClientTiledPaintedLayer::IsOptimizedFor(LayerManager::PaintedLayerCreationHint a // large, scrollable layers, so we want the layer to be recreated in this // situation. return aHint == GetCreationHint(); -#else - return true; -#endif } void diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 8f7ceaa04edd..0764089c6199 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -2040,9 +2040,6 @@ ContainerState::GetLayerCreationHint(const nsIFrame* aAnimatedGeometryRoot) { // Check whether the layer will be scrollable. This is used as a hint to // influence whether tiled layers are used or not. - if (mParameters.mInLowPrecisionDisplayPort) { - return LayerManager::SCROLLABLE; - } nsIFrame* animatedGeometryRootParent = aAnimatedGeometryRoot->GetParent(); nsIScrollableFrame* scrollable = do_QueryFrame(animatedGeometryRootParent); if (scrollable From d203f90a3e00f3bf505d92873bc680670233d138 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Thu, 3 Sep 2015 15:47:22 -0500 Subject: [PATCH 053/131] Bug 1182665 - Don't try to call JNI methods in nsScreenManagerAndroid if it's not available r=esawin --- widget/android/nsScreenManagerAndroid.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/widget/android/nsScreenManagerAndroid.cpp b/widget/android/nsScreenManagerAndroid.cpp index 9a8b3651fe79..f661bc77edca 100644 --- a/widget/android/nsScreenManagerAndroid.cpp +++ b/widget/android/nsScreenManagerAndroid.cpp @@ -32,6 +32,12 @@ nsScreenAndroid::GetId(uint32_t *outId) NS_IMETHODIMP nsScreenAndroid::GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) { + if (!mozilla::jni::IsAvailable()) { + // xpcshell most likely + *outLeft = *outTop = *outWidth = *outHeight = 0; + return NS_ERROR_FAILURE; + } + widget::sdk::Rect::LocalRef rect = widget::GeckoAppShell::GetScreenSize(); rect->Left(outLeft); rect->Top(outTop); @@ -53,7 +59,13 @@ nsScreenAndroid::GetAvailRect(int32_t *outLeft, int32_t *outTop, int32_t *outWid NS_IMETHODIMP nsScreenAndroid::GetPixelDepth(int32_t *aPixelDepth) { - *aPixelDepth = AndroidBridge::Bridge()->GetScreenDepth(); + if (!mozilla::jni::IsAvailable()) { + // xpcshell most likely + *aPixelDepth = 16; + return NS_ERROR_FAILURE; + } + + *aPixelDepth = widget::GeckoAppShell::GetScreenDepthWrapper(); return NS_OK; } @@ -67,7 +79,9 @@ nsScreenAndroid::GetColorDepth(int32_t *aColorDepth) void nsScreenAndroid::ApplyMinimumBrightness(uint32_t aBrightness) { - widget::GeckoAppShell::SetKeepScreenOn(aBrightness == BRIGHTNESS_FULL); + if (mozilla::jni::IsAvailable()) { + widget::GeckoAppShell::SetKeepScreenOn(aBrightness == BRIGHTNESS_FULL); + } } NS_IMPL_ISUPPORTS(nsScreenManagerAndroid, nsIScreenManager) From d06b91de484fd0cee28ef17129731abfa4b009c4 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Thu, 3 Sep 2015 16:00:53 -0500 Subject: [PATCH 054/131] Bug 1148131 - Enable DrawTargetTiled on Android r=Bas --- gfx/tests/reftest/reftest.list | 4 ++-- layout/reftests/text-overflow/reftest.list | 2 +- modules/libpref/init/all.js | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/gfx/tests/reftest/reftest.list b/gfx/tests/reftest/reftest.list index c9eed7b0c2d0..95303aa33727 100644 --- a/gfx/tests/reftest/reftest.list +++ b/gfx/tests/reftest/reftest.list @@ -4,5 +4,5 @@ fuzzy-if(winWidget,175,443) == 611498-1.html 611498-ref.html skip-if(B2G) fuzzy-if(Android&&AndroidVersion>=15,8,1000) == 709477-1.html 709477-1-ref.html # bug 773482 skip-if(!asyncPan) == 1086723.html 1086723-ref.html == 853889-1.html 853889-1-ref.html -== 1143303-1.svg pass.svg -fuzzy(100,30) == 1149923.html 1149923-ref.html # use fuzzy due to few distorted pixels caused by border-radius \ No newline at end of file +skip-if(Android) == 1143303-1.svg pass.svg +fuzzy(100,30) == 1149923.html 1149923-ref.html # use fuzzy due to few distorted pixels caused by border-radius diff --git a/layout/reftests/text-overflow/reftest.list b/layout/reftests/text-overflow/reftest.list index 42313a5faee2..9978c6b6e445 100644 --- a/layout/reftests/text-overflow/reftest.list +++ b/layout/reftests/text-overflow/reftest.list @@ -4,7 +4,7 @@ fuzzy-if(Android,16,244) skip-if(B2G||Mulet) HTTP(..) == marker-basic.html marke skip-if(B2G||Mulet) HTTP(..) == marker-string.html marker-string-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(Android||B2G) HTTP(..) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing skip-if(!gtkWidget) fuzzy-if(gtkWidget,2,289) HTTP(..) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing -skip-if(B2G||Mulet) fuzzy-if(Android&&AndroidVersion<15,9,2545) fuzzy-if(Android&&AndroidVersion>=15,24,4000) fuzzy-if(cocoaWidget,1,40) fuzzy-if(asyncPan&&!layersGPUAccelerated,102,1770) HTTP(..) == scroll-rounding.html scroll-rounding-ref.html # bug 760264 # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet) fuzzy-if(Android&&AndroidVersion<15,206,41) fuzzy-if(Android&&AndroidVersion>=15,24,4000) fuzzy-if(cocoaWidget,1,40) fuzzy-if(asyncPan&&!layersGPUAccelerated,102,1770) HTTP(..) == scroll-rounding.html scroll-rounding-ref.html # bug 760264 # Initial mulet triage: parity with B2G/B2G Desktop fuzzy-if(OSX==1008,1,1) HTTP(..) == anonymous-block.html anonymous-block-ref.html skip-if(B2G||Mulet) HTTP(..) == false-marker-overlap.html false-marker-overlap-ref.html # Initial mulet triage: parity with B2G/B2G Desktop HTTP(..) == visibility-hidden.html visibility-hidden-ref.html diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index fa1a6c5c4d9b..ec93faa95219 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4280,6 +4280,11 @@ pref("layers.tiles.edge-padding", false); pref("layers.tiled-drawtarget.enabled", true); #endif +#ifdef MOZ_WIDGET_ANDROID +pref("layers.tiled-drawtarget.enabled", true); +pref("layers.tiles.edge-padding", true); +#endif + // same effect as layers.offmainthreadcomposition.enabled, but specifically for // use with tests. pref("layers.offmainthreadcomposition.testing.enabled", false); From 827acb829b30386f2b485c39d71a899cdabdf9ae Mon Sep 17 00:00:00 2001 From: James Willcox Date: Fri, 4 Sep 2015 15:21:37 -0500 Subject: [PATCH 055/131] Bug 1178376 - Put progressive paint status in tile updates r=nical --- gfx/layers/client/SingleTiledContentClient.cpp | 9 +++++++-- gfx/layers/client/SingleTiledContentClient.h | 4 +++- gfx/layers/client/TiledContentClient.cpp | 9 ++++++--- gfx/layers/client/TiledContentClient.h | 9 +++++++-- gfx/layers/ipc/LayersMessages.ipdlh | 1 + 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/gfx/layers/client/SingleTiledContentClient.cpp b/gfx/layers/client/SingleTiledContentClient.cpp index b195fd9abfd0..ec5b15b43339 100644 --- a/gfx/layers/client/SingleTiledContentClient.cpp +++ b/gfx/layers/client/SingleTiledContentClient.cpp @@ -45,6 +45,7 @@ ClientSingleTiledLayerBuffer::ClientSingleTiledLayerBuffer(ClientTiledPaintedLay ClientLayerManager* aManager) : ClientTiledLayerBuffer(aPaintedLayer, aCompositableClient) , mManager(aManager) + , mWasLastPaintProgressive(false) { } @@ -89,7 +90,8 @@ ClientSingleTiledLayerBuffer::GetSurfaceDescriptorTiles() 0, 0, 1, 1, 1.0, mFrameResolution.xScale, - mFrameResolution.yScale); + mFrameResolution.yScale, + mWasLastPaintProgressive); } already_AddRefed @@ -105,8 +107,11 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData) + void* aCallbackData, + bool aIsProgressive) { + mWasLastPaintProgressive = aIsProgressive; + // Compare layer visible region size to current backbuffer size, discard if not matching. IntSize size = mPaintedLayer->GetVisibleRegion().GetBounds().Size(); IntPoint origin = mPaintedLayer->GetVisibleRegion().GetBounds().TopLeft(); diff --git a/gfx/layers/client/SingleTiledContentClient.h b/gfx/layers/client/SingleTiledContentClient.h index 33a01c5c44cc..c3d84618f772 100644 --- a/gfx/layers/client/SingleTiledContentClient.h +++ b/gfx/layers/client/SingleTiledContentClient.h @@ -41,7 +41,8 @@ public: const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData) override; + void* aCallbackData, + bool aIsProgressive = false) override; bool SupportsProgressiveUpdate() override { return false; } bool ProgressiveUpdate(nsIntRegion& aValidRegion, @@ -88,6 +89,7 @@ private: nsIntRegion mPaintedRegion; nsIntRegion mValidRegion; + bool mWasLastPaintProgressive; /** * While we're adding tiles, this is used to keep track of the position of diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index 861cfc065cca..95220a82d6c3 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -905,7 +905,8 @@ ClientMultiTiledLayerBuffer::GetSurfaceDescriptorTiles() mTiles.mFirst.x, mTiles.mFirst.y, mTiles.mSize.width, mTiles.mSize.height, mResolution, mFrameResolution.xScale, - mFrameResolution.yScale); + mFrameResolution.yScale, + mWasLastPaintProgressive); } void @@ -913,13 +914,15 @@ ClientMultiTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData) + void* aCallbackData, + bool aIsProgressive) { TILING_LOG("TILING %p: PaintThebes painting region %s\n", mPaintedLayer, Stringify(aPaintRegion).c_str()); TILING_LOG("TILING %p: PaintThebes new valid region %s\n", mPaintedLayer, Stringify(aNewValidRegion).c_str()); mCallback = aCallback; mCallbackData = aCallbackData; + mWasLastPaintProgressive = aIsProgressive; #ifdef GFX_TILEDLAYER_PREF_WARNINGS long start = PR_IntervalNow(); @@ -1653,7 +1656,7 @@ ClientMultiTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion, // Paint the computed region and subtract it from the invalid region. PaintThebes(validOrStale, regionToPaint, aInvalidRegion, - aCallback, aCallbackData); + aCallback, aCallbackData, true); aInvalidRegion.Sub(aInvalidRegion, regionToPaint); } while (repeat); diff --git a/gfx/layers/client/TiledContentClient.h b/gfx/layers/client/TiledContentClient.h index 1ce96533a265..d5a4169245f3 100644 --- a/gfx/layers/client/TiledContentClient.h +++ b/gfx/layers/client/TiledContentClient.h @@ -407,13 +407,15 @@ public: , mCompositableClient(aCompositableClient) , mLastPaintContentType(gfxContentType::COLOR) , mLastPaintSurfaceMode(SurfaceMode::SURFACE_OPAQUE) + , mWasLastPaintProgressive(false) {} virtual void PaintThebes(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData) = 0; + void* aCallbackData, + bool aIsProgressive = false) = 0; virtual bool SupportsProgressiveUpdate() = 0; virtual bool ProgressiveUpdate(nsIntRegion& aValidRegion, @@ -447,6 +449,8 @@ protected: gfxContentType mLastPaintContentType; SurfaceMode mLastPaintSurfaceMode; CSSToParentLayerScale2D mFrameResolution; + + bool mWasLastPaintProgressive; }; class ClientMultiTiledLayerBuffer @@ -473,7 +477,8 @@ public: const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData) override; + void* aCallbackData, + bool aIsProgressive = false) override; virtual bool SupportsProgressiveUpdate() override { return true; } /** diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index 091b0a03e141..63794143b6e6 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -341,6 +341,7 @@ struct SurfaceDescriptorTiles { float resolution; float frameXResolution; float frameYResolution; + bool isProgressive; }; struct OpUseTiledLayerBuffer { From 55d33074aae6ad26845bbdf0913825bc33079d06 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Fri, 4 Sep 2015 15:29:29 -0500 Subject: [PATCH 056/131] Bug 1178376 - Allow progressive painting when low-precision tiles are disabled r=BenWa --- gfx/layers/client/ClientTiledPaintedLayer.cpp | 22 +++++++++---------- gfx/layers/client/TiledContentClient.cpp | 1 + gfx/layers/client/TiledContentClient.h | 5 +++++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/gfx/layers/client/ClientTiledPaintedLayer.cpp b/gfx/layers/client/ClientTiledPaintedLayer.cpp index c9b59e00b9f4..234c19e9ba91 100644 --- a/gfx/layers/client/ClientTiledPaintedLayer.cpp +++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp @@ -169,7 +169,8 @@ ClientTiledPaintedLayer::BeginPaint() // on this layer. If there is an OMT animation then we need to draw the whole // visible region of this layer as determined by layout, because we don't know // what parts of it might move into view in the compositor. - if (!hasTransformAnimation && + mPaintData.mHasTransformAnimation = hasTransformAnimation; + if (!mPaintData.mHasTransformAnimation && mContentClient->GetLowPrecisionTiledBuffer()) { ParentLayerRect criticalDisplayPort = (displayportMetrics.GetCriticalDisplayPort() * displayportMetrics.GetZoom()) @@ -256,15 +257,6 @@ ClientTiledPaintedLayer::UseProgressiveDraw() { return false; } - if (mPaintData.mCriticalDisplayPort.IsEmpty()) { - // This catches three scenarios: - // 1) This layer doesn't have a scrolling ancestor - // 2) This layer is subject to OMTA transforms - // 3) Low-precision painting is disabled - // In all of these cases, we don't want to draw this layer progressively. - return false; - } - if (GetIsFixedPosition() || GetParent()->GetIsFixedPosition()) { // This layer is fixed-position and so even if it does have a scrolling // ancestor it will likely be entirely on-screen all the time, so we @@ -272,10 +264,18 @@ ClientTiledPaintedLayer::UseProgressiveDraw() { return false; } + if (mPaintData.mHasTransformAnimation) { + // The compositor is going to animate this somehow, so we want it all + // on the screen at once. + return false; + } + if (ClientManager()->AsyncPanZoomEnabled()) { LayerMetricsWrapper scrollAncestor; GetAncestorLayers(&scrollAncestor, nullptr, nullptr); - MOZ_ASSERT(scrollAncestor); // because mPaintData.mCriticalDisplayPort is non-empty + if (!scrollAncestor) { + return false; + } const FrameMetrics& parentMetrics = scrollAncestor.Metrics(); if (!IsScrollingOnCompositor(parentMetrics)) { return false; diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index 95220a82d6c3..d93c604d278d 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -1695,6 +1695,7 @@ BasicTiledLayerPaintData::ResetPaintData() { mLowPrecisionPaintCount = 0; mPaintFinished = false; + mHasTransformAnimation = false; mCompositionBounds.SetEmpty(); mCriticalDisplayPort.SetEmpty(); } diff --git a/gfx/layers/client/TiledContentClient.h b/gfx/layers/client/TiledContentClient.h index d5a4169245f3..2a68e20dd56b 100644 --- a/gfx/layers/client/TiledContentClient.h +++ b/gfx/layers/client/TiledContentClient.h @@ -353,6 +353,11 @@ struct BasicTiledLayerPaintData { */ bool mPaintFinished : 1; + /* + * Whether or not there is an async transform animation active + */ + bool mHasTransformAnimation : 1; + /* * Initializes/clears data to prepare for paint action. */ From fd1ffff272486fb008d7c54c9472a30ac325107f Mon Sep 17 00:00:00 2001 From: James Willcox Date: Tue, 8 Sep 2015 09:24:16 -0500 Subject: [PATCH 057/131] Bug 1178376 - Optionally fade in new progressively painted tiles r=nical --- gfx/layers/Layers.h | 2 +- gfx/layers/client/TiledContentClient.cpp | 20 +++--- gfx/layers/client/TiledContentClient.h | 1 + gfx/layers/composite/ContentHost.h | 2 + .../composite/PaintedLayerComposite.cpp | 11 +++ gfx/layers/composite/PaintedLayerComposite.h | 2 + gfx/layers/composite/TiledContentHost.cpp | 69 ++++++++++++++++++- gfx/layers/composite/TiledContentHost.h | 13 ++++ gfx/layers/ipc/LayersMessages.ipdlh | 1 + gfx/thebes/gfxPrefs.h | 2 + 10 files changed, 112 insertions(+), 11 deletions(-) diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 1409837157fd..087c0adb8ece 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -1593,7 +1593,7 @@ public: * Returns the current area of the layer (in layer-space coordinates) * marked as needed to be recomposited. */ - const nsIntRegion& GetInvalidRegion() { return mInvalidRegion; } + const virtual nsIntRegion GetInvalidRegion() { return mInvalidRegion; } const void SetInvalidRegion(const nsIntRegion& aRect) { mInvalidRegion = aRect; } /** diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index d93c604d278d..92b1a29b6bc9 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -497,7 +497,7 @@ TileClient::PrivateProtector::Set(TileClient * const aContainer, TextureClient* // Placeholder TileClient::TileClient() - : mCompositableClient(nullptr) + : mCompositableClient(nullptr), mWasPlaceholder(false) { } @@ -518,6 +518,7 @@ TileClient::TileClient(const TileClient& o) mBackLock = o.mBackLock; mFrontLock = o.mFrontLock; mCompositableClient = o.mCompositableClient; + mWasPlaceholder = o.mWasPlaceholder; mUpdateRect = o.mUpdateRect; #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY mLastUpdate = o.mLastUpdate; @@ -539,6 +540,7 @@ TileClient::operator=(const TileClient& o) mBackLock = o.mBackLock; mFrontLock = o.mFrontLock; mCompositableClient = o.mCompositableClient; + mWasPlaceholder = o.mWasPlaceholder; mUpdateRect = o.mUpdateRect; #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY mLastUpdate = o.mLastUpdate; @@ -842,9 +844,12 @@ TileDescriptor TileClient::GetTileDescriptor() { if (IsPlaceholderTile()) { + mWasPlaceholder = true; return PlaceholderTileDescriptor(); } MOZ_ASSERT(mFrontLock); + bool wasPlaceholder = mWasPlaceholder; + mWasPlaceholder = false; if (mFrontLock->GetType() == gfxSharedReadLock::TYPE_MEMORY) { // AddRef here and Release when receiving on the host side to make sure the // reference count doesn't go to zero before the host receives the message. @@ -856,13 +861,15 @@ TileClient::GetTileDescriptor() return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(), mFrontBufferOnWhite ? MaybeTexture(mFrontBufferOnWhite->GetIPDLActor()) : MaybeTexture(null_t()), mUpdateRect, - TileLock(uintptr_t(mFrontLock.get()))); + TileLock(uintptr_t(mFrontLock.get())), + wasPlaceholder); } else { gfxShmSharedReadLock *lock = static_cast(mFrontLock.get()); return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(), mFrontBufferOnWhite ? MaybeTexture(mFrontBufferOnWhite->GetIPDLActor()) : MaybeTexture(null_t()), mUpdateRect, - TileLock(lock->GetShmemSection())); + TileLock(lock->GetShmemSection()), + wasPlaceholder); } } @@ -889,12 +896,7 @@ ClientMultiTiledLayerBuffer::GetSurfaceDescriptorTiles() InfallibleTArray tiles; for (TileClient& tile : mRetainedTiles) { - TileDescriptor tileDesc; - if (tile.IsPlaceholderTile()) { - tileDesc = PlaceholderTileDescriptor(); - } else { - tileDesc = tile.GetTileDescriptor(); - } + TileDescriptor tileDesc = tile.GetTileDescriptor(); tiles.AppendElement(tileDesc); // Reset the update rect tile.mUpdateRect = IntRect(); diff --git a/gfx/layers/client/TiledContentClient.h b/gfx/layers/client/TiledContentClient.h index 2a68e20dd56b..b63dabc6680d 100644 --- a/gfx/layers/client/TiledContentClient.h +++ b/gfx/layers/client/TiledContentClient.h @@ -275,6 +275,7 @@ struct TileClient RefPtr mAllocator; gfx::IntRect mUpdateRect; CompositableClient* mCompositableClient; + bool mWasPlaceholder; #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY TimeStamp mLastUpdate; #endif diff --git a/gfx/layers/composite/ContentHost.h b/gfx/layers/composite/ContentHost.h index 544236fb487d..3f1550ff5775 100644 --- a/gfx/layers/composite/ContentHost.h +++ b/gfx/layers/composite/ContentHost.h @@ -61,6 +61,8 @@ public: virtual void SetPaintWillResample(bool aResample) { mPaintWillResample = aResample; } bool PaintWillResample() { return mPaintWillResample; } + virtual void InvalidateForAnimation(nsIntRegion& aRegion) { } + protected: explicit ContentHost(const TextureInfo& aTextureInfo) : CompositableHost(aTextureInfo) diff --git a/gfx/layers/composite/PaintedLayerComposite.cpp b/gfx/layers/composite/PaintedLayerComposite.cpp index 476b88e182ea..725218d1a14c 100644 --- a/gfx/layers/composite/PaintedLayerComposite.cpp +++ b/gfx/layers/composite/PaintedLayerComposite.cpp @@ -179,5 +179,16 @@ PaintedLayerComposite::PrintInfo(std::stringstream& aStream, const char* aPrefix } } +const nsIntRegion +PaintedLayerComposite::GetInvalidRegion() +{ + nsIntRegion region = mInvalidRegion; + if (mBuffer) { + mBuffer->InvalidateForAnimation(region); + } + return region; +} + + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/composite/PaintedLayerComposite.h b/gfx/layers/composite/PaintedLayerComposite.h index c4107d6a9b20..39fa6fd0dbb6 100644 --- a/gfx/layers/composite/PaintedLayerComposite.h +++ b/gfx/layers/composite/PaintedLayerComposite.h @@ -73,6 +73,8 @@ public: Mutated(); } + const virtual nsIntRegion GetInvalidRegion() override; + MOZ_LAYER_DECL_NAME("PaintedLayerComposite", TYPE_PAINTED) protected: diff --git a/gfx/layers/composite/TiledContentHost.cpp b/gfx/layers/composite/TiledContentHost.cpp index f876970bcc53..1cf4f1bc82e9 100644 --- a/gfx/layers/composite/TiledContentHost.cpp +++ b/gfx/layers/composite/TiledContentHost.cpp @@ -10,6 +10,7 @@ #include "mozilla/gfx/Matrix.h" // for Matrix4x4 #include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/layers/Compositor.h" // for Compositor +#include "mozilla/layers/CompositorParent.h" // for CompositorParent #include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL @@ -28,6 +29,26 @@ namespace layers { class Layer; +float +TileHost::GetFadeInOpacity(float aOpacity) +{ + TimeStamp now = TimeStamp::Now(); + if (!gfxPrefs::LayerTileFadeInEnabled() || + mFadeStart.IsNull() || + now < mFadeStart) + { + return aOpacity; + } + + float duration = gfxPrefs::LayerTileFadeInDuration(); + float elapsed = (now - mFadeStart).ToMilliseconds(); + if (elapsed > duration) { + mFadeStart = TimeStamp(); + return aOpacity; + } + return aOpacity * (elapsed / duration); +} + TiledLayerBufferComposite::TiledLayerBufferComposite() : mFrameResolution() {} @@ -56,6 +77,21 @@ TiledLayerBufferComposite::SetCompositor(Compositor* aCompositor) } } +void +TiledLayerBufferComposite::InvalidateForAnimation(nsIntRegion& aRegion) +{ + // We need to invalidate rects where we have a tile that is in the + // process of fading in. + for (size_t i = 0; i < mRetainedTiles.Length(); i++) { + if (!mRetainedTiles[i].mFadeStart.IsNull()) { + TileIntPoint position = mTiles.TilePosition(i); + IntPoint offset = GetTileOffset(position); + nsIntRegion tileRegion = IntRect(offset, GetScaledTileSize()); + aRegion.OrWith(tileRegion); + } + } +} + TiledContentHost::TiledContentHost(const TextureInfo& aTextureInfo) : ContentHost(aTextureInfo) , mTiledBuffer(TiledLayerBufferComposite()) @@ -233,6 +269,14 @@ public: } } + void RecycleTileFading(TileHost& aTile) { + for (size_t i = 0; i < mTiles.Length(); i++) { + if (mTiles[i].mTextureHost == aTile.mTextureHost) { + aTile.mFadeStart = mTiles[i].mFadeStart; + } + } + } + protected: nsTArray mTiles; size_t mFirstPossibility; @@ -310,6 +354,20 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles, // If this same tile texture existed in the old tile set then this will move the texture // source into our new tile. oldRetainedTiles.RecycleTextureSourceForTile(tile); + + // If this tile is in the process of fading, we need to keep that going + oldRetainedTiles.RecycleTileFading(tile); + + if (aTiles.isProgressive() && + texturedDesc.wasPlaceholder()) + { + // This is a progressive paint, and the tile used to be a placeholder. + // We need to begin fading it in (if enabled via layers.tiles.fade-in.enabled) + tile.mFadeStart = TimeStamp::Now(); + + aCompositor->CompositeUntil(tile.mFadeStart + + TimeDuration::FromMilliseconds(gfxPrefs::LayerTileFadeInDuration())); + } } // Step 3, attempt to recycle unused texture sources from the old tile set into new tiles. @@ -487,6 +545,8 @@ TiledContentHost::RenderTile(TileHost& aTile, return; } + float opacity = aTile.GetFadeInOpacity(aOpacity); + aEffectChain.mPrimaryEffect = effect; nsIntRegionRectIterator it(aScreenRegion); @@ -499,7 +559,7 @@ TiledContentHost::RenderTile(TileHost& aTile, textureRect.y / aTextureBounds.height, textureRect.width / aTextureBounds.width, textureRect.height / aTextureBounds.height); - mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, aOpacity, aTransform, aVisibleRect); + mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, opacity, aTransform, aVisibleRect); } DiagnosticFlags flags = DiagnosticFlags::CONTENT | DiagnosticFlags::TILE; if (aTile.mTextureHostOnWhite) { @@ -634,5 +694,12 @@ TiledContentHost::Dump(std::stringstream& aStream, mTiledBuffer.Dump(aStream, aPrefix, aDumpHtml); } +void +TiledContentHost::InvalidateForAnimation(nsIntRegion& aRegion) +{ + return mTiledBuffer.InvalidateForAnimation(aRegion); +} + + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/composite/TiledContentHost.h b/gfx/layers/composite/TiledContentHost.h index 1291fb1a0b85..f74433def407 100644 --- a/gfx/layers/composite/TiledContentHost.h +++ b/gfx/layers/composite/TiledContentHost.h @@ -113,6 +113,14 @@ public: CompositableHost::DumpTextureHost(aStream, mTextureHost); } + /** + * This does a linear tween of the passed opacity (which is assumed + * to be between 0.0 and 1.0). The duration of the fade is controlled + * by the 'layers.tiles.fade-in.duration-ms' preference. It is enabled + * via 'layers.tiles.fade-in.enabled' + */ + float GetFadeInOpacity(float aOpacity); + RefPtr mSharedLock; CompositableTextureHostRef mTextureHost; CompositableTextureHostRef mTextureHostOnWhite; @@ -120,6 +128,7 @@ public: mutable CompositableTextureSourceRef mTextureSourceOnWhite; // This is not strictly necessary but makes debugging whole lot easier. TileIntPoint mTilePosition; + TimeStamp mFadeStart; }; class TiledLayerBufferComposite @@ -152,6 +161,8 @@ public: // Used when TiledContentClient is present in client side. static void RecycleCallback(TextureHost* textureHost, void* aClosure); + void InvalidateForAnimation(nsIntRegion& aRegion); + protected: CSSToParentLayerScale2D mFrameResolution; @@ -267,6 +278,8 @@ public: virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override; + virtual void InvalidateForAnimation(nsIntRegion& aRegion) override; + private: void RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer, diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index 63794143b6e6..16563e4691c5 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -319,6 +319,7 @@ struct TexturedTileDescriptor { MaybeTexture textureOnWhite; IntRect updateRect; TileLock sharedLock; + bool wasPlaceholder; }; struct PlaceholderTileDescriptor { diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index 50d60d4f7fa7..ac3012b6ffd8 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -352,6 +352,8 @@ private: DECL_GFX_PREF(Once, "layers.tiled-drawtarget.enabled", TiledDrawTargetEnabled, bool, false); DECL_GFX_PREF(Once, "layers.tiles.adjust", LayersTilesAdjust, bool, true); DECL_GFX_PREF(Once, "layers.tiles.edge-padding", TileEdgePaddingEnabled, bool, true); + DECL_GFX_PREF(Live, "layers.tiles.fade-in.enabled", LayerTileFadeInEnabled, bool, false); + DECL_GFX_PREF(Live, "layers.tiles.fade-in.duration-ms", LayerTileFadeInDuration, uint32_t, 100); DECL_GFX_PREF(Live, "layers.transaction.warning-ms", LayerTransactionWarning, uint32_t, 200); DECL_GFX_PREF(Once, "layers.uniformity-info", UniformityInfo, bool, false); DECL_GFX_PREF(Once, "layers.use-image-offscreen-surfaces", UseImageOffscreenSurfaces, bool, false); From 3f7b44f628921bab367811d0c24ba4850529cf2b Mon Sep 17 00:00:00 2001 From: Christian Holler Date: Fri, 11 Sep 2015 16:11:56 +0200 Subject: [PATCH 058/131] Bug 1199203 - Add support for per-thread OOM testing. r=jonco --- js/public/Utility.h | 56 +++++++++++++++++++++++++++-- js/src/builtin/TestingFunctions.cpp | 56 ++++++++++++++++++++++------- js/src/jsapi.cpp | 6 ++++ js/src/jsutil.cpp | 26 +++++++++++++- js/src/vm/HelperThreads.cpp | 21 +++++++---- 5 files changed, 143 insertions(+), 22 deletions(-) diff --git a/js/public/Utility.h b/js/public/Utility.h index d0e5c33a3402..4d91aa8324e7 100644 --- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -62,6 +62,46 @@ JS_Assert(const char* s, const char* file, int ln); #if defined JS_USE_CUSTOM_ALLOCATOR # include "jscustomallocator.h" #else + +namespace js { +namespace oom { + +/* + * To make testing OOM in certain helper threads more effective, + * allow restricting the OOM testing to a certain helper thread + * type. This allows us to fail e.g. in off-thread script parsing + * without causing an OOM in the main thread first. + */ +enum ThreadType { + THREAD_TYPE_NONE, // 0 + THREAD_TYPE_MAIN, // 1 + THREAD_TYPE_ASMJS, // 2 + THREAD_TYPE_ION, // 3 + THREAD_TYPE_PARSE, // 4 + THREAD_TYPE_COMPRESS, // 5 + THREAD_TYPE_GCHELPER, // 6 + THREAD_TYPE_GCPARALLEL, // 7 + THREAD_TYPE_MAX // Used to check shell function arguments +}; + + +/* + * Getter/Setter functions to encapsulate mozilla::ThreadLocal, + * implementation is in jsutil.cpp. + */ +# if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) +extern bool InitThreadType(void); +extern void SetThreadType(ThreadType); +extern uint32_t GetThreadType(void); +# else +inline bool InitThreadType(void) { return true; } +inline void SetThreadType(ThreadType t) {}; +inline uint32_t GetThreadType(void) { return 0; } +# endif + +} /* namespace oom */ +} /* namespace js */ + # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) /* @@ -83,16 +123,28 @@ static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); } namespace js { namespace oom { +extern JS_PUBLIC_DATA(uint32_t) targetThread; + +static inline bool +OOMThreadCheck() +{ + return (!js::oom::targetThread + || js::oom::targetThread == js::oom::GetThreadType()); +} + static inline bool IsSimulatedOOMAllocation() { - return OOM_counter == OOM_maxAllocations || - (OOM_counter > OOM_maxAllocations && OOM_failAlways); + return OOMThreadCheck() && (OOM_counter == OOM_maxAllocations || + (OOM_counter > OOM_maxAllocations && OOM_failAlways)); } static inline bool ShouldFailWithOOM() { + if (!OOMThreadCheck()) + return false; + OOM_counter++; if (IsSimulatedOOMAllocation()) { JS_OOM_CALL_BP_FUNC(); diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 64308da6f1ce..e20fd269b3df 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -987,15 +987,30 @@ static bool OOMAfterAllocations(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() != 1) { + if (args.length() < 1) { JS_ReportError(cx, "count argument required"); return false; } - uint32_t count; - if (!JS::ToUint32(cx, args[0], &count)) + if (args.length() > 2) { + JS_ReportError(cx, "too many arguments"); + return false; + } + + uint32_t targetThread = 0; + if (!ToUint32(cx, args.get(1), &targetThread)) return false; + if (targetThread >= js::oom::THREAD_TYPE_MAX) { + JS_ReportError(cx, "invalid thread type specified"); + return false; + } + + uint32_t count; + if (!JS::ToUint32(cx, args.get(0), &count)) + return false; + + js::oom::targetThread = targetThread; OOM_maxAllocations = OOM_counter + count; OOM_failAlways = true; return true; @@ -1005,15 +1020,30 @@ static bool OOMAtAllocation(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() != 1) { + if (args.length() < 1) { JS_ReportError(cx, "count argument required"); return false; } - uint32_t count; - if (!JS::ToUint32(cx, args[0], &count)) + if (args.length() > 2) { + JS_ReportError(cx, "too many arguments"); + return false; + } + + uint32_t targetThread = 0; + if (!ToUint32(cx, args.get(1), &targetThread)) return false; + if (targetThread >= js::oom::THREAD_TYPE_MAX) { + JS_ReportError(cx, "invalid thread type specified"); + return false; + } + + uint32_t count; + if (!JS::ToUint32(cx, args.get(0), &count)) + return false; + + js::oom::targetThread = targetThread; OOM_maxAllocations = OOM_counter + count; OOM_failAlways = false; return true; @@ -2832,15 +2862,17 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = { " Stop capturing the JS stack at every allocation."), #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) - JS_FN_HELP("oomAfterAllocations", OOMAfterAllocations, 1, 0, -"oomAfterAllocations(count)", + JS_FN_HELP("oomAfterAllocations", OOMAfterAllocations, 2, 0, +"oomAfterAllocations(count [,threadType])", " After 'count' js_malloc memory allocations, fail every following allocation\n" -" (return NULL)."), +" (return nullptr). The optional thread type limits the effect to the\n" +" specified type of helper thread."), - JS_FN_HELP("oomAtAllocation", OOMAtAllocation, 1, 0, -"oomAtAllocation(count)", + JS_FN_HELP("oomAtAllocation", OOMAtAllocation, 2, 0, +"oomAtAllocation(count [,threadType])", " After 'count' js_malloc memory allocations, fail the next allocation\n" -" (return NULL)."), +" (return nullptr). The optional thread type limits the effect to the\n" +" specified type of helper thread."), JS_FN_HELP("resetOOMFailure", ResetOOMFailure, 0, 0, "resetOOMFailure()", diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 778bf46de02d..8636c83d477a 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -590,6 +590,12 @@ JS_Init(void) if (!TlsPerThreadData.initialized() && !TlsPerThreadData.init()) return false; +#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) + if (!js::oom::InitThreadType()) + return false; + js::oom::SetThreadType(js::oom::THREAD_TYPE_MAIN); +#endif + jit::ExecutableAllocator::initStatic(); if (!jit::InitializeIon()) diff --git a/js/src/jsutil.cpp b/js/src/jsutil.cpp index 5a592c66d5fe..303063fc8565 100644 --- a/js/src/jsutil.cpp +++ b/js/src/jsutil.cpp @@ -11,6 +11,7 @@ #include "mozilla/Assertions.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/PodOperations.h" +#include "mozilla/ThreadLocal.h" #include @@ -32,7 +33,30 @@ using mozilla::PodArrayZero; JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations = UINT32_MAX; JS_PUBLIC_DATA(uint32_t) OOM_counter = 0; JS_PUBLIC_DATA(bool) OOM_failAlways = true; -#endif +namespace js { +namespace oom { + +JS_PUBLIC_DATA(uint32_t) targetThread = 0; +JS_PUBLIC_DATA(mozilla::ThreadLocal) threadType; + +bool +InitThreadType(void) { + return threadType.initialized() || threadType.init(); +} + +void +SetThreadType(ThreadType type) { + threadType.set(type); +} + +uint32_t +GetThreadType(void) { + return threadType.get(); +} + +} // namespace oom +} // namespace js +#endif // defined(DEBUG) || defined(JS_OOM_BREAKPOINT) JS_PUBLIC_API(void) JS_Assert(const char* s, const char* file, int ln) diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index 90012de8a1d6..3187644fa8f5 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -1451,19 +1451,26 @@ HelperThread::threadLoop() } // Dispatch tasks, prioritizing AsmJS work. - if (HelperThreadState().canStartAsmJSCompile()) + if (HelperThreadState().canStartAsmJSCompile()) { + js::oom::SetThreadType(js::oom::THREAD_TYPE_ASMJS); handleAsmJSWorkload(); - else if (ionCompile) + } else if (ionCompile) { + js::oom::SetThreadType(js::oom::THREAD_TYPE_ION); handleIonWorkload(); - else if (HelperThreadState().canStartParseTask()) + } else if (HelperThreadState().canStartParseTask()) { + js::oom::SetThreadType(js::oom::THREAD_TYPE_PARSE); handleParseWorkload(); - else if (HelperThreadState().canStartCompressionTask()) + } else if (HelperThreadState().canStartCompressionTask()) { + js::oom::SetThreadType(js::oom::THREAD_TYPE_COMPRESS); handleCompressionWorkload(); - else if (HelperThreadState().canStartGCHelperTask()) + } else if (HelperThreadState().canStartGCHelperTask()) { + js::oom::SetThreadType(js::oom::THREAD_TYPE_GCHELPER); handleGCHelperWorkload(); - else if (HelperThreadState().canStartGCParallelTask()) + } else if (HelperThreadState().canStartGCParallelTask()) { + js::oom::SetThreadType(js::oom::THREAD_TYPE_GCPARALLEL); handleGCParallelWorkload(); - else + } else { MOZ_CRASH("No task to perform"); + } } } From 565273c02b88bfe43ba15498dbbb454525543aff Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Thu, 3 Sep 2015 00:16:32 +0900 Subject: [PATCH 059/131] Bug 1196041 - Disallow getter/setter with expression closure in class declaration. r=efaust --HG-- extra : rebase_source : 0aa2c3b94ce864a27750c94c8ade5dea8df828c0 --- js/src/frontend/ParseNode.h | 16 +++++++++- js/src/frontend/Parser.cpp | 30 ++++++++++++++----- js/src/frontend/Parser.h | 2 ++ .../tests/ecma_6/Class/geterNoExprClosure.js | 24 +++++++++++++++ 4 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 js/src/tests/ecma_6/Class/geterNoExprClosure.js diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 6a14ec935cec..b54f8accf933 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -1716,7 +1716,9 @@ enum FunctionSyntaxKind ClassConstructor, DerivedClassConstructor, Getter, - Setter + GetterNoExpressionClosure, + Setter, + SetterNoExpressionClosure }; static inline bool @@ -1725,6 +1727,18 @@ IsConstructorKind(FunctionSyntaxKind kind) return kind == ClassConstructor || kind == DerivedClassConstructor; } +static inline bool +IsGetterKind(FunctionSyntaxKind kind) +{ + return kind == Getter || kind == GetterNoExpressionClosure; +} + +static inline bool +IsSetterKind(FunctionSyntaxKind kind) +{ + return kind == Setter || kind == SetterNoExpressionClosure; +} + static inline ParseNode* FunctionArgsList(ParseNode* fn, unsigned* numFormals) { diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index f2a2f33c5569..99d5f0af9dd7 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1431,10 +1431,12 @@ Parser::newFunction(HandleAtom atom, FunctionSyntaxKind kind, allocKind = gc::AllocKind::FUNCTION_EXTENDED; break; case Getter: + case GetterNoExpressionClosure: flags = JSFunction::INTERPRETED_GETTER; allocKind = gc::AllocKind::FUNCTION_EXTENDED; break; case Setter: + case SetterNoExpressionClosure: flags = JSFunction::INTERPRETED_SETTER; allocKind = gc::AllocKind::FUNCTION_EXTENDED; break; @@ -1860,7 +1862,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn Node duplicatedArg = null(); bool disallowDuplicateArgs = kind == Arrow || kind == Method || kind == ClassConstructor; - if (kind == Getter) { + if (IsGetterKind(kind)) { report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s"); return false; } @@ -1926,7 +1928,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn case TOK_TRIPLEDOT: { - if (kind == Setter) { + if (IsSetterKind(kind)) { report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; @@ -2003,7 +2005,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; } - if (parenFreeArrow || kind == Setter) + if (parenFreeArrow || IsSetterKind(kind)) break; if (!tokenStream.matchToken(&matched, TOK_COMMA)) @@ -2017,7 +2019,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!tokenStream.getToken(&tt)) return false; if (tt != TOK_RP) { - if (kind == Setter) { + if (IsSetterKind(kind)) { report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; @@ -2030,7 +2032,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!hasDefaults) funbox->length = pc->numArgs() - *hasRest; - } else if (kind == Setter) { + } else if (IsSetterKind(kind)) { report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", ""); return false; } @@ -2781,7 +2783,9 @@ Parser::functionArgsAndBodyGeneric(InHandling inHandling, if (!tokenStream.getToken(&tt, TokenStream::Operand)) return false; if (tt != TOK_LC) { - if (funbox->isStarGenerator() || kind == Method || IsConstructorKind(kind)) { + if (funbox->isStarGenerator() || kind == Method || + kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure || + IsConstructorKind(kind)) { report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY); return false; } @@ -6319,8 +6323,10 @@ JSOpFromPropertyType(PropertyType propType) { switch (propType) { case PropertyType::Getter: + case PropertyType::GetterNoExpressionClosure: return JSOP_INITPROP_GETTER; case PropertyType::Setter: + case PropertyType::SetterNoExpressionClosure: return JSOP_INITPROP_SETTER; case PropertyType::Normal: case PropertyType::Method: @@ -6339,8 +6345,12 @@ FunctionSyntaxKindFromPropertyType(PropertyType propType) switch (propType) { case PropertyType::Getter: return Getter; + case PropertyType::GetterNoExpressionClosure: + return GetterNoExpressionClosure; case PropertyType::Setter: return Setter; + case PropertyType::SetterNoExpressionClosure: + return SetterNoExpressionClosure; case PropertyType::Method: return Method; case PropertyType::GeneratorMethod: @@ -6474,6 +6484,10 @@ Parser::classDefinition(YieldHandling yieldHandling, return null(); } + if (propType == PropertyType::Getter) + propType = PropertyType::GetterNoExpressionClosure; + if (propType == PropertyType::Setter) + propType = PropertyType::SetterNoExpressionClosure; if (!isStatic && propAtom == context->names().constructor) { if (propType != PropertyType::Method) { report(ParseError, false, propName, JSMSG_BAD_METHOD_DEF); @@ -6494,8 +6508,8 @@ Parser::classDefinition(YieldHandling yieldHandling, // (bug 883377). RootedPropertyName funName(context); switch (propType) { - case PropertyType::Getter: - case PropertyType::Setter: + case PropertyType::GetterNoExpressionClosure: + case PropertyType::SetterNoExpressionClosure: funName = nullptr; break; case PropertyType::Constructor: diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 7a7079ad80ec..9ba7884d6110 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -358,7 +358,9 @@ enum class PropertyType { Normal, Shorthand, Getter, + GetterNoExpressionClosure, Setter, + SetterNoExpressionClosure, Method, GeneratorMethod, Constructor, diff --git a/js/src/tests/ecma_6/Class/geterNoExprClosure.js b/js/src/tests/ecma_6/Class/geterNoExprClosure.js new file mode 100644 index 000000000000..b447d08576d0 --- /dev/null +++ b/js/src/tests/ecma_6/Class/geterNoExprClosure.js @@ -0,0 +1,24 @@ +// getter/setter with expression closure is allowed only in object literal. + +function test() { + assertThrowsInstanceOf(() => eval(` +class foo { + constructor() {} + + get a() 1 +} +`), SyntaxError); + assertThrowsInstanceOf(() => eval(` +class foo { + constructor() {} + + set a(v) 1 +} +`), SyntaxError); +} + +if (classesEnabled()) + test(); + +if (typeof reportCompare === 'function') + reportCompare(0,0,"OK"); From edd37ff6991e815212d3d551bd12ae038848e00d Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 18 Aug 2015 10:43:48 +0900 Subject: [PATCH 060/131] Bug 1195578 - Part 2: Get a token next to an arrow function with block body with Operand modifier. r=Waldo --HG-- extra : rebase_source : a11972d77462ff2cc5071c0f94a20f45a2b8fd0d --- js/src/frontend/Parser.cpp | 42 ++++++++- js/src/frontend/TokenStream.h | 16 +++- .../jit-test/tests/parser/arrow-with-block.js | 92 +++++++++++++++++++ 3 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 js/src/jit-test/tests/parser/arrow-with-block.js diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 99d5f0af9dd7..075e5b485948 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -7089,6 +7089,13 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl "expression", TokenKindToDesc(TOK_ARROW)); return null(); } + tokenStream.consumeKnownToken(TOK_ARROW); + + bool isBlock = false; + if (!tokenStream.peekToken(&next, TokenStream::Operand)) + return null(); + if (next == TOK_LC) + isBlock = true; tokenStream.seek(start); if (!abortIfSyntaxParser()) @@ -7103,7 +7110,40 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl return null(); } - return functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator); + Node arrowFunc = functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator); + if (!arrowFunc) + return null(); + + if (isBlock) { + // This arrow function could be a non-trailing member of a comma + // expression or a semicolon terminating a full expression. If so, + // the next token is that comma/semicolon, gotten with None: + // + // a => {}, b; // as if (a => {}), b; + // a => {}; + // + // But if this arrow function ends a statement, ASI permits the + // next token to start an expression statement. In that case the + // next token must be gotten as Operand: + // + // a => {} // complete expression statement + // /x/g; // regular expression as a statement, *not* division + // + // Getting the second case right requires the first token-peek + // after the arrow function use Operand, and that peek must occur + // before Parser::expr() looks for a comma. Do so here, then + // immediately add the modifier exception needed for the first + // case. + // + // Note that the second case occurs *only* if the arrow function + // has block body. An arrow function not ending in such, ends in + // another AssignmentExpression that we can inductively assume was + // peeked consistently. + if (!tokenStream.peekToken(&ignored, TokenStream::Operand)) + return null(); + tokenStream.addModifierException(TokenStream::NoneIsOperand); + } + return arrowFunc; } default: diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index a0f12e528b42..ce3032084331 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -121,7 +121,8 @@ struct Token { NoException, - // After |yield| we look for a token on the same line that starts an + // Used in following 2 cases: + // a) After |yield| we look for a token on the same line that starts an // expression (Operand): |yield |. If no token is found, the // |yield| stands alone, and the next token on a subsequent line must // be: a comma continuing a comma expression, a semicolon terminating @@ -129,6 +130,19 @@ struct Token // statement (possibly an expression statement). The comma/semicolon // cases are gotten as operators (None), contrasting with Operand // earlier. + // b) After an arrow function with a block body in an expression + // statement, the next token must be: a colon in a conditional + // expression, a comma continuing a comma expression, a semicolon + // terminating the statement, or the token on a subsequent line that is + // the start of another statement (possibly an expression statement). + // Colon is gotten as operator (None), and it should only be gotten in + // conditional expression and missing it results in SyntaxError. + // Comma/semicolon cases are also gotten as operators (None), and 4th + // case is gotten after them. If no comma/semicolon found but EOL, + // the next token should be gotten as operand in 4th case (especially if + // '/' is the first character). So we should peek the token as + // operand before try getting colon/comma/semicolon. + // See also the comment in Parser::assignExpr(). NoneIsOperand, // If a semicolon is inserted automatically, the next token is already diff --git a/js/src/jit-test/tests/parser/arrow-with-block.js b/js/src/jit-test/tests/parser/arrow-with-block.js new file mode 100644 index 000000000000..de6f34c3149c --- /dev/null +++ b/js/src/jit-test/tests/parser/arrow-with-block.js @@ -0,0 +1,92 @@ +load(libdir + "asserts.js"); + +let x = 10; +let g = 4; + +assertEq(eval(` +a => {} +/x/g; +`).toString(), "/x/g"); +assertEq(eval(` +a => {} +/x/; +`).toString(), "/x/"); +assertThrowsInstanceOf(() => eval(` +a => {} /x/g; +`), SyntaxError); + +assertEq(eval(` +a => {}, +/x/; +`).toString(), "/x/"); +assertEq(eval(` +a => {} +, +/x/; +`).toString(), "/x/"); + +assertEq(eval(` +false ? +a => {} : +/x/; +`).toString(), "/x/"); +assertEq(eval(` +false ? +a => {} +: +/x/; +`).toString(), "/x/"); + +assertEq(eval(` +a => {}; +/x/; +`).toString(), "/x/"); +assertEq(eval(` +a => {} +; +/x/; +`).toString(), "/x/"); + +assertEq(eval(` +a => 200 +/x/g; +`) instanceof Function, true); +assertEq(eval(` +a => 200 +/x/g; +`)(), 5); +assertEq(eval(` +a => 200 /x/g; +`)(), 5); + +assertEq(eval(` +a => 1, +/x/; +`).toString(), "/x/"); +assertEq(eval(` +a => 1 +, +/x/; +`).toString(), "/x/"); + +assertEq(eval(` +false ? +a => 1 : +/x/; +`).toString(), "/x/"); +assertEq(eval(` +false ? +a => 1 +: +/x/; +`).toString(), "/x/"); + +assertEq(eval(` +a => 1; +/x/; +`).toString(), "/x/"); +assertEq(eval(` +a => 1 +; +/x/; +`).toString(), "/x/"); From a7f75d48d47912f2012b2b3dd39936aedc66759a Mon Sep 17 00:00:00 2001 From: Dragana Damjanovic Date: Fri, 11 Sep 2015 07:51:32 -0700 Subject: [PATCH 061/131] Bug 1172502 - Add message encription for WebPush. r=mt r=kitcambridge r=keeler r=smaug --HG-- extra : commitid : FsE5V9w4fej extra : amend_source : 8b44837b765bd319cadc93a53948264dfbd87ecf --- dom/interfaces/push/nsIPushClient.idl | 7 +- dom/push/Push.js | 16 +- dom/push/PushClient.js | 29 +- dom/push/PushManager.cpp | 115 ++++++-- dom/push/PushManager.h | 32 +- dom/push/PushService.jsm | 19 +- dom/push/PushServiceHttp2.jsm | 279 +++++++++++++----- dom/push/PushServiceHttp2Crypto.jsm | 189 ++++++++++++ dom/push/moz.build | 1 + .../test/xpcshell/test_notification_http2.js | 61 +++- ...subscribe_listening_for_msg_error_http2.js | 10 + .../test_updateRecordNoEncryptionKeys.js | 80 +++++ dom/push/test/xpcshell/xpcshell.ini | 1 + dom/webidl/PushSubscription.webidl | 8 +- testing/xpcshell/moz-http2/moz-http2.js | 39 ++- 15 files changed, 755 insertions(+), 131 deletions(-) create mode 100644 dom/push/PushServiceHttp2Crypto.jsm create mode 100644 dom/push/test/xpcshell/test_updateRecordNoEncryptionKeys.js diff --git a/dom/interfaces/push/nsIPushClient.idl b/dom/interfaces/push/nsIPushClient.idl index 5c9bdf627e2c..b2c6940cc4c2 100644 --- a/dom/interfaces/push/nsIPushClient.idl +++ b/dom/interfaces/push/nsIPushClient.idl @@ -17,10 +17,13 @@ interface nsIPrincipal; * endpoint. */ -[scriptable, uuid(0bcac389-a3ac-44a4-97fb-b50e41a46146)] +[scriptable, uuid(dc201064-8e5c-4a26-bd37-d1e33558a903)] interface nsIPushEndpointCallback : nsISupports { - void onPushEndpoint(in nsresult status, in DOMString endpoint); + void onPushEndpoint(in nsresult status, + in DOMString endpoint, + in uint32_t keyLen, + [array, size_is(keyLen)] in octet key); }; /** diff --git a/dom/push/Push.js b/dom/push/Push.js index 01e222bc4a7b..6eb14b38c5b7 100644 --- a/dom/push/Push.js +++ b/dom/push/Push.js @@ -121,10 +121,22 @@ Push.prototype = { () => { fn(that._scope, that._principal, { QueryInterface: XPCOMUtils.generateQI([Ci.nsIPushEndpointCallback]), - onPushEndpoint: function(ok, endpoint) { + onPushEndpoint: function(ok, endpoint, keyLen, key) { if (ok === Cr.NS_OK) { if (endpoint) { - let sub = new that._window.PushSubscription(endpoint, that._scope); + let sub; + if (keyLen) { + let publicKey = new ArrayBuffer(keyLen); + let keyView = new Uint8Array(publicKey); + keyView.set(key); + sub = new that._window.PushSubscription(endpoint, + that._scope, + publicKey); + } else { + sub = new that._window.PushSubscription(endpoint, + that._scope, + null); + } sub.setPrincipal(that._principal); resolve(sub); } else { diff --git a/dom/push/PushClient.js b/dom/push/PushClient.js index c2ce2989888f..8c8a15ce36d4 100644 --- a/dom/push/PushClient.js +++ b/dom/push/PushClient.js @@ -100,6 +100,19 @@ PushClient.prototype = { }, null, principal); }, + _deliverPushEndpoint: function(request, registration) { + if (registration.p256dhKey) { + let key = new Uint8Array(registration.p256dhKey); + request.onPushEndpoint(Cr.NS_OK, + registration.pushEndpoint, + key.length, + key); + return; + } + + request.onPushEndpoint(Cr.NS_OK, registration.pushEndpoint, 0, null); + }, + receiveMessage: function(aMessage) { let json = aMessage.data; @@ -112,23 +125,23 @@ PushClient.prototype = { debug("receiveMessage(): " + JSON.stringify(aMessage)) switch (aMessage.name) { case "PushService:Register:OK": - { - request.onPushEndpoint(Cr.NS_OK, json.pushEndpoint); + this._deliverPushEndpoint(request, json); break; - } case "PushService:Register:KO": - request.onPushEndpoint(Cr.NS_ERROR_FAILURE, ""); + request.onPushEndpoint(Cr.NS_ERROR_FAILURE, "", 0, null); break; case "PushService:Registration:OK": { let endpoint = ""; - if (json.registration) - endpoint = json.registration.pushEndpoint; - request.onPushEndpoint(Cr.NS_OK, endpoint); + if (!json.registration) { + request.onPushEndpoint(Cr.NS_OK, "", 0, null); + } else { + this._deliverPushEndpoint(request, json.registration); + } break; } case "PushService:Registration:KO": - request.onPushEndpoint(Cr.NS_ERROR_FAILURE, ""); + request.onPushEndpoint(Cr.NS_ERROR_FAILURE, "", 0, null); break; case "PushService:Unregister:OK": if (typeof json.result !== "boolean") { diff --git a/dom/push/PushManager.cpp b/dom/push/PushManager.cpp index 498aae1c4625..c350a447615a 100644 --- a/dom/push/PushManager.cpp +++ b/dom/push/PushManager.cpp @@ -90,13 +90,18 @@ PushSubscription::Unsubscribe(ErrorResult& aRv) PushSubscription::PushSubscription(nsIGlobalObject* aGlobal, const nsAString& aEndpoint, - const nsAString& aScope) - : mGlobal(aGlobal), mEndpoint(aEndpoint), mScope(aScope) + const nsAString& aScope, + const nsTArray& aRawP256dhKey) + : mGlobal(aGlobal) + , mEndpoint(aEndpoint) + , mScope(aScope) + , mRawP256dhKey(aRawP256dhKey) { } PushSubscription::~PushSubscription() -{} +{ +} JSObject* PushSubscription::WrapObject(JSContext* aCx, JS::Handle aGivenProto) @@ -104,6 +109,20 @@ PushSubscription::WrapObject(JSContext* aCx, JS::Handle aGivenProto) return PushSubscriptionBinding::Wrap(aCx, this, aGivenProto); } +void +PushSubscription::GetKey(JSContext* aCx, + PushEncryptionKeyName aType, + JS::MutableHandle aP256dhKey) +{ + if (aType == PushEncryptionKeyName::P256dh && !mRawP256dhKey.IsEmpty()) { + aP256dhKey.set(ArrayBuffer::Create(aCx, + mRawP256dhKey.Length(), + mRawP256dhKey.Elements())); + } else { + aP256dhKey.set(nullptr); + } +} + void PushSubscription::SetPrincipal(nsIPrincipal* aPrincipal) { @@ -113,16 +132,34 @@ PushSubscription::SetPrincipal(nsIPrincipal* aPrincipal) // static already_AddRefed -PushSubscription::Constructor(GlobalObject& aGlobal, const nsAString& aEndpoint, const nsAString& aScope, ErrorResult& aRv) +PushSubscription::Constructor(GlobalObject& aGlobal, + const nsAString& aEndpoint, + const nsAString& aScope, + const Nullable& aP256dhKey, + ErrorResult& aRv) { MOZ_ASSERT(!aEndpoint.IsEmpty()); MOZ_ASSERT(!aScope.IsEmpty()); + nsCOMPtr global = do_QueryInterface(aGlobal.GetAsSupports()); - nsRefPtr sub = new PushSubscription(global, aEndpoint, aScope); + + nsTArray rawKey; + if (!aP256dhKey.IsNull()) { + const ArrayBuffer& key = aP256dhKey.Value(); + key.ComputeLengthAndData(); + rawKey.SetLength(key.Length()); + rawKey.ReplaceElementsAt(0, key.Length(), key.Data(), key.Length()); + } + nsRefPtr sub = new PushSubscription(global, + aEndpoint, + aScope, + rawKey); + return sub.forget(); } NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushSubscription, mGlobal, mPrincipal) + NS_IMPL_CYCLE_COLLECTING_ADDREF(PushSubscription) NS_IMPL_CYCLE_COLLECTING_RELEASE(PushSubscription) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushSubscription) @@ -188,8 +225,9 @@ NS_INTERFACE_MAP_END // WorkerPushSubscription WorkerPushSubscription::WorkerPushSubscription(const nsAString& aEndpoint, - const nsAString& aScope) - : mEndpoint(aEndpoint), mScope(aScope) + const nsAString& aScope, + const nsTArray& aRawP256dhKey) + : mEndpoint(aEndpoint), mScope(aScope), mRawP256dhKey(aRawP256dhKey) { MOZ_ASSERT(!aScope.IsEmpty()); MOZ_ASSERT(!aEndpoint.IsEmpty()); @@ -206,16 +244,45 @@ WorkerPushSubscription::WrapObject(JSContext* aCx, JS::Handle aGivenP // static already_AddRefed -WorkerPushSubscription::Constructor(GlobalObject& aGlobal, const nsAString& aEndpoint, const nsAString& aScope, ErrorResult& aRv) +WorkerPushSubscription::Constructor(GlobalObject& aGlobal, + const nsAString& aEndpoint, + const nsAString& aScope, + const Nullable& aP256dhKey, + ErrorResult& aRv) { WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); MOZ_ASSERT(worker); worker->AssertIsOnWorkerThread(); - nsRefPtr sub = new WorkerPushSubscription(aEndpoint, aScope); + nsTArray rawKey; + if (!aP256dhKey.IsNull()) { + const ArrayBuffer& key = aP256dhKey.Value(); + key.ComputeLengthAndData(); + rawKey.SetLength(key.Length()); + rawKey.ReplaceElementsAt(0, key.Length(), key.Data(), key.Length()); + } + nsRefPtr sub = new WorkerPushSubscription(aEndpoint, + aScope, + rawKey); + return sub.forget(); } +void +WorkerPushSubscription::GetKey(JSContext* aCx, + PushEncryptionKeyName aType, + JS::MutableHandle aP256dhKey) +{ + if (aType == mozilla::dom::PushEncryptionKeyName::P256dh && + !mRawP256dhKey.IsEmpty()) { + aP256dhKey.set(ArrayBuffer::Create(aCx, + mRawP256dhKey.Length(), + mRawP256dhKey.Elements())); + } else { + aP256dhKey.set(nullptr); + } +} + class UnsubscribeResultRunnable final : public WorkerRunnable { public: @@ -371,6 +438,7 @@ WorkerPushSubscription::Unsubscribe(ErrorResult &aRv) } NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerPushSubscription) + NS_IMPL_CYCLE_COLLECTING_ADDREF(WorkerPushSubscription) NS_IMPL_CYCLE_COLLECTING_RELEASE(WorkerPushSubscription) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerPushSubscription) @@ -397,12 +465,14 @@ public: GetSubscriptionResultRunnable(PromiseWorkerProxy* aProxy, nsresult aStatus, const nsAString& aEndpoint, - const nsAString& aScope) + const nsAString& aScope, + const nsTArray& aRawP256dhKey) : WorkerRunnable(aProxy->GetWorkerPrivate(), WorkerThreadModifyBusyCount) , mProxy(aProxy) , mStatus(aStatus) , mEndpoint(aEndpoint) , mScope(aScope) + , mRawP256dhKey(aRawP256dhKey) { } bool @@ -414,7 +484,7 @@ public: promise->MaybeResolve(JS::NullHandleValue); } else { nsRefPtr sub = - new WorkerPushSubscription(mEndpoint, mScope); + new WorkerPushSubscription(mEndpoint, mScope, mRawP256dhKey); promise->MaybeResolve(sub); } } else { @@ -432,6 +502,7 @@ private: nsresult mStatus; nsString mEndpoint; nsString mScope; + nsTArray mRawP256dhKey; }; class GetSubscriptionCallback final : public nsIPushEndpointCallback @@ -446,7 +517,10 @@ public: {} NS_IMETHOD - OnPushEndpoint(nsresult aStatus, const nsAString& aEndpoint) override + OnPushEndpoint(nsresult aStatus, + const nsAString& aEndpoint, + uint32_t aKeyLen, + uint8_t* aKey) override { AssertIsOnMainThread(); MOZ_ASSERT(mProxy, "OnPushEndpoint() called twice?"); @@ -461,8 +535,15 @@ public: AutoJSAPI jsapi; jsapi.Init(); + nsTArray rawP256dhKey(aKeyLen); + rawP256dhKey.ReplaceElementsAt(0, aKeyLen, aKey, aKeyLen); + nsRefPtr r = - new GetSubscriptionResultRunnable(proxy, aStatus, aEndpoint, mScope); + new GetSubscriptionResultRunnable(proxy, + aStatus, + aEndpoint, + mScope, + rawP256dhKey); r->Dispatch(jsapi.cx()); return NS_OK; } @@ -502,7 +583,7 @@ public: nsCOMPtr permManager = mozilla::services::GetPermissionManager(); if (!permManager) { - callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString()); + callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString(), 0, nullptr); return NS_OK; } @@ -515,14 +596,14 @@ public: &permission); if (NS_WARN_IF(NS_FAILED(rv)) || permission != nsIPermissionManager::ALLOW_ACTION) { - callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString()); + callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString(), 0, nullptr); return NS_OK; } nsCOMPtr client = do_CreateInstance("@mozilla.org/push/PushClient;1"); if (!client) { - callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString()); + callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString(), 0, nullptr); return NS_OK; } @@ -534,7 +615,7 @@ public: } if (NS_WARN_IF(NS_FAILED(rv))) { - callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString()); + callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString(), 0, nullptr); return rv; } diff --git a/dom/push/PushManager.h b/dom/push/PushManager.h index ecc42b879643..882681108225 100644 --- a/dom/push/PushManager.h +++ b/dom/push/PushManager.h @@ -36,6 +36,7 @@ #include "mozilla/AlreadyAddRefed.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/TypedArray.h" #include "nsCOMPtr.h" #include "mozilla/nsRefPtr.h" @@ -44,6 +45,8 @@ class nsIGlobalObject; class nsIPrincipal; +#include "mozilla/dom/PushSubscriptionBinding.h" + namespace mozilla { namespace dom { @@ -63,7 +66,8 @@ public: explicit PushSubscription(nsIGlobalObject* aGlobal, const nsAString& aEndpoint, - const nsAString& aScope); + const nsAString& aScope, + const nsTArray& aP256dhKey); JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; @@ -80,8 +84,17 @@ public: aEndpoint = mEndpoint; } + void + GetKey(JSContext* cx, + PushEncryptionKeyName aType, + JS::MutableHandle aP256dhKey); + static already_AddRefed - Constructor(GlobalObject& aGlobal, const nsAString& aEndpoint, const nsAString& aScope, ErrorResult& aRv); + Constructor(GlobalObject& aGlobal, + const nsAString& aEndpoint, + const nsAString& aScope, + const Nullable& aP256dhKey, + ErrorResult& aRv); void SetPrincipal(nsIPrincipal* aPrincipal); @@ -97,6 +110,7 @@ private: nsCOMPtr mPrincipal; nsString mEndpoint; nsString mScope; + nsTArray mRawP256dhKey; }; class PushManager final : public nsISupports @@ -146,7 +160,8 @@ public: NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WorkerPushSubscription) explicit WorkerPushSubscription(const nsAString& aEndpoint, - const nsAString& aScope); + const nsAString& aScope, + const nsTArray& aRawP256dhKey); nsIGlobalObject* GetParentObject() const @@ -158,7 +173,11 @@ public: WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; static already_AddRefed - Constructor(GlobalObject& aGlobal, const nsAString& aEndpoint, const nsAString& aScope, ErrorResult& aRv); + Constructor(GlobalObject& aGlobal, + const nsAString& aEndpoint, + const nsAString& aScope, + const Nullable& aP256dhKey, + ErrorResult& aRv); void GetEndpoint(nsAString& aEndpoint) const @@ -166,6 +185,10 @@ public: aEndpoint = mEndpoint; } + void + GetKey(JSContext* cx, PushEncryptionKeyName aType, + JS::MutableHandle aP256dhKey); + already_AddRefed Unsubscribe(ErrorResult& aRv); @@ -175,6 +198,7 @@ protected: private: nsString mEndpoint; nsString mScope; + nsTArray mRawP256dhKey; }; class WorkerPushManager final : public nsISupports diff --git a/dom/push/PushService.jsm b/dom/push/PushService.jsm index d7e79b777ac0..fe36e0cee456 100644 --- a/dom/push/PushService.jsm +++ b/dom/push/PushService.jsm @@ -719,6 +719,11 @@ this.PushService = { .then(record => this._notifySubscriptionChangeObservers(record)); }, + updateRecordAndNotifyApp: function(aKeyID, aUpdateFunc) { + return this._db.update(aKeyID, aUpdateFunc) + .then(record => this._notifySubscriptionChangeObservers(record)); + }, + /** * Dispatches an incoming message to a service worker, recalculating the * quota for the associated push registration. If the quota is exceeded, @@ -737,7 +742,7 @@ this.PushService = { debug("receivedPushMessage()"); let shouldNotify = false; - this.getByKeyID(keyID).then(record => { + return this.getByKeyID(keyID).then(record => { if (!record) { throw new Error("No record for key ID " + keyID); } @@ -761,11 +766,13 @@ this.PushService = { return newRecord; }); }).then(record => { + var notified = false; if (!record) { - return null; + return notified; } + if (shouldNotify) { - this._notifyApp(record, message); + notified = this._notifyApp(record, message); } if (record.isExpired()) { // Drop the registration in the background. If the user returns to the @@ -775,6 +782,7 @@ this.PushService = { debug("receivedPushMessage: Unregister error: " + error); }); } + return notified; }).catch(error => { debug("receivedPushMessage: Error notifying app: " + error); }); @@ -785,7 +793,7 @@ this.PushService = { aPushRecord.originAttributes === undefined) { debug("notifyApp() something is undefined. Dropping notification: " + JSON.stringify(aPushRecord) ); - return; + return false; } debug("notifyApp() " + aPushRecord.scope); @@ -807,7 +815,7 @@ this.PushService = { // If permission has been revoked, trash the message. if (!aPushRecord.hasPermission()) { debug("Does not have permission for push."); - return; + return false; } // TODO data. @@ -818,6 +826,7 @@ this.PushService = { }; this._notifyListeners('push', data); + return true; }, getByKeyID: function(aKeyID) { diff --git a/dom/push/PushServiceHttp2.jsm b/dom/push/PushServiceHttp2.jsm index c8624ec8ed7c..e771339bf469 100644 --- a/dom/push/PushServiceHttp2.jsm +++ b/dom/push/PushServiceHttp2.jsm @@ -19,6 +19,9 @@ Cu.import("resource://gre/modules/Timer.jsm"); Cu.import("resource://gre/modules/Preferences.jsm"); Cu.import("resource://gre/modules/Promise.jsm"); +const {PushServiceHttp2Crypto, concatArray} = + Cu.import("resource://gre/modules/PushServiceHttp2Crypto.jsm"); + this.EXPORTED_SYMBOLS = ["PushServiceHttp2"]; const prefs = new Preferences("dom.push."); @@ -34,7 +37,7 @@ function debug(s) { } const kPUSHHTTP2DB_DB_NAME = "pushHttp2"; -const kPUSHHTTP2DB_DB_VERSION = 4; // Change this if the IndexedDB format changes +const kPUSHHTTP2DB_DB_VERSION = 5; // Change this if the IndexedDB format changes const kPUSHHTTP2DB_STORE_NAME = "pushHttp2"; /** @@ -114,13 +117,12 @@ PushSubscriptionListener.prototype = { var PushChannelListener = function(pushSubscriptionListener) { debug("Creating a new push channel listener."); this._mainListener = pushSubscriptionListener; + this._message = []; + this._ackUri = null; }; PushChannelListener.prototype = { - _message: null, - _ackUri: null, - onStartRequest: function(aRequest, aContext) { this._ackUri = aRequest.URI.spec; }, @@ -132,15 +134,13 @@ PushChannelListener.prototype = { return; } - let inputStream = Cc["@mozilla.org/scriptableinputstream;1"] - .createInstance(Ci.nsIScriptableInputStream); + let inputStream = Cc["@mozilla.org/binaryinputstream;1"] + .createInstance(Ci.nsIBinaryInputStream); - inputStream.init(aStream); - if (!this._message) { - this._message = inputStream.read(aCount); - } else { - this._message.concat(inputStream.read(aCount)); - } + inputStream.setInputStream(aStream); + let chunk = new ArrayBuffer(aCount); + inputStream.readArrayBuffer(aCount, chunk); + this._message.push(chunk); }, onStopRequest: function(aRequest, aContext, aStatusCode) { @@ -148,13 +148,76 @@ PushChannelListener.prototype = { if (Components.isSuccessCode(aStatusCode) && this._mainListener && this._mainListener._pushService) { + + var keymap = encryptKeyFieldParser(aRequest); + if (!keymap) { + return; + } + var enc = encryptFieldParser(aRequest); + if (!enc || !enc.keyid) { + return; + } + var dh = keymap[enc.keyid]; + var salt = enc.salt; + var rs = (enc.rs)? parseInt(enc.rs, 10) : 4096; + if (!dh || !salt || isNaN(rs) || (rs <= 1)) { + return; + } + + var msg = concatArray(this._message); + this._mainListener._pushService._pushChannelOnStop(this._mainListener.uri, this._ackUri, - this._message); + msg, + dh, + salt, + rs); } } }; +var parseHeaderFieldParams = (m, v) => { + var i = v.indexOf('='); + if (i >= 0) { + // A quoted string with internal quotes is invalid for all the possible + // values of this header field. + m[v.substring(0, i).trim()] = v.substring(i + 1).trim() + .replace(/^"(.*)"$/, '$1'); + } + return m; +}; + +function encryptKeyFieldParser(aRequest) { + try { + var encryptKeyField = aRequest.getRequestHeader("Encryption-Key"); + + var params = encryptKeyField.split(','); + return params.reduce((m, p) => { + var pmap = p.split(';').reduce(parseHeaderFieldParams, {}); + if (pmap.keyid && pmap.dh) { + m[pmap.keyid] = pmap.dh; + } + return m; + }, {}); + + } catch(e) { + // getRequestHeader can throw. + return null; + } +} + +function encryptFieldParser(aRequest) { + try { + return aRequest.getRequestHeader("Encryption") + .split(',', 1)[0] + .split(';') + .reduce(parseHeaderFieldParams, {}); + } catch(e) { + // getRequestHeader can throw. + return null; + } +} + var PushServiceDelete = function(resolve, reject) { this._resolve = resolve; this._reject = reject; @@ -188,9 +251,12 @@ PushServiceDelete.prototype = { } }; -var SubscriptionListener = function(aSubInfo, aServerURI, aPushServiceHttp2) { +var SubscriptionListener = function(aSubInfo, aResolve, aReject, + aServerURI, aPushServiceHttp2) { debug("Creating a new subscription listener."); this._subInfo = aSubInfo; + this._resolve = aResolve; + this._reject = aReject; this._data = ''; this._serverURI = aServerURI; this._service = aPushServiceHttp2; @@ -221,12 +287,12 @@ SubscriptionListener.prototype = { // Check if pushService is still active. if (!this._service.hasmainPushService()) { - this._subInfo.reject({error: "Service deactivated"}); + this._reject({error: "Service deactivated"}); return; } if (!Components.isSuccessCode(aStatus)) { - this._subInfo.reject({error: "Error status" + aStatus}); + this._reject({error: "Error status" + aStatus}); return; } @@ -236,15 +302,18 @@ SubscriptionListener.prototype = { if (this._subInfo.retries < prefs.get("http2.maxRetries")) { this._subInfo.retries++; var retryAfter = retryAfterParser(aRequest); - setTimeout(this._service.retrySubscription.bind(this._service, - this._subInfo), - retryAfter); + setTimeout(_ => this._reject( + { + retry: true, + subInfo: this._subInfo + }), + retryAfter); } else { - this._subInfo.reject({error: "Error response code: " + statusCode }); + this._reject({error: "Error response code: " + statusCode }); } return; } else if (statusCode != 201) { - this._subInfo.reject({error: "Error response code: " + statusCode }); + this._reject({error: "Error response code: " + statusCode }); return; } @@ -252,7 +321,7 @@ SubscriptionListener.prototype = { try { subscriptionUri = aRequest.getResponseHeader("location"); } catch (err) { - this._subInfo.reject({error: "Return code 201, but the answer is bogus"}); + this._reject({error: "Return code 201, but the answer is bogus"}); return; } @@ -262,27 +331,27 @@ SubscriptionListener.prototype = { try { linkList = aRequest.getResponseHeader("link"); } catch (err) { - this._subInfo.reject({error: "Return code 201, but the answer is bogus"}); + this._reject({error: "Return code 201, but the answer is bogus"}); return; } var linkParserResult = linkParser(linkList, this._serverURI); if (linkParserResult.error) { - this._subInfo.reject(linkParserResult); + this._reject(linkParserResult); return; } if (!subscriptionUri) { - this._subInfo.reject({error: "Return code 201, but the answer is bogus," + - " missing subscriptionUri"}); + this._reject({error: "Return code 201, but the answer is bogus," + + " missing subscriptionUri"}); return; } try { let uriTry = Services.io.newURI(subscriptionUri, null, null); } catch (e) { debug("Invalid URI " + subscriptionUri); - this._subInfo.reject({error: "Return code 201, but URI is bogus. " + - subscriptionUri}); + this._reject({error: "Return code 201, but URI is bogus. " + + subscriptionUri}); return; } @@ -295,7 +364,7 @@ SubscriptionListener.prototype = { quota: this._subInfo.record.maxQuota, }); - this._subInfo.resolve(reply); + this._resolve(reply); }, }; @@ -456,41 +525,53 @@ this.PushServiceHttp2 = { _subscribeResource: function(aRecord) { debug("subscribeResource()"); - return new Promise((resolve, reject) => { - this._subscribeResourceInternal({record: aRecord, - resolve, - reject, - retries: 0}); + return this._subscribeResourceInternal({ + record: aRecord, + retries: 0 }) - .then(result => { - this._conns[result.subscriptionUri] = {channel: null, - listener: null, - countUnableToConnect: 0, - lastStartListening: 0, - waitingForAlarm: false}; - this._listenForMsgs(result.subscriptionUri); - return result; - }); + .then(result => + PushServiceHttp2Crypto.generateKeys() + .then(exportedKeys => { + result.p256dhPublicKey = exportedKeys[0]; + result.p256dhPrivateKey = exportedKeys[1]; + this._conns[result.subscriptionUri] = { + channel: null, + listener: null, + countUnableToConnect: 0, + lastStartListening: 0, + waitingForAlarm: false + }; + this._listenForMsgs(result.subscriptionUri); + return result; + }) + ); }, _subscribeResourceInternal: function(aSubInfo) { - debug("subscribeResource()"); + debug("subscribeResourceInternal()"); - var listener = new SubscriptionListener(aSubInfo, - this._serverURI, - this); + return new Promise((resolve, reject) => { + var listener = new SubscriptionListener(aSubInfo, + resolve, + reject, + this._serverURI, + this); - var chan = this._makeChannel(this._serverURI.spec); - chan.requestMethod = "POST"; - try{ - chan.asyncOpen(listener, null); - } catch(e) { - aSubInfo.reject({status: 0, error: "NetworkError"}); - } - }, - - retrySubscription: function(aSubInfo) { - this._subscribeResourceInternal(aSubInfo); + var chan = this._makeChannel(this._serverURI.spec); + chan.requestMethod = "POST"; + try { + chan.asyncOpen(listener, null); + } catch(e) { + reject({status: 0, error: "NetworkError"}); + } + }) + .catch(err => { + if ("retry" in err) { + return this._subscribeResourceInternal(err.subInfo); + } else { + throw err; + } + }) }, _deleteResource: function(aUri) { @@ -640,19 +721,51 @@ this.PushServiceHttp2 = { for (let i = 0; i < aSubscriptions.length; i++) { let record = aSubscriptions[i]; - if (typeof this._conns[record.subscriptionUri] != "object") { - this._conns[record.subscriptionUri] = {channel: null, - listener: null, - countUnableToConnect: 0, - waitingForAlarm: false}; - } - if (!this._conns[record.subscriptionUri].conn) { - this._conns[record.subscriptionUri].waitingForAlarm = false; - this._listenForMsgs(record.subscriptionUri); + if (record.p256dhPublicKey && record.p256dhPrivateKey) { + this._startSingleConnection(record); + } else { + // We do not have a encryption key. so we need to generate it. This + // is only going to happen on db upgrade from version 4 to higher. + PushServiceHttp2Crypto.generateKeys() + .then(exportedKeys => { + if (this._mainPushService) { + return this._mainPushService + .updateRecordAndNotifyApp(record.subscriptionUri, record => { + record.p256dhPublicKey = exportedKeys[0]; + record.p256dhPrivateKey = exportedKeys[1]; + return record; + }); + } + }, error => { + record = null; + if (this._mainPushService) { + this._mainPushService + .dropRegistrationAndNotifyApp(record.subscriptionUri); + } + }) + .then(_ => { + if (record) { + this._startSingleConnection(record); + } + }); } } }, + _startSingleConnection: function(record) { + debug("_startSingleConnection()"); + if (typeof this._conns[record.subscriptionUri] != "object") { + this._conns[record.subscriptionUri] = {channel: null, + listener: null, + countUnableToConnect: 0, + waitingForAlarm: false}; + } + if (!this._conns[record.subscriptionUri].conn) { + this._conns[record.subscriptionUri].waitingForAlarm = false; + this._listenForMsgs(record.subscriptionUri); + } + }, + // Start listening if subscriptions present. _startConnectionsWaitingForAlarm: function() { debug("startConnectionsWaitingForAlarm()"); @@ -756,19 +869,33 @@ this.PushServiceHttp2 = { } }, - _pushChannelOnStop: function(aUri, aAckUri, aMessage) { + _pushChannelOnStop: function(aUri, aAckUri, aMessage, dh, salt, rs) { debug("pushChannelOnStop() "); - this._mainPushService.receivedPushMessage(aUri, aMessage, record => { - // Always update the stored record. - return record; + this._mainPushService.getByKeyID(aUri) + .then(aPushRecord => + PushServiceHttp2Crypto.decodeMsg(aMessage, aPushRecord.p256dhPrivateKey, + dh, salt, rs) + .then(msg => { + var msgString = ''; + for (var i=0; i { + // Always update the stored record. + return record; + }); + }) + ) + .then(_ => this._ackMsgRecv(aAckUri)) + .catch(err => { + debug("Error receiving message: " + err); }); - this._ackMsgRecv(aAckUri); }, onAlarmFired: function() { - // Conditions are arranged in decreasing specificity. - // i.e. when _waitingForPong is true, other conditions are also true. this._startConnectionsWaitingForAlarm(); }, }; @@ -777,6 +904,8 @@ function PushRecordHttp2(record) { PushRecord.call(this, record); this.subscriptionUri = record.subscriptionUri; this.pushReceiptEndpoint = record.pushReceiptEndpoint; + this.p256dhPublicKey = record.p256dhPublicKey; + this.p256dhPrivateKey = record.p256dhPrivateKey; } PushRecordHttp2.prototype = Object.create(PushRecord.prototype, { @@ -790,11 +919,13 @@ PushRecordHttp2.prototype = Object.create(PushRecord.prototype, { PushRecordHttp2.prototype.toRegistration = function() { let registration = PushRecord.prototype.toRegistration.call(this); registration.pushReceiptEndpoint = this.pushReceiptEndpoint; + registration.p256dhKey = this.p256dhPublicKey; return registration; }; PushRecordHttp2.prototype.toRegister = function() { let register = PushRecord.prototype.toRegister.call(this); register.pushReceiptEndpoint = this.pushReceiptEndpoint; + register.p256dhKey = this.p256dhPublicKey; return register; }; diff --git a/dom/push/PushServiceHttp2Crypto.jsm b/dom/push/PushServiceHttp2Crypto.jsm new file mode 100644 index 000000000000..64bfe9eebb67 --- /dev/null +++ b/dom/push/PushServiceHttp2Crypto.jsm @@ -0,0 +1,189 @@ +/* jshint moz: true, esnext: true */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +const Cu = Components.utils; + +Cu.importGlobalProperties(['crypto']); + +this.EXPORTED_SYMBOLS = ['PushServiceHttp2Crypto', 'concatArray']; + +var ENCRYPT_INFO = new TextEncoder('utf-8').encode('Content-Encoding: aesgcm128'); +var NONCE_INFO = new TextEncoder('utf-8').encode('Content-Encoding: nonce'); + +function chunkArray(array, size) { + var start = array.byteOffset || 0; + array = array.buffer || array; + var index = 0; + var result = []; + while(index + size <= array.byteLength) { + result.push(new Uint8Array(array, start + index, size)); + index += size; + } + if (index < array.byteLength) { + result.push(new Uint8Array(array, start + index)); + } + return result; +} + +function base64UrlDecode(s) { + s = s.replace(/-/g, '+').replace(/_/g, '/'); + + // Replace padding if it was stripped by the sender. + // See http://tools.ietf.org/html/rfc4648#section-4 + switch (s.length % 4) { + case 0: + break; // No pad chars in this case + case 2: + s += '=='; + break; // Two pad chars + case 3: + s += '='; + break; // One pad char + default: + throw new Error('Illegal base64url string!'); + } + + // With correct padding restored, apply the standard base64 decoder + var decoded = atob(s); + + var array = new Uint8Array(new ArrayBuffer(decoded.length)); + for (var i = 0; i < decoded.length; i++) { + array[i] = decoded.charCodeAt(i); + } + return array; +} + +this.concatArray = function(arrays) { + var size = arrays.reduce((total, a) => total + a.byteLength, 0); + var index = 0; + return arrays.reduce((result, a) => { + result.set(new Uint8Array(a), index); + index += a.byteLength; + return result; + }, new Uint8Array(size)); +}; + +var HMAC_SHA256 = { name: 'HMAC', hash: 'SHA-256' }; + +function hmac(key) { + this.keyPromise = crypto.subtle.importKey('raw', key, HMAC_SHA256, + false, ['sign']); +} + +hmac.prototype.hash = function(input) { + return this.keyPromise.then(k => crypto.subtle.sign('HMAC', k, input)); +}; + +function hkdf(salt, ikm) { + this.prkhPromise = new hmac(salt).hash(ikm) + .then(prk => new hmac(prk)); +} + +hkdf.prototype.generate = function(info, len) { + var input = concatArray([info, new Uint8Array([1])]); + return this.prkhPromise + .then(prkh => prkh.hash(input)) + .then(h => { + if (h.byteLength < len) { + throw new Error('Length is too long'); + } + return h.slice(0, len); + }); +}; + +/* generate a 96-bit IV for use in GCM, 48-bits of which are populated */ +function generateNonce(base, index) { + if (index >= Math.pow(2, 48)) { + throw new Error('Error generating IV - index is too large.'); + } + var nonce = base.slice(0, 12); + nonce = new Uint8Array(nonce); + for (var i = 0; i < 6; ++i) { + nonce[nonce.byteLength - 1 - i] ^= (index / Math.pow(256, i)) & 0xff; + } + return nonce; +} + +this.PushServiceHttp2Crypto = { + + generateKeys: function() { + return crypto.subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256'}, + true, + ['deriveBits']) + .then(cryptoKey => + Promise.all([ + crypto.subtle.exportKey('raw', cryptoKey.publicKey), + // TODO: change this when bug 1048931 lands. + crypto.subtle.exportKey('jwk', cryptoKey.privateKey) + ])); + }, + + decodeMsg: function(aData, aPrivateKey, aRemotePublicKey, aSalt, aRs) { + + if (aData.byteLength === 0) { + // Zero length messages will be passed as null. + return Promise.resolve(null); + } + + // The last chunk of data must be less than aRs, if it is not return an + // error. + if (aData.byteLength % (aRs + 16) === 0) { + return Promise.reject(new Error('Data truncated')); + } + + return Promise.all([ + crypto.subtle.importKey('raw', base64UrlDecode(aRemotePublicKey), + { name: 'ECDH', namedCurve: 'P-256' }, + false, + ['deriveBits']), + crypto.subtle.importKey('jwk', aPrivateKey, + { name: 'ECDH', namedCurve: 'P-256' }, + false, + ['deriveBits']) + ]) + .then(keys => + crypto.subtle.deriveBits({ name: 'ECDH', public: keys[0] }, keys[1], 256)) + .then(rawKey => { + var kdf = new hkdf(base64UrlDecode(aSalt), new Uint8Array(rawKey)); + return Promise.all([ + kdf.generate(ENCRYPT_INFO, 16) + .then(gcmBits => + crypto.subtle.importKey('raw', gcmBits, 'AES-GCM', false, + ['decrypt'])), + kdf.generate(NONCE_INFO, 12) + ]) + }) + .then(r => + // AEAD_AES_128_GCM expands ciphertext to be 16 octets longer. + Promise.all(chunkArray(aData, aRs + 16).map((slice, index) => + this._decodeChunk(slice, index, r[1], r[0])))) + .then(r => concatArray(r)); + }, + + _decodeChunk: function(aSlice, aIndex, aNonce, aKey) { + return crypto.subtle.decrypt({name: 'AES-GCM', + iv: generateNonce(aNonce, aIndex) + }, + aKey, aSlice) + .then(decoded => { + decoded = new Uint8Array(decoded); + if (decoded.length == 0) { + return Promise.reject(new Error('Decoded array is too short!')); + } else if (decoded[0] > decoded.length) { + return Promise.reject(new Error ('Padding is wrong!')); + } else { + // All padded bytes must be zero except the first one. + for (var i = 1; i <= decoded[0]; i++) { + if (decoded[i] != 0) { + return Promise.reject(new Error('Padding is wrong!')); + } + } + return decoded.slice(decoded[0] + 1); + } + }); + } +}; diff --git a/dom/push/moz.build b/dom/push/moz.build index d32225fc53a2..e5ef251f2e87 100644 --- a/dom/push/moz.build +++ b/dom/push/moz.build @@ -20,6 +20,7 @@ EXTRA_JS_MODULES += [ 'PushService.jsm', 'PushServiceChildPreload.jsm', 'PushServiceHttp2.jsm', + 'PushServiceHttp2Crypto.jsm', ] MOCHITEST_MANIFESTS += [ diff --git a/dom/push/test/xpcshell/test_notification_http2.js b/dom/push/test/xpcshell/test_notification_http2.js index 59b5d35bfe53..0650f7de1394 100644 --- a/dom/push/test/xpcshell/test_notification_http2.js +++ b/dom/push/test/xpcshell/test_notification_http2.js @@ -46,6 +46,13 @@ function run_test() { add_task(function* test_pushNotifications() { + // /pushNotifications/subscription1 will send a message with no rs and padding + // length 1. + // /pushNotifications/subscription2 will send a message with no rs and padding + // length 16. + // /pushNotifications/subscription3 will send a message with rs equal 24 and + // padding length 16. + let db = PushServiceHttp2.newPushDB(); do_register_cleanup(() => { return db.drop().then(_ => db.close()); @@ -58,6 +65,16 @@ add_task(function* test_pushNotifications() { pushEndpoint: serverURL + '/pushEndpoint1', pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint1', scope: 'https://example.com/page/1', + p256dhPublicKey: 'BPCd4gNQkjwRah61LpdALdzZKLLnU5UAwDztQ5_h0QsT26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA', + p256dhPrivateKey: { + crv: 'P-256', + d: '1jUPhzVsRkzV0vIzwL4ZEsOlKdNOWm7TmaTfzitJkgM', + ext: true, + key_ops: ["deriveBits"], + kty: "EC", + x: '8J3iA1CSPBFqHrUul0At3NkosudTlQDAPO1Dn-HRCxM', + y: '26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA' + }, originAttributes: ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), quota: Infinity, }, { @@ -65,6 +82,16 @@ add_task(function* test_pushNotifications() { pushEndpoint: serverURL + '/pushEndpoint2', pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint2', scope: 'https://example.com/page/2', + p256dhPublicKey: 'BPnWyUo7yMnuMlyKtERuLfWE8a09dtdjHSW2lpC9_BqR5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E', + p256dhPrivateKey: { + crv: 'P-256', + d: 'lFm4nPsUKYgNGBJb5nXXKxl8bspCSp0bAhCYxbveqT4', + ext: true, + key_ops: ["deriveBits"], + kty: 'EC', + x: '-dbJSjvIye4yXIq0RG4t9YTxrT1212MdJbaWkL38GpE', + y: '5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E' + }, originAttributes: ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), quota: Infinity, }, { @@ -72,6 +99,16 @@ add_task(function* test_pushNotifications() { pushEndpoint: serverURL + '/pushEndpoint3', pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint3', scope: 'https://example.com/page/3', + p256dhPublicKey: 'BDhUHITSeVrWYybFnb7ylVTCDDLPdQWMpf8gXhcWwvaaJa6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI', + p256dhPrivateKey: { + crv: 'P-256', + d: 'Q1_SE1NySTYzjbqgWwPgrYh7XRg3adqZLkQPsy319G8', + ext: true, + key_ops: ["deriveBits"], + kty: 'EC', + x: 'OFQchNJ5WtZjJsWdvvKVVMIMMs91BYyl_yBeFxbC9po', + y: 'Ja6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI' + }, originAttributes: ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }), quota: Infinity, }]; @@ -81,9 +118,27 @@ add_task(function* test_pushNotifications() { } let notifyPromise = Promise.all([ - promiseObserverNotification('push-notification'), - promiseObserverNotification('push-notification'), - promiseObserverNotification('push-notification') + promiseObserverNotification('push-notification', function(subject, data) { + var notification = subject.QueryInterface(Ci.nsIPushObserverNotification); + if (notification && (data == "https://example.com/page/1")){ + equal(subject.data, "Some message", "decoded message is incorrect"); + return true; + } + }), + promiseObserverNotification('push-notification', function(subject, data) { + var notification = subject.QueryInterface(Ci.nsIPushObserverNotification); + if (notification && (data == "https://example.com/page/2")){ + equal(subject.data, "Some message", "decoded message is incorrect"); + return true; + } + }), + promiseObserverNotification('push-notification', function(subject, data) { + var notification = subject.QueryInterface(Ci.nsIPushObserverNotification); + if (notification && (data == "https://example.com/page/3")){ + equal(subject.data, "Some message", "decoded message is incorrect"); + return true; + } + }) ]); PushService.init({ diff --git a/dom/push/test/xpcshell/test_resubscribe_listening_for_msg_error_http2.js b/dom/push/test/xpcshell/test_resubscribe_listening_for_msg_error_http2.js index f798f3a502c6..8cd82f676032 100644 --- a/dom/push/test/xpcshell/test_resubscribe_listening_for_msg_error_http2.js +++ b/dom/push/test/xpcshell/test_resubscribe_listening_for_msg_error_http2.js @@ -68,6 +68,16 @@ add_task(function* test1() { pushEndpoint: serverURL + '/pushEndpoint', pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint', scope: 'https://example.com/page', + p256dhPublicKey: 'BPCd4gNQkjwRah61LpdALdzZKLLnU5UAwDztQ5_h0QsT26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA', + p256dhPrivateKey: { + crv: 'P-256', + d: '1jUPhzVsRkzV0vIzwL4ZEsOlKdNOWm7TmaTfzitJkgM', + ext: true, + key_ops: ["deriveBits"], + kty: "EC", + x: '8J3iA1CSPBFqHrUul0At3NkosudTlQDAPO1Dn-HRCxM', + y: '26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA' + }, originAttributes: '', quota: Infinity, }]; diff --git a/dom/push/test/xpcshell/test_updateRecordNoEncryptionKeys.js b/dom/push/test/xpcshell/test_updateRecordNoEncryptionKeys.js new file mode 100644 index 000000000000..a091b566fec2 --- /dev/null +++ b/dom/push/test/xpcshell/test_updateRecordNoEncryptionKeys.js @@ -0,0 +1,80 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +'use strict'; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://testing-common/httpd.js"); + +const {PushDB, PushService, PushServiceHttp2} = serviceExports; + +var httpServer = null; + +XPCOMUtils.defineLazyGetter(this, "serverPort", function() { + return httpServer.identity.primaryPort; +}); + +function listenHandler(metadata, response) { + do_check_true(true, "Start listening"); + httpServer.stop(do_test_finished); + response.setHeader("Retry-After", "10"); + response.setStatusLine(metadata.httpVersion, 500, "Retry"); +} + +httpServer = new HttpServer(); +httpServer.registerPathHandler("/subscriptionNoKey", listenHandler); +httpServer.start(-1); + +function run_test() { + + do_get_profile(); + setPrefs({ + 'http2.retryInterval': 1000, + 'http2.maxRetries': 2 + }); + disableServiceWorkerEvents( + 'https://example.com/page' + ); + + run_next_test(); +} + +add_task(function* test1() { + + let db = PushServiceHttp2.newPushDB(); + do_register_cleanup(_ => { + return db.drop().then(_ => db.close()); + }); + + do_test_pending(); + + var serverURL = "http://localhost:" + httpServer.identity.primaryPort; + + let record = { + subscriptionUri: serverURL + '/subscriptionNoKey', + pushEndpoint: serverURL + '/pushEndpoint', + pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint', + scope: 'https://example.com/page', + originAttributes: '', + quota: Infinity, + }; + + yield db.put(record); + + let notifyPromise = promiseObserverNotification('push-subscription-change', + _ => true); + + PushService.init({ + serverURI: serverURL + "/subscribe", + service: PushServiceHttp2, + db + }); + + yield waitForPromise(notifyPromise, DEFAULT_TIMEOUT, + 'Timed out waiting for notifications'); + + let aRecord = yield db.getByKeyID(serverURL + '/subscriptionNoKey'); + ok(aRecord, 'The record should still be there'); + ok(aRecord.p256dhPublicKey, 'There should be a public key'); + ok(aRecord.p256dhPrivateKey, 'There should be a private key'); +}); diff --git a/dom/push/test/xpcshell/xpcshell.ini b/dom/push/test/xpcshell/xpcshell.ini index 841bb76649f9..f10692601f3f 100644 --- a/dom/push/test/xpcshell/xpcshell.ini +++ b/dom/push/test/xpcshell/xpcshell.ini @@ -38,6 +38,7 @@ skip-if = toolkit == 'android' [test_resubscribe_5xxCode_http2.js] [test_resubscribe_listening_for_msg_error_http2.js] [test_register_5xxCode_http2.js] +[test_updateRecordNoEncryptionKeys.js] [test_register_success_http2.js] skip-if = !hasNode run-sequentially = node server exceptions dont replay well diff --git a/dom/webidl/PushSubscription.webidl b/dom/webidl/PushSubscription.webidl index 2be9f2981307..3f6ce336c000 100644 --- a/dom/webidl/PushSubscription.webidl +++ b/dom/webidl/PushSubscription.webidl @@ -9,11 +9,17 @@ interface Principal; +enum PushEncryptionKeyName +{ + "p256dh" +}; + [Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled", - ChromeConstructor(DOMString pushEndpoint, DOMString scope)] + ChromeConstructor(DOMString pushEndpoint, DOMString scope, ArrayBuffer? key)] interface PushSubscription { readonly attribute USVString endpoint; + ArrayBuffer? getKey(PushEncryptionKeyName name); [Throws, UseCounter] Promise unsubscribe(); jsonifier; diff --git a/testing/xpcshell/moz-http2/moz-http2.js b/testing/xpcshell/moz-http2/moz-http2.js index 275dc83dc35b..4d278e4ec2da 100644 --- a/testing/xpcshell/moz-http2/moz-http2.js +++ b/testing/xpcshell/moz-http2/moz-http2.js @@ -487,40 +487,49 @@ function handleRequest(req, res) { else if (u.pathname ==="/pushNotifications/subscription1") { pushPushServer1 = res.push( - { hostname: 'localhost:' + serverPort, port: serverPort, - path : '/pushNotificationsDeliver1', method : 'GET', - headers: {'x-pushed-request': 'true', 'x-foo' : 'bar'}}); + { hostname: 'localhost:' + serverPort, port: serverPort, + path : '/pushNotificationsDeliver1', method : 'GET', + headers: { 'Encryption-Key': 'keyid="notification1"; dh="BO_tgGm-yvYAGLeRe16AvhzaUcpYRiqgsGOlXpt0DRWDRGGdzVLGlEVJMygqAUECarLnxCiAOHTP_znkedrlWoU"', + 'Encryption': 'keyid="notification1";salt="uAZaiXpOSfOLJxtOCZ09dA"' + } + }); pushPushServer1.writeHead(200, { - 'content-length' : 2, 'subresource' : '1' }); - pushPushServer1.end('ok'); + + pushPushServer1.end('370aeb3963f12c4f12bf946bd0a7a9ee7d3eaff8f7aec62b530fc25cfa', 'hex'); return; } else if (u.pathname ==="/pushNotifications/subscription2") { pushPushServer2 = res.push( - { hostname: 'localhost:' + serverPort, port: serverPort, - path : '/pushNotificationsDeliver3', method : 'GET', - headers: {'x-pushed-request': 'true', 'x-foo' : 'bar'}}); + { hostname: 'localhost:' + serverPort, port: serverPort, + path : '/pushNotificationsDeliver3', method : 'GET', + headers: { 'Encryption-Key': 'keyid="notification2"; dh="BKVdQcgfncpNyNWsGrbecX0zq3eHIlHu5XbCGmVcxPnRSbhjrA6GyBIeGdqsUL69j5Z2CvbZd-9z1UBH0akUnGQ"', + 'Encryption': 'keyid="notification2";salt="vFn3t3M_k42zHBdpch3VRw"' + } + }); pushPushServer2.writeHead(200, { - 'content-length' : 2, 'subresource' : '1' }); - pushPushServer2.end('ok'); + + pushPushServer2.end('66df5d11daa01e5c802ff97cdf7f39684b5bf7c6418a5cf9b609c6826c04b25e403823607ac514278a7da945', 'hex'); return; } else if (u.pathname ==="/pushNotifications/subscription3") { pushPushServer3 = res.push( - { hostname: 'localhost:' + serverPort, port: serverPort, - path : '/pushNotificationsDeliver3', method : 'GET', - headers: {'x-pushed-request': 'true', 'x-foo' : 'bar'}}); + { hostname: 'localhost:' + serverPort, port: serverPort, + path : '/pushNotificationsDeliver3', method : 'GET', + headers: { 'Encryption-Key': 'keyid="notification3";dh="BD3xV_ACT8r6hdIYES3BJj1qhz9wyv7MBrG9vM2UCnjPzwE_YFVpkD-SGqE-BR2--0M-Yf31wctwNsO1qjBUeMg"', + 'Encryption': 'keyid="notification3"; salt="DFq188piWU7osPBgqn4Nlg"; rs=24' + } + }); pushPushServer3.writeHead(200, { - 'content-length' : 2, 'subresource' : '1' }); - pushPushServer3.end('ok'); + + pushPushServer3.end('2caaeedd9cf1059b80c58b6c6827da8ff7de864ac8bea6d5775892c27c005209cbf9c4de0c3fbcddb9711d74eaeebd33f7275374cb42dd48c07168bc2cc9df63e045ce2d2a2408c66088a40c', 'hex'); return; } From 0abf6a52fba1a94c89e968a69ae2959ab6383c50 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Thu, 10 Sep 2015 11:04:01 -0400 Subject: [PATCH 062/131] Bug 1197296. Check the error code of Map. r=bas --HG-- extra : rebase_source : 093468b6ce7df1bafcd3e73288e93555228dc919 --- gfx/thebes/gfxWindowsPlatform.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 6e32380b7eef..dc63dea98661 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -1792,7 +1792,11 @@ bool DoesRenderTargetViewNeedsRecreating(ID3D11Device *device) deviceContext->CopyResource(cpuTexture, offscreenTexture); D3D11_MAPPED_SUBRESOURCE mapped; - deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped); + hr = deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped); + if (FAILED(hr)) { + gfxCriticalNote << "DoesRecreatingMapFailed " << hexa(hr); + return false; + } int resultColor = *(int*)mapped.pData; deviceContext->Unmap(cpuTexture, 0); cpuTexture->Release(); From 863f79b465dff44260740191e7a43f639cdaf844 Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Fri, 11 Sep 2015 08:17:40 -0700 Subject: [PATCH 063/131] Bug 1174510 - Fix fallback from cursor formats that we don't support or that fail to decode to other cursor files. r=seth Although I didn't test this theory, I think it's fixing a regression from patch 3 in bug 1084136 (changeset e7ecd25d7e7c), which stopped clearing other flags when an error occurred. --HG-- extra : transplant_source : %E8%B9%F6%BA-%22%C2s%A59V%DB%F7%D7%9D%A7Vpa2 --- layout/generic/nsFrame.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 9ff132a57fb5..0dabb793d238 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -8299,7 +8299,9 @@ void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui, item < item_end; ++item) { uint32_t status; nsresult rv = item->GetImage()->GetImageStatus(&status); - if (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_LOAD_COMPLETE)) { + if (NS_SUCCEEDED(rv) && + (status & imgIRequest::STATUS_LOAD_COMPLETE) && + !(status & imgIRequest::STATUS_ERROR)) { // This is the one we want item->GetImage()->GetImage(getter_AddRefs(aCursor.mContainer)); aCursor.mHaveHotspot = item->mHaveHotspot; From 85d7b073ac553acea4b3d57c240abd0f97c4a942 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Fri, 4 Sep 2015 20:39:10 -0400 Subject: [PATCH 064/131] Bug 1202828 - use nsEventQueue::HasPendingEvent in nsThread.cpp; r=mccr8 nsEventQueue's HasPending event is defined to simply: return GetEvent(false, nullptr); So we can substitute HasPendingEvent for this particular GetEvent call to make the code clearer. --- xpcom/threads/nsThread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index 188571136141..3e85ac636e55 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -702,7 +702,7 @@ nsThread::HasPendingEvents(bool* aResult) return NS_ERROR_NOT_SAME_THREAD; } - *aResult = mEvents->GetEvent(false, nullptr); + *aResult = mEvents->HasPendingEvent(); return NS_OK; } From e61857780b3b82a41ed2e60da15bb1414ad0da59 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 11 Sep 2015 16:47:03 +0100 Subject: [PATCH 065/131] Bug 1099557 - Make -moz-control-character-visibility default to 'visible' rather than 'hidden', so that spurious control characters are rendered as hexboxes. r=dbaron --- layout/style/nsRuleNode.cpp | 4 ++-- layout/style/nsStyleStruct.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 2d7d9ff4075b..aff7337ce6c1 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -4364,13 +4364,13 @@ nsRuleNode::ComputeTextData(void* aStartStruct, parentText->mTextCombineUpright, NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE, 0, 0, 0, 0); - // -moz-text-discard: enum, inherit, initial + // -moz-control-character-visibility: enum, inherit, initial SetDiscrete(*aRuleData->ValueForControlCharacterVisibility(), text->mControlCharacterVisibility, conditions, SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT, parentText->mControlCharacterVisibility, - NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN, 0, 0, 0, 0); + NS_STYLE_CONTROL_CHARACTER_VISIBILITY_VISIBLE, 0, 0, 0, 0); COMPUTE_END_INHERITED(Text, text) } diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index e1da6f228d16..5635e7df4c7a 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -3408,7 +3408,7 @@ nsStyleText::nsStyleText(void) mRubyPosition = NS_STYLE_RUBY_POSITION_OVER; mTextSizeAdjust = NS_STYLE_TEXT_SIZE_ADJUST_AUTO; mTextCombineUpright = NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE; - mControlCharacterVisibility = NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN; + mControlCharacterVisibility = NS_STYLE_CONTROL_CHARACTER_VISIBILITY_VISIBLE; mLetterSpacing.SetNormalValue(); mLineHeight.SetNormalValue(); From 2338209aaaab86e736bdcb2c58ad6e5c40587c41 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 11 Sep 2015 16:47:34 +0100 Subject: [PATCH 066/131] Bug 1099557 - Reftest to check that stray control characters are visible in HTML content. r=dbaron --HG-- rename : layout/reftests/text/control-chars-01-notref.html => layout/reftests/text/control-chars-04-notref.html rename : layout/reftests/text/control-chars-01a.html => layout/reftests/text/control-chars-04a.html rename : layout/reftests/text/control-chars-01b.html => layout/reftests/text/control-chars-04b.html rename : layout/reftests/text/control-chars-01c.html => layout/reftests/text/control-chars-04c.html rename : layout/reftests/text/control-chars-01d.html => layout/reftests/text/control-chars-04d.html --- layout/reftests/text/control-chars-04-notref.html | 11 +++++++++++ layout/reftests/text/control-chars-04a.html | 11 +++++++++++ layout/reftests/text/control-chars-04b.html | 11 +++++++++++ layout/reftests/text/control-chars-04c.html | 11 +++++++++++ layout/reftests/text/control-chars-04d.html | 11 +++++++++++ layout/reftests/text/reftest.list | 6 +++++- 6 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 layout/reftests/text/control-chars-04-notref.html create mode 100644 layout/reftests/text/control-chars-04a.html create mode 100644 layout/reftests/text/control-chars-04b.html create mode 100644 layout/reftests/text/control-chars-04c.html create mode 100644 layout/reftests/text/control-chars-04d.html diff --git a/layout/reftests/text/control-chars-04-notref.html b/layout/reftests/text/control-chars-04-notref.html new file mode 100644 index 000000000000..97509ce9670e --- /dev/null +++ b/layout/reftests/text/control-chars-04-notref.html @@ -0,0 +1,11 @@ + + + + + + +
    +foobar +
    + + diff --git a/layout/reftests/text/control-chars-04a.html b/layout/reftests/text/control-chars-04a.html new file mode 100644 index 000000000000..9a8e3332db2c --- /dev/null +++ b/layout/reftests/text/control-chars-04a.html @@ -0,0 +1,11 @@ + + + + + + +
    +foobar +
    + + diff --git a/layout/reftests/text/control-chars-04b.html b/layout/reftests/text/control-chars-04b.html new file mode 100644 index 000000000000..48e24b03850c --- /dev/null +++ b/layout/reftests/text/control-chars-04b.html @@ -0,0 +1,11 @@ + + + + + + +
    +foobar +
    + + diff --git a/layout/reftests/text/control-chars-04c.html b/layout/reftests/text/control-chars-04c.html new file mode 100644 index 000000000000..fd5f892c9433 --- /dev/null +++ b/layout/reftests/text/control-chars-04c.html @@ -0,0 +1,11 @@ + + + + + + +
    +foobar +
    + + diff --git a/layout/reftests/text/control-chars-04d.html b/layout/reftests/text/control-chars-04d.html new file mode 100644 index 000000000000..94623baeb674 --- /dev/null +++ b/layout/reftests/text/control-chars-04d.html @@ -0,0 +1,11 @@ + + + + + + +
    +foobar +
    + + diff --git a/layout/reftests/text/reftest.list b/layout/reftests/text/reftest.list index 2a8a30a1c508..d954221543e8 100644 --- a/layout/reftests/text/reftest.list +++ b/layout/reftests/text/reftest.list @@ -305,7 +305,7 @@ fails-if(!cocoaWidget||OSX==1006||OSX==1007) != osx-font-smoothing-2.html osx-fo pref(layout.css.text-align-true-value.enabled,true) == text-align-true.html text-align-true-ref.html -# stray control chars should not be invisible, bug 909344 +# stray control chars should be visible by default, bug 1099557 != control-chars-01a.html control-chars-01-notref.html != control-chars-01b.html control-chars-01-notref.html != control-chars-01c.html control-chars-01-notref.html @@ -313,6 +313,10 @@ pref(layout.css.text-align-true-value.enabled,true) == text-align-true.html text != control-chars-02.html control-chars-02-notref.html == control-chars-03a.html control-chars-03-ref.html == control-chars-03b.html control-chars-03-ref.html +!= control-chars-04a.html control-chars-04-notref.html +!= control-chars-04b.html control-chars-04-notref.html +!= control-chars-04c.html control-chars-04-notref.html +!= control-chars-04d.html control-chars-04-notref.html # font fallback for when not supported in the primary font family - bug 970891 HTTP(..) == space-font-1.html space-font-1-ref.html From 60c4905182d43c630c13656153546bc3758eac22 Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Fri, 17 Oct 2014 14:22:27 -0700 Subject: [PATCH 067/131] Bug 1069762 - CSP: blocked-uri in violation reports should not contain sensitive data - tests (r=sstamm) --- dom/security/test/csp/mochitest.ini | 2 + .../test/csp/test_blocked_uri_in_reports.html | 118 ++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 dom/security/test/csp/test_blocked_uri_in_reports.html diff --git a/dom/security/test/csp/mochitest.ini b/dom/security/test/csp/mochitest.ini index 9bb77e7dd559..13897873308c 100644 --- a/dom/security/test/csp/mochitest.ini +++ b/dom/security/test/csp/mochitest.ini @@ -191,3 +191,5 @@ skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'gonk' || toolk skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'gonk' || toolkit == 'android' [test_upgrade_insecure_cors.html] skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'gonk' || toolkit == 'android' +[test_blocked_uri_in_reports.html] +skip-if = e10s || buildapp == 'b2g' # http-on-opening-request observer not supported in child process (bug 1009632) diff --git a/dom/security/test/csp/test_blocked_uri_in_reports.html b/dom/security/test/csp/test_blocked_uri_in_reports.html new file mode 100644 index 000000000000..fd71e4f0ca64 --- /dev/null +++ b/dom/security/test/csp/test_blocked_uri_in_reports.html @@ -0,0 +1,118 @@ + + + + Bug 1069762 - Check blocked-uri in csp-reports after redirect + + + + + + + + + + From b16155d584af639fcbbdb01cc4139457e400c416 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:25 +0900 Subject: [PATCH 068/131] Bug 895274 part.206 Rename NS_MOZ_TIME_CHANGE_EVENT to eTimeChange r=smaug --- dom/events/EventListenerManager.cpp | 2 +- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index 7ddba2ccfe28..48c39dfb79b2 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -510,7 +510,7 @@ EventListenerManager::RemoveEventListenerInternal( uint32_t typeCount = 0; bool deviceType = IsDeviceType(aEventMessage); #ifdef MOZ_B2G - bool timeChangeEvent = (aEventMessage == NS_MOZ_TIME_CHANGE_EVENT); + bool timeChangeEvent = (aEventMessage == eTimeChange); bool networkEvent = (aEventMessage == NS_NETWORK_UPLOAD_EVENT || aEventMessage == NS_NETWORK_DOWNLOAD_EVENT); #endif // MOZ_B2G diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 3946bf909b37..67e046ece037 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -550,7 +550,7 @@ WINDOW_ONLY_EVENT(devicelight, #ifdef MOZ_B2G WINDOW_ONLY_EVENT(moztimechange, - NS_MOZ_TIME_CHANGE_EVENT, + eTimeChange, EventNameType_None, eBasicEventClass) WINDOW_ONLY_EVENT(moznetworkupload, diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 05285027f0a2..a9b312e73dd2 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -395,7 +395,7 @@ NS_EVENT_MESSAGE(eWheelOperationStart, eWheelEventFirst + 1) NS_EVENT_MESSAGE(eWheelOperationEnd, eWheelEventFirst + 2) //System time is changed -NS_EVENT_MESSAGE(NS_MOZ_TIME_CHANGE_EVENT, 5500) +NS_EVENT_MESSAGE(eTimeChange, 5500) // Network packet events. NS_EVENT_MESSAGE(NS_NETWORK_EVENT_START, 5600) From a7aae5c1170864f27be27ab5ed27da091e31e255 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:26 +0900 Subject: [PATCH 069/131] Bug 895274 part.207 Rename NS_NETWORK_DOWNLOAD_EVENT to eNetworkDownload r=smaug --- dom/base/nsGlobalWindow.cpp | 6 +++--- dom/events/EventListenerManager.cpp | 4 ++-- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 5f9652e9d3c6..ffe82d6cd808 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -1450,7 +1450,7 @@ nsGlobalWindow::CleanUp() #ifdef MOZ_B2G DisableNetworkEvent(NS_NETWORK_UPLOAD_EVENT); - DisableNetworkEvent(NS_NETWORK_DOWNLOAD_EVENT); + DisableNetworkEvent(eNetworkDownload); #endif // MOZ_B2G if (mIdleService) { @@ -14607,7 +14607,7 @@ nsGlobalWindow::EnableNetworkEvent(EventMessage aEventMessage) os->AddObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC, false); } break; - case NS_NETWORK_DOWNLOAD_EVENT: + case eNetworkDownload: if (!mNetworkDownloadObserverEnabled) { mNetworkDownloadObserverEnabled = true; os->AddObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC, false); @@ -14635,7 +14635,7 @@ nsGlobalWindow::DisableNetworkEvent(EventMessage aEventMessage) os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC); } break; - case NS_NETWORK_DOWNLOAD_EVENT: + case eNetworkDownload: if (mNetworkDownloadObserverEnabled) { mNetworkDownloadObserverEnabled = false; os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC); diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index 48c39dfb79b2..aab88d9a19ce 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -339,7 +339,7 @@ EventListenerManager::AddEventListenerInternal( } else if (aTypeAtom == nsGkAtoms::onmoznetworkdownload) { nsCOMPtr window = GetTargetAsInnerWindow(); if (window) { - window->EnableNetworkEvent(NS_NETWORK_DOWNLOAD_EVENT); + window->EnableNetworkEvent(eNetworkDownload); } #endif // MOZ_B2G } else if (aTypeAtom == nsGkAtoms::ontouchstart || @@ -512,7 +512,7 @@ EventListenerManager::RemoveEventListenerInternal( #ifdef MOZ_B2G bool timeChangeEvent = (aEventMessage == eTimeChange); bool networkEvent = (aEventMessage == NS_NETWORK_UPLOAD_EVENT || - aEventMessage == NS_NETWORK_DOWNLOAD_EVENT); + aEventMessage == eNetworkDownload); #endif // MOZ_B2G for (uint32_t i = 0; i < count; ++i) { diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 67e046ece037..a5d6b437c4d7 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -558,7 +558,7 @@ WINDOW_ONLY_EVENT(moznetworkupload, EventNameType_None, eBasicEventClass) WINDOW_ONLY_EVENT(moznetworkdownload, - NS_NETWORK_DOWNLOAD_EVENT, + eNetworkDownload, EventNameType_None, eBasicEventClass) #endif // MOZ_B2G diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index a9b312e73dd2..be1aaf7f406e 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -400,7 +400,7 @@ NS_EVENT_MESSAGE(eTimeChange, 5500) // Network packet events. NS_EVENT_MESSAGE(NS_NETWORK_EVENT_START, 5600) NS_EVENT_MESSAGE(NS_NETWORK_UPLOAD_EVENT, NS_NETWORK_EVENT_START + 1) -NS_EVENT_MESSAGE(NS_NETWORK_DOWNLOAD_EVENT, NS_NETWORK_EVENT_START + 2) +NS_EVENT_MESSAGE(eNetworkDownload, NS_NETWORK_EVENT_START + 2) // MediaRecorder events. NS_EVENT_MESSAGE(NS_MEDIARECORDER_EVENT_START, 5700) From 585a5b420dd0af0e73f405d944099331c5ed5611 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:26 +0900 Subject: [PATCH 070/131] Bug 895274 part.208 Rename NS_NETWORK_UPLOAD_EVENT to eNetworkUpload r=smaug --- dom/base/nsGlobalWindow.cpp | 6 +++--- dom/events/EventListenerManager.cpp | 4 ++-- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index ffe82d6cd808..772d66600c57 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -1449,7 +1449,7 @@ nsGlobalWindow::CleanUp() } #ifdef MOZ_B2G - DisableNetworkEvent(NS_NETWORK_UPLOAD_EVENT); + DisableNetworkEvent(eNetworkUpload); DisableNetworkEvent(eNetworkDownload); #endif // MOZ_B2G @@ -14601,7 +14601,7 @@ nsGlobalWindow::EnableNetworkEvent(EventMessage aEventMessage) } switch (aEventMessage) { - case NS_NETWORK_UPLOAD_EVENT: + case eNetworkUpload: if (!mNetworkUploadObserverEnabled) { mNetworkUploadObserverEnabled = true; os->AddObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC, false); @@ -14629,7 +14629,7 @@ nsGlobalWindow::DisableNetworkEvent(EventMessage aEventMessage) } switch (aEventMessage) { - case NS_NETWORK_UPLOAD_EVENT: + case eNetworkUpload: if (mNetworkUploadObserverEnabled) { mNetworkUploadObserverEnabled = false; os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC); diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index aab88d9a19ce..d5d69f840b62 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -334,7 +334,7 @@ EventListenerManager::AddEventListenerInternal( } else if (aTypeAtom == nsGkAtoms::onmoznetworkupload) { nsCOMPtr window = GetTargetAsInnerWindow(); if (window) { - window->EnableNetworkEvent(NS_NETWORK_UPLOAD_EVENT); + window->EnableNetworkEvent(eNetworkUpload); } } else if (aTypeAtom == nsGkAtoms::onmoznetworkdownload) { nsCOMPtr window = GetTargetAsInnerWindow(); @@ -511,7 +511,7 @@ EventListenerManager::RemoveEventListenerInternal( bool deviceType = IsDeviceType(aEventMessage); #ifdef MOZ_B2G bool timeChangeEvent = (aEventMessage == eTimeChange); - bool networkEvent = (aEventMessage == NS_NETWORK_UPLOAD_EVENT || + bool networkEvent = (aEventMessage == eNetworkUpload || aEventMessage == eNetworkDownload); #endif // MOZ_B2G diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index a5d6b437c4d7..ec4476d276cb 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -554,7 +554,7 @@ WINDOW_ONLY_EVENT(moztimechange, EventNameType_None, eBasicEventClass) WINDOW_ONLY_EVENT(moznetworkupload, - NS_NETWORK_UPLOAD_EVENT, + eNetworkUpload, EventNameType_None, eBasicEventClass) WINDOW_ONLY_EVENT(moznetworkdownload, diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index be1aaf7f406e..76068b5cc881 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -399,7 +399,7 @@ NS_EVENT_MESSAGE(eTimeChange, 5500) // Network packet events. NS_EVENT_MESSAGE(NS_NETWORK_EVENT_START, 5600) -NS_EVENT_MESSAGE(NS_NETWORK_UPLOAD_EVENT, NS_NETWORK_EVENT_START + 1) +NS_EVENT_MESSAGE(eNetworkUpload, NS_NETWORK_EVENT_START + 1) NS_EVENT_MESSAGE(eNetworkDownload, NS_NETWORK_EVENT_START + 2) // MediaRecorder events. From 08b16b6cd2f6ef71d198b67b25cd90073652b16d Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:26 +0900 Subject: [PATCH 071/131] Bug 895274 part.209 Rename NS_NETWORK_EVENT_START to eNetworkEventFirst r=smaug --- widget/EventMessageList.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 76068b5cc881..ce9f258ddbc1 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -398,9 +398,9 @@ NS_EVENT_MESSAGE(eWheelOperationEnd, eWheelEventFirst + 2) NS_EVENT_MESSAGE(eTimeChange, 5500) // Network packet events. -NS_EVENT_MESSAGE(NS_NETWORK_EVENT_START, 5600) -NS_EVENT_MESSAGE(eNetworkUpload, NS_NETWORK_EVENT_START + 1) -NS_EVENT_MESSAGE(eNetworkDownload, NS_NETWORK_EVENT_START + 2) +NS_EVENT_MESSAGE(eNetworkEventFirst, 5600) +NS_EVENT_MESSAGE(eNetworkUpload, eNetworkEventFirst + 1) +NS_EVENT_MESSAGE(eNetworkDownload, eNetworkEventFirst + 2) // MediaRecorder events. NS_EVENT_MESSAGE(NS_MEDIARECORDER_EVENT_START, 5700) From 63339aed2695a666562860889361ad1b012a2542 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:26 +0900 Subject: [PATCH 072/131] Bug 895274 part.210 Rename NS_POINTERLOCK_START to ePointerLockEventFirst r=smaug --- widget/EventMessageList.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index ce9f258ddbc1..30b10acc5dfd 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -378,9 +378,9 @@ NS_EVENT_MESSAGE(NS_TOUCH_END, NS_TOUCH_EVENT_START + 2) NS_EVENT_MESSAGE(NS_TOUCH_CANCEL, NS_TOUCH_EVENT_START + 3) // Pointerlock DOM API -NS_EVENT_MESSAGE(NS_POINTERLOCK_START, 5300) -NS_EVENT_MESSAGE(NS_POINTERLOCKCHANGE, NS_POINTERLOCK_START) -NS_EVENT_MESSAGE(NS_POINTERLOCKERROR, NS_POINTERLOCK_START + 1) +NS_EVENT_MESSAGE(ePointerLockEventFirst, 5300) +NS_EVENT_MESSAGE(NS_POINTERLOCKCHANGE, ePointerLockEventFirst) +NS_EVENT_MESSAGE(NS_POINTERLOCKERROR, ePointerLockEventFirst + 1) NS_EVENT_MESSAGE(eWheelEventFirst, 5400) // eWheel is the event message of DOM wheel event. From e6d530e97c605b19447fe066e29b9b3347aa38cf Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:26 +0900 Subject: [PATCH 073/131] Bug 895274 part.211 Rename NS_POINTERLOCKCHANGE to ePointerLockChange r=smaug --- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index ec4476d276cb..ddc699999459 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -303,7 +303,7 @@ EVENT(mozfullscreenerror, EventNameType_HTML, eBasicEventClass) EVENT(mozpointerlockchange, - NS_POINTERLOCKCHANGE, + ePointerLockChange, EventNameType_HTML, eBasicEventClass) EVENT(mozpointerlockerror, diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 30b10acc5dfd..fe54e7539456 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -379,7 +379,7 @@ NS_EVENT_MESSAGE(NS_TOUCH_CANCEL, NS_TOUCH_EVENT_START + 3) // Pointerlock DOM API NS_EVENT_MESSAGE(ePointerLockEventFirst, 5300) -NS_EVENT_MESSAGE(NS_POINTERLOCKCHANGE, ePointerLockEventFirst) +NS_EVENT_MESSAGE(ePointerLockChange, ePointerLockEventFirst) NS_EVENT_MESSAGE(NS_POINTERLOCKERROR, ePointerLockEventFirst + 1) NS_EVENT_MESSAGE(eWheelEventFirst, 5400) From 43c26f84509b8c61f6481e506670a14d4034fe9d Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:26 +0900 Subject: [PATCH 074/131] Bug 895274 part.212 Rename NS_POINTERLOCKERROR to ePointerLockError r=smaug --- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index ddc699999459..9f1cd2a629ce 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -307,7 +307,7 @@ EVENT(mozpointerlockchange, EventNameType_HTML, eBasicEventClass) EVENT(mozpointerlockerror, - NS_POINTERLOCKERROR, + ePointerLockError, EventNameType_HTML, eBasicEventClass) EVENT(pointerdown, diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index fe54e7539456..0110dcb56f6f 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -380,7 +380,7 @@ NS_EVENT_MESSAGE(NS_TOUCH_CANCEL, NS_TOUCH_EVENT_START + 3) // Pointerlock DOM API NS_EVENT_MESSAGE(ePointerLockEventFirst, 5300) NS_EVENT_MESSAGE(ePointerLockChange, ePointerLockEventFirst) -NS_EVENT_MESSAGE(NS_POINTERLOCKERROR, ePointerLockEventFirst + 1) +NS_EVENT_MESSAGE(ePointerLockError, ePointerLockEventFirst + 1) NS_EVENT_MESSAGE(eWheelEventFirst, 5400) // eWheel is the event message of DOM wheel event. From 2237026931e1e241a3c1bd70513595643c2e853e Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:27 +0900 Subject: [PATCH 075/131] Bug 895274 part.213 Rename NS_SCROLLPORT_OVERFLOW to eScrollPortOverflow r=smaug --- dom/events/EventNameList.h | 2 +- dom/html/HTMLInputElement.cpp | 2 +- layout/generic/nsGfxScrollFrame.cpp | 2 +- layout/xul/tree/nsTreeBodyFrame.cpp | 4 ++-- widget/EventMessageList.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 9f1cd2a629ce..9d5f2443dd81 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -732,7 +732,7 @@ NON_IDL_EVENT(draggesture, EventNameType_XUL, eDragEventClass) NON_IDL_EVENT(overflow, - NS_SCROLLPORT_OVERFLOW, + eScrollPortOverflow, EventNameType_XUL, eBasicEventClass) NON_IDL_EVENT(underflow, diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 3b20335f90d8..8bf48e9cd856 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -3035,7 +3035,7 @@ HTMLInputElement::NeedToInitializeEditorForEvent( case eMouseOver: case eMouseOut: case NS_SCROLLPORT_UNDERFLOW: - case NS_SCROLLPORT_OVERFLOW: + case eScrollPortOverflow: return false; default: return true; diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index aed21a2b350c..3a20eb5569aa 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -3753,7 +3753,7 @@ ScrollFrameHelper::FireScrollPortEvent() InternalScrollPortEvent event(true, (orient == InternalScrollPortEvent::horizontal ? mHorizontalOverflow : mVerticalOverflow) ? - NS_SCROLLPORT_OVERFLOW : NS_SCROLLPORT_UNDERFLOW, nullptr); + eScrollPortOverflow : NS_SCROLLPORT_UNDERFLOW, nullptr); event.orient = orient; return EventDispatcher::Dispatch(mOuter->GetContent(), mOuter->PresContext(), &event); diff --git a/layout/xul/tree/nsTreeBodyFrame.cpp b/layout/xul/tree/nsTreeBodyFrame.cpp index 90814109c099..e2f478dc1415 100644 --- a/layout/xul/tree/nsTreeBodyFrame.cpp +++ b/layout/xul/tree/nsTreeBodyFrame.cpp @@ -917,7 +917,7 @@ nsTreeBodyFrame::CheckOverflow(const ScrollParts& aParts) if (verticalOverflowChanged) { InternalScrollPortEvent event(true, - mVerticalOverflow ? NS_SCROLLPORT_OVERFLOW : NS_SCROLLPORT_UNDERFLOW, + mVerticalOverflow ? eScrollPortOverflow : NS_SCROLLPORT_UNDERFLOW, nullptr); event.orient = InternalScrollPortEvent::vertical; EventDispatcher::Dispatch(content, presContext, &event); @@ -925,7 +925,7 @@ nsTreeBodyFrame::CheckOverflow(const ScrollParts& aParts) if (horizontalOverflowChanged) { InternalScrollPortEvent event(true, - mHorizontalOverflow ? NS_SCROLLPORT_OVERFLOW : NS_SCROLLPORT_UNDERFLOW, + mHorizontalOverflow ? eScrollPortOverflow : NS_SCROLLPORT_UNDERFLOW, nullptr); event.orient = InternalScrollPortEvent::horizontal; EventDispatcher::Dispatch(content, presContext, &event); diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 0110dcb56f6f..ff2a0230ef21 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -130,7 +130,7 @@ NS_EVENT_MESSAGE(eLegacyMousePixelScroll, eLegacyMouseScrollEventFirst + 1) NS_EVENT_MESSAGE(NS_SCROLLPORT_START, 1700) NS_EVENT_MESSAGE(NS_SCROLLPORT_UNDERFLOW, NS_SCROLLPORT_START) -NS_EVENT_MESSAGE(NS_SCROLLPORT_OVERFLOW, NS_SCROLLPORT_START + 1) +NS_EVENT_MESSAGE(eScrollPortOverflow, NS_SCROLLPORT_START + 1) NS_EVENT_MESSAGE(eLegacyMutationEventFirst, 1800) NS_EVENT_MESSAGE(eLegacySubtreeModified, eLegacyMutationEventFirst) From 93a08167ad5c7dca28d61b15a5a54a17c5935d66 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:27 +0900 Subject: [PATCH 076/131] Bug 895274 part.214 Rename NS_SCROLLPORT_UNDERFLOW to eScrollPortUnderflow r=smaug --- dom/events/EventNameList.h | 2 +- dom/html/HTMLInputElement.cpp | 2 +- layout/generic/nsGfxScrollFrame.cpp | 2 +- layout/xul/tree/nsTreeBodyFrame.cpp | 4 ++-- widget/EventMessageList.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 9d5f2443dd81..183a1ac813e7 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -736,7 +736,7 @@ NON_IDL_EVENT(overflow, EventNameType_XUL, eBasicEventClass) NON_IDL_EVENT(underflow, - NS_SCROLLPORT_UNDERFLOW, + eScrollPortUnderflow, EventNameType_XUL, eBasicEventClass) diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 8bf48e9cd856..9879ca0dc583 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -3034,7 +3034,7 @@ HTMLInputElement::NeedToInitializeEditorForEvent( case eMouseExitFromWidget: case eMouseOver: case eMouseOut: - case NS_SCROLLPORT_UNDERFLOW: + case eScrollPortUnderflow: case eScrollPortOverflow: return false; default: diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 3a20eb5569aa..63e4c3473eb1 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -3753,7 +3753,7 @@ ScrollFrameHelper::FireScrollPortEvent() InternalScrollPortEvent event(true, (orient == InternalScrollPortEvent::horizontal ? mHorizontalOverflow : mVerticalOverflow) ? - eScrollPortOverflow : NS_SCROLLPORT_UNDERFLOW, nullptr); + eScrollPortOverflow : eScrollPortUnderflow, nullptr); event.orient = orient; return EventDispatcher::Dispatch(mOuter->GetContent(), mOuter->PresContext(), &event); diff --git a/layout/xul/tree/nsTreeBodyFrame.cpp b/layout/xul/tree/nsTreeBodyFrame.cpp index e2f478dc1415..d7347dd69547 100644 --- a/layout/xul/tree/nsTreeBodyFrame.cpp +++ b/layout/xul/tree/nsTreeBodyFrame.cpp @@ -917,7 +917,7 @@ nsTreeBodyFrame::CheckOverflow(const ScrollParts& aParts) if (verticalOverflowChanged) { InternalScrollPortEvent event(true, - mVerticalOverflow ? eScrollPortOverflow : NS_SCROLLPORT_UNDERFLOW, + mVerticalOverflow ? eScrollPortOverflow : eScrollPortUnderflow, nullptr); event.orient = InternalScrollPortEvent::vertical; EventDispatcher::Dispatch(content, presContext, &event); @@ -925,7 +925,7 @@ nsTreeBodyFrame::CheckOverflow(const ScrollParts& aParts) if (horizontalOverflowChanged) { InternalScrollPortEvent event(true, - mHorizontalOverflow ? eScrollPortOverflow : NS_SCROLLPORT_UNDERFLOW, + mHorizontalOverflow ? eScrollPortOverflow : eScrollPortUnderflow, nullptr); event.orient = InternalScrollPortEvent::horizontal; EventDispatcher::Dispatch(content, presContext, &event); diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index ff2a0230ef21..8b9b97341052 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -129,7 +129,7 @@ NS_EVENT_MESSAGE(eLegacyMouseLineOrPageScroll, eLegacyMouseScrollEventFirst) NS_EVENT_MESSAGE(eLegacyMousePixelScroll, eLegacyMouseScrollEventFirst + 1) NS_EVENT_MESSAGE(NS_SCROLLPORT_START, 1700) -NS_EVENT_MESSAGE(NS_SCROLLPORT_UNDERFLOW, NS_SCROLLPORT_START) +NS_EVENT_MESSAGE(eScrollPortUnderflow, NS_SCROLLPORT_START) NS_EVENT_MESSAGE(eScrollPortOverflow, NS_SCROLLPORT_START + 1) NS_EVENT_MESSAGE(eLegacyMutationEventFirst, 1800) From 9e8aa4e31ca23fcaf4b37c236f5b3af0c0c7dc4f Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:27 +0900 Subject: [PATCH 077/131] Bug 895274 part.215 Rename NS_SCROLLPORT_START to eScrollPortEventFirst r=smaug --- widget/EventMessageList.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 8b9b97341052..4a169a4e3785 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -128,9 +128,9 @@ NS_EVENT_MESSAGE(eLegacyMouseScrollEventFirst, 1600) NS_EVENT_MESSAGE(eLegacyMouseLineOrPageScroll, eLegacyMouseScrollEventFirst) NS_EVENT_MESSAGE(eLegacyMousePixelScroll, eLegacyMouseScrollEventFirst + 1) -NS_EVENT_MESSAGE(NS_SCROLLPORT_START, 1700) -NS_EVENT_MESSAGE(eScrollPortUnderflow, NS_SCROLLPORT_START) -NS_EVENT_MESSAGE(eScrollPortOverflow, NS_SCROLLPORT_START + 1) +NS_EVENT_MESSAGE(eScrollPortEventFirst, 1700) +NS_EVENT_MESSAGE(eScrollPortUnderflow, eScrollPortEventFirst) +NS_EVENT_MESSAGE(eScrollPortOverflow, eScrollPortEventFirst + 1) NS_EVENT_MESSAGE(eLegacyMutationEventFirst, 1800) NS_EVENT_MESSAGE(eLegacySubtreeModified, eLegacyMutationEventFirst) From ae789a7c596cc8d2ccfc109ceab6bccab68afc6d Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:27 +0900 Subject: [PATCH 078/131] Bug 895274 part.216 Rename NS_SCROLLAREA_EVENT_START to eScrolledAreaEventFirst r=smaug --- widget/EventMessageList.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 4a169a4e3785..4d408fbc61b5 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -320,8 +320,8 @@ NS_EVENT_MESSAGE(NS_GESTURENOTIFY_EVENT_START, 3900) NS_EVENT_MESSAGE(NS_ORIENTATION_EVENT, 4000) -NS_EVENT_MESSAGE(NS_SCROLLAREA_EVENT_START, 4100) -NS_EVENT_MESSAGE(NS_SCROLLEDAREACHANGED, NS_SCROLLAREA_EVENT_START) +NS_EVENT_MESSAGE(eScrolledAreaEventFirst, 4100) +NS_EVENT_MESSAGE(NS_SCROLLEDAREACHANGED, eScrolledAreaEventFirst) NS_EVENT_MESSAGE(NS_TRANSITION_EVENT_START, 4200) NS_EVENT_MESSAGE(NS_TRANSITION_END, NS_TRANSITION_EVENT_START) From 18894de95908a23a7338fba7a77a017b9cf3e444 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:27 +0900 Subject: [PATCH 079/131] Bug 895274 part.217 Rename NS_SCROLLEDAREACHANGE to eScrolledAreaChanged r=smaug --- dom/events/EventNameList.h | 2 +- layout/generic/nsGfxScrollFrame.cpp | 2 +- widget/EventMessageList.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 183a1ac813e7..a88933070a86 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -811,7 +811,7 @@ NON_IDL_EVENT(MozAfterPaint, eBasicEventClass) NON_IDL_EVENT(MozScrolledAreaChanged, - NS_SCROLLEDAREACHANGED, + eScrolledAreaChanged, EventNameType_None, eScrollAreaEventClass) diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 63e4c3473eb1..257bc4f526a9 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -5324,7 +5324,7 @@ ScrollFrameHelper::FireScrolledAreaEvent() { mScrolledAreaEvent.Forget(); - InternalScrollAreaEvent event(true, NS_SCROLLEDAREACHANGED, nullptr); + InternalScrollAreaEvent event(true, eScrolledAreaChanged, nullptr); nsPresContext *prescontext = mOuter->PresContext(); nsIContent* content = mOuter->GetContent(); diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 4d408fbc61b5..84446f627b1f 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -321,7 +321,7 @@ NS_EVENT_MESSAGE(NS_GESTURENOTIFY_EVENT_START, 3900) NS_EVENT_MESSAGE(NS_ORIENTATION_EVENT, 4000) NS_EVENT_MESSAGE(eScrolledAreaEventFirst, 4100) -NS_EVENT_MESSAGE(NS_SCROLLEDAREACHANGED, eScrolledAreaEventFirst) +NS_EVENT_MESSAGE(eScrolledAreaChanged, eScrolledAreaEventFirst) NS_EVENT_MESSAGE(NS_TRANSITION_EVENT_START, 4200) NS_EVENT_MESSAGE(NS_TRANSITION_END, NS_TRANSITION_EVENT_START) From 0574db1cbdbdfdaeb2491e67c7ee8f164c0b83b2 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:27 +0900 Subject: [PATCH 080/131] Bug 895274 part.218 Remove NS_ORIENTATION_EVENT due to unused r=smaug --- widget/EventMessageList.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 84446f627b1f..288649709961 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -318,8 +318,6 @@ NS_EVENT_MESSAGE(eContentCommandScroll, eContentCommandEventFirst + 7 // Event to gesture notification NS_EVENT_MESSAGE(NS_GESTURENOTIFY_EVENT_START, 3900) -NS_EVENT_MESSAGE(NS_ORIENTATION_EVENT, 4000) - NS_EVENT_MESSAGE(eScrolledAreaEventFirst, 4100) NS_EVENT_MESSAGE(eScrolledAreaChanged, eScrolledAreaEventFirst) From ada4e843de3bf1e96666c1b2036268e2aee3e4bc Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:28 +0900 Subject: [PATCH 081/131] Bug 895274 part.219 Rename NS_GESTURENOTIFY_EVENT_START to eGestureNotify r=smaug --- dom/events/EventStateManager.cpp | 4 ++-- widget/EventMessageList.h | 2 +- widget/windows/nsWindow.cpp | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index 4c190bd04734..9dc3cad998c9 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -2563,7 +2563,7 @@ EventStateManager::DecideGestureEvent(WidgetGestureNotifyEvent* aEvent, nsIFrame* targetFrame) { - NS_ASSERTION(aEvent->mMessage == NS_GESTURENOTIFY_EVENT_START, + NS_ASSERTION(aEvent->mMessage == eGestureNotify, "DecideGestureEvent called with a non-gesture event"); /* Check the ancestor tree to decide if any frame is willing* to receive @@ -3133,7 +3133,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext, } break; - case NS_GESTURENOTIFY_EVENT_START: + case eGestureNotify: { if (nsEventStatus_eConsumeNoDefault != *aStatus) { DecideGestureEvent(aEvent->AsGestureNotifyEvent(), mCurrentTarget); diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 288649709961..b0da052521ed 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -316,7 +316,7 @@ NS_EVENT_MESSAGE(eContentCommandPasteTransferable, eContentCommandEventFirst + 6 NS_EVENT_MESSAGE(eContentCommandScroll, eContentCommandEventFirst + 7) // Event to gesture notification -NS_EVENT_MESSAGE(NS_GESTURENOTIFY_EVENT_START, 3900) +NS_EVENT_MESSAGE(eGestureNotify, 3900) NS_EVENT_MESSAGE(eScrolledAreaEventFirst, 4100) NS_EVENT_MESSAGE(eScrolledAreaChanged, eScrolledAreaEventFirst) diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 1a4d468136e4..813783545fab 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -5633,8 +5633,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam, nsPointWin touchPoint; touchPoint = gestureinfo->ptsLocation; touchPoint.ScreenToClient(mWnd); - WidgetGestureNotifyEvent gestureNotifyEvent(true, - NS_GESTURENOTIFY_EVENT_START, this); + WidgetGestureNotifyEvent gestureNotifyEvent(true, eGestureNotify, this); gestureNotifyEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(touchPoint); nsEventStatus status; DispatchEvent(&gestureNotifyEvent, status); From a289282e10709f850ab1a37e54a8f1eb66d853ec Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:28 +0900 Subject: [PATCH 082/131] Bug 895274 part.220 Rename NS_PRINT_EVENT_START to ePrintEventFirst r=smaug --- widget/EventMessageList.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index b0da052521ed..462bfd999d1a 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -343,9 +343,9 @@ NS_EVENT_MESSAGE(eScriptEventFirst, 4500) NS_EVENT_MESSAGE(eBeforeScriptExecute, eScriptEventFirst) NS_EVENT_MESSAGE(eAfterScriptExecute, eScriptEventFirst + 1) -NS_EVENT_MESSAGE(NS_PRINT_EVENT_START, 4600) -NS_EVENT_MESSAGE(NS_BEFOREPRINT, NS_PRINT_EVENT_START) -NS_EVENT_MESSAGE(NS_AFTERPRINT, NS_PRINT_EVENT_START + 1) +NS_EVENT_MESSAGE(ePrintEventFirst, 4600) +NS_EVENT_MESSAGE(NS_BEFOREPRINT, ePrintEventFirst) +NS_EVENT_MESSAGE(NS_AFTERPRINT, ePrintEventFirst + 1) NS_EVENT_MESSAGE(NS_MESSAGE_EVENT_START, 4700) NS_EVENT_MESSAGE(NS_MESSAGE, NS_MESSAGE_EVENT_START) From 9151616481c918a2d8c69e7195cbdb445c99d79f Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:28 +0900 Subject: [PATCH 083/131] Bug 895274 part.221 Rename NS_BEFOREPRINT to eBeforePrint r=smaug --- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index a88933070a86..9640cc8a7bed 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -473,7 +473,7 @@ WINDOW_EVENT(afterprint, EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly, eBasicEventClass) WINDOW_EVENT(beforeprint, - NS_BEFOREPRINT, + eBeforePrint, EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly, eBasicEventClass) BEFOREUNLOAD_EVENT(beforeunload, diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 462bfd999d1a..3f4b911b9c79 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -344,7 +344,7 @@ NS_EVENT_MESSAGE(eBeforeScriptExecute, eScriptEventFirst) NS_EVENT_MESSAGE(eAfterScriptExecute, eScriptEventFirst + 1) NS_EVENT_MESSAGE(ePrintEventFirst, 4600) -NS_EVENT_MESSAGE(NS_BEFOREPRINT, ePrintEventFirst) +NS_EVENT_MESSAGE(eBeforePrint, ePrintEventFirst) NS_EVENT_MESSAGE(NS_AFTERPRINT, ePrintEventFirst + 1) NS_EVENT_MESSAGE(NS_MESSAGE_EVENT_START, 4700) From ab9946a446e8d19c619d4753b97ef0af867c90ae Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:28 +0900 Subject: [PATCH 084/131] Bug 895274 part.222 Rename NS_AFTERPRINT to eAfterPrint r=smaug --- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 9640cc8a7bed..23e2d277e31c 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -469,7 +469,7 @@ FORWARDED_EVENT(scroll, eBasicEventClass) WINDOW_EVENT(afterprint, - NS_AFTERPRINT, + eAfterPrint, EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly, eBasicEventClass) WINDOW_EVENT(beforeprint, diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 3f4b911b9c79..fcc65a802b3c 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -345,7 +345,7 @@ NS_EVENT_MESSAGE(eAfterScriptExecute, eScriptEventFirst + 1) NS_EVENT_MESSAGE(ePrintEventFirst, 4600) NS_EVENT_MESSAGE(eBeforePrint, ePrintEventFirst) -NS_EVENT_MESSAGE(NS_AFTERPRINT, ePrintEventFirst + 1) +NS_EVENT_MESSAGE(eAfterPrint, ePrintEventFirst + 1) NS_EVENT_MESSAGE(NS_MESSAGE_EVENT_START, 4700) NS_EVENT_MESSAGE(NS_MESSAGE, NS_MESSAGE_EVENT_START) From 51ecb52487360b02ce76a5203563483c4a29344c Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:28 +0900 Subject: [PATCH 085/131] Bug 895274 part.223 Rename NS_DEVICE_ORIENTATION_START to eDeviceEventFirst r=smaug --- widget/EventMessageList.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index fcc65a802b3c..7b1880c37102 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -355,12 +355,12 @@ NS_EVENT_MESSAGE(eOpenCloseEventFirst, 4800) NS_EVENT_MESSAGE(eOpen, eOpenCloseEventFirst) // Device motion and orientation -NS_EVENT_MESSAGE(NS_DEVICE_ORIENTATION_START, 4900) -NS_EVENT_MESSAGE(NS_DEVICE_ORIENTATION, NS_DEVICE_ORIENTATION_START) -NS_EVENT_MESSAGE(NS_DEVICE_MOTION, NS_DEVICE_ORIENTATION_START + 1) -NS_EVENT_MESSAGE(NS_DEVICE_PROXIMITY, NS_DEVICE_ORIENTATION_START + 2) -NS_EVENT_MESSAGE(NS_USER_PROXIMITY, NS_DEVICE_ORIENTATION_START + 3) -NS_EVENT_MESSAGE(NS_DEVICE_LIGHT, NS_DEVICE_ORIENTATION_START + 4) +NS_EVENT_MESSAGE(eDeviceEventFirst, 4900) +NS_EVENT_MESSAGE(NS_DEVICE_ORIENTATION, eDeviceEventFirst) +NS_EVENT_MESSAGE(NS_DEVICE_MOTION, eDeviceEventFirst + 1) +NS_EVENT_MESSAGE(NS_DEVICE_PROXIMITY, eDeviceEventFirst + 2) +NS_EVENT_MESSAGE(NS_USER_PROXIMITY, eDeviceEventFirst + 3) +NS_EVENT_MESSAGE(NS_DEVICE_LIGHT, eDeviceEventFirst + 4) NS_EVENT_MESSAGE(NS_SHOW_EVENT, 5000) From 6cde63ca22d95e81ef6f08abce207d26f4d6d3fe Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:28 +0900 Subject: [PATCH 086/131] Bug 895274 part.224 Rename NS_DEVICE_ORIENTATION to eDeviceOrientation r=smaug --- dom/events/EventListenerManager.cpp | 8 ++++---- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index d5d69f840b62..9ee35f6c5254 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -318,7 +318,7 @@ EventListenerManager::AddEventListenerInternal( kAllMutationBits : MutationBitForEventType(aEventMessage)); } } else if (aTypeAtom == nsGkAtoms::ondeviceorientation) { - EnableDevice(NS_DEVICE_ORIENTATION); + EnableDevice(eDeviceOrientation); } else if (aTypeAtom == nsGkAtoms::ondeviceproximity || aTypeAtom == nsGkAtoms::onuserproximity) { EnableDevice(NS_DEVICE_PROXIMITY); } else if (aTypeAtom == nsGkAtoms::ondevicelight) { @@ -419,7 +419,7 @@ bool EventListenerManager::IsDeviceType(EventMessage aEventMessage) { switch (aEventMessage) { - case NS_DEVICE_ORIENTATION: + case eDeviceOrientation: case NS_DEVICE_MOTION: case NS_DEVICE_LIGHT: case NS_DEVICE_PROXIMITY: @@ -440,7 +440,7 @@ EventListenerManager::EnableDevice(EventMessage aEventMessage) } switch (aEventMessage) { - case NS_DEVICE_ORIENTATION: + case eDeviceOrientation: window->EnableDeviceSensor(SENSOR_ORIENTATION); break; case NS_DEVICE_PROXIMITY: @@ -470,7 +470,7 @@ EventListenerManager::DisableDevice(EventMessage aEventMessage) } switch (aEventMessage) { - case NS_DEVICE_ORIENTATION: + case eDeviceOrientation: window->DisableDeviceSensor(SENSOR_ORIENTATION); break; case NS_DEVICE_MOTION: diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 23e2d277e31c..21a9610f3a2b 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -532,7 +532,7 @@ WINDOW_ONLY_EVENT(devicemotion, EventNameType_None, eBasicEventClass) WINDOW_ONLY_EVENT(deviceorientation, - NS_DEVICE_ORIENTATION, + eDeviceOrientation, EventNameType_None, eBasicEventClass) WINDOW_ONLY_EVENT(deviceproximity, diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 7b1880c37102..4a5d810ded57 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -356,7 +356,7 @@ NS_EVENT_MESSAGE(eOpen, eOpenCloseEventFirst) // Device motion and orientation NS_EVENT_MESSAGE(eDeviceEventFirst, 4900) -NS_EVENT_MESSAGE(NS_DEVICE_ORIENTATION, eDeviceEventFirst) +NS_EVENT_MESSAGE(eDeviceOrientation, eDeviceEventFirst) NS_EVENT_MESSAGE(NS_DEVICE_MOTION, eDeviceEventFirst + 1) NS_EVENT_MESSAGE(NS_DEVICE_PROXIMITY, eDeviceEventFirst + 2) NS_EVENT_MESSAGE(NS_USER_PROXIMITY, eDeviceEventFirst + 3) From d8412db0d977b81a342b651b8c8117d53356fc74 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:28 +0900 Subject: [PATCH 087/131] Bug 895274 part.225 Rename NS_DEVICE_MOTION to eDeviceMotion r=smaug --- dom/events/EventListenerManager.cpp | 8 ++++---- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index 9ee35f6c5254..7135ea537fcc 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -324,7 +324,7 @@ EventListenerManager::AddEventListenerInternal( } else if (aTypeAtom == nsGkAtoms::ondevicelight) { EnableDevice(NS_DEVICE_LIGHT); } else if (aTypeAtom == nsGkAtoms::ondevicemotion) { - EnableDevice(NS_DEVICE_MOTION); + EnableDevice(eDeviceMotion); #ifdef MOZ_B2G } else if (aTypeAtom == nsGkAtoms::onmoztimechange) { nsCOMPtr window = GetTargetAsInnerWindow(); @@ -420,7 +420,7 @@ EventListenerManager::IsDeviceType(EventMessage aEventMessage) { switch (aEventMessage) { case eDeviceOrientation: - case NS_DEVICE_MOTION: + case eDeviceMotion: case NS_DEVICE_LIGHT: case NS_DEVICE_PROXIMITY: case NS_USER_PROXIMITY: @@ -450,7 +450,7 @@ EventListenerManager::EnableDevice(EventMessage aEventMessage) case NS_DEVICE_LIGHT: window->EnableDeviceSensor(SENSOR_LIGHT); break; - case NS_DEVICE_MOTION: + case eDeviceMotion: window->EnableDeviceSensor(SENSOR_ACCELERATION); window->EnableDeviceSensor(SENSOR_LINEAR_ACCELERATION); window->EnableDeviceSensor(SENSOR_GYROSCOPE); @@ -473,7 +473,7 @@ EventListenerManager::DisableDevice(EventMessage aEventMessage) case eDeviceOrientation: window->DisableDeviceSensor(SENSOR_ORIENTATION); break; - case NS_DEVICE_MOTION: + case eDeviceMotion: window->DisableDeviceSensor(SENSOR_ACCELERATION); window->DisableDeviceSensor(SENSOR_LINEAR_ACCELERATION); window->DisableDeviceSensor(SENSOR_GYROSCOPE); diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 21a9610f3a2b..1dec043a29cf 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -528,7 +528,7 @@ WINDOW_EVENT(unload, eBasicEventClass) WINDOW_ONLY_EVENT(devicemotion, - NS_DEVICE_MOTION, + eDeviceMotion, EventNameType_None, eBasicEventClass) WINDOW_ONLY_EVENT(deviceorientation, diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 4a5d810ded57..9a478542e029 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -357,7 +357,7 @@ NS_EVENT_MESSAGE(eOpen, eOpenCloseEventFirst) // Device motion and orientation NS_EVENT_MESSAGE(eDeviceEventFirst, 4900) NS_EVENT_MESSAGE(eDeviceOrientation, eDeviceEventFirst) -NS_EVENT_MESSAGE(NS_DEVICE_MOTION, eDeviceEventFirst + 1) +NS_EVENT_MESSAGE(eDeviceMotion, eDeviceEventFirst + 1) NS_EVENT_MESSAGE(NS_DEVICE_PROXIMITY, eDeviceEventFirst + 2) NS_EVENT_MESSAGE(NS_USER_PROXIMITY, eDeviceEventFirst + 3) NS_EVENT_MESSAGE(NS_DEVICE_LIGHT, eDeviceEventFirst + 4) From ab55bf9a3f278506bf5090d8ac998ecdfad3b7f6 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:28 +0900 Subject: [PATCH 088/131] Bug 895274 part.226 Rename NS_DEVICE_PROXIMITY to eDeviceProximity r=smaug --- dom/events/EventListenerManager.cpp | 8 ++++---- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index 7135ea537fcc..1f52ed063f5e 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -320,7 +320,7 @@ EventListenerManager::AddEventListenerInternal( } else if (aTypeAtom == nsGkAtoms::ondeviceorientation) { EnableDevice(eDeviceOrientation); } else if (aTypeAtom == nsGkAtoms::ondeviceproximity || aTypeAtom == nsGkAtoms::onuserproximity) { - EnableDevice(NS_DEVICE_PROXIMITY); + EnableDevice(eDeviceProximity); } else if (aTypeAtom == nsGkAtoms::ondevicelight) { EnableDevice(NS_DEVICE_LIGHT); } else if (aTypeAtom == nsGkAtoms::ondevicemotion) { @@ -422,7 +422,7 @@ EventListenerManager::IsDeviceType(EventMessage aEventMessage) case eDeviceOrientation: case eDeviceMotion: case NS_DEVICE_LIGHT: - case NS_DEVICE_PROXIMITY: + case eDeviceProximity: case NS_USER_PROXIMITY: return true; default: @@ -443,7 +443,7 @@ EventListenerManager::EnableDevice(EventMessage aEventMessage) case eDeviceOrientation: window->EnableDeviceSensor(SENSOR_ORIENTATION); break; - case NS_DEVICE_PROXIMITY: + case eDeviceProximity: case NS_USER_PROXIMITY: window->EnableDeviceSensor(SENSOR_PROXIMITY); break; @@ -478,7 +478,7 @@ EventListenerManager::DisableDevice(EventMessage aEventMessage) window->DisableDeviceSensor(SENSOR_LINEAR_ACCELERATION); window->DisableDeviceSensor(SENSOR_GYROSCOPE); break; - case NS_DEVICE_PROXIMITY: + case eDeviceProximity: case NS_USER_PROXIMITY: window->DisableDeviceSensor(SENSOR_PROXIMITY); break; diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 1dec043a29cf..4e3f4f666816 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -536,7 +536,7 @@ WINDOW_ONLY_EVENT(deviceorientation, EventNameType_None, eBasicEventClass) WINDOW_ONLY_EVENT(deviceproximity, - NS_DEVICE_PROXIMITY, + eDeviceProximity, EventNameType_None, eBasicEventClass) WINDOW_ONLY_EVENT(userproximity, diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 9a478542e029..4d2f65570499 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -358,7 +358,7 @@ NS_EVENT_MESSAGE(eOpen, eOpenCloseEventFirst) NS_EVENT_MESSAGE(eDeviceEventFirst, 4900) NS_EVENT_MESSAGE(eDeviceOrientation, eDeviceEventFirst) NS_EVENT_MESSAGE(eDeviceMotion, eDeviceEventFirst + 1) -NS_EVENT_MESSAGE(NS_DEVICE_PROXIMITY, eDeviceEventFirst + 2) +NS_EVENT_MESSAGE(eDeviceProximity, eDeviceEventFirst + 2) NS_EVENT_MESSAGE(NS_USER_PROXIMITY, eDeviceEventFirst + 3) NS_EVENT_MESSAGE(NS_DEVICE_LIGHT, eDeviceEventFirst + 4) From 899fffeb6b5c0d925ff0b8ccdee2c851779e2549 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:28 +0900 Subject: [PATCH 089/131] Bug 895274 part.227 Rename NS_USER_PROXIMITY to eUserProximity r=smaug --- dom/events/EventListenerManager.cpp | 6 +++--- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index 1f52ed063f5e..e3214a87e807 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -423,7 +423,7 @@ EventListenerManager::IsDeviceType(EventMessage aEventMessage) case eDeviceMotion: case NS_DEVICE_LIGHT: case eDeviceProximity: - case NS_USER_PROXIMITY: + case eUserProximity: return true; default: break; @@ -444,7 +444,7 @@ EventListenerManager::EnableDevice(EventMessage aEventMessage) window->EnableDeviceSensor(SENSOR_ORIENTATION); break; case eDeviceProximity: - case NS_USER_PROXIMITY: + case eUserProximity: window->EnableDeviceSensor(SENSOR_PROXIMITY); break; case NS_DEVICE_LIGHT: @@ -479,7 +479,7 @@ EventListenerManager::DisableDevice(EventMessage aEventMessage) window->DisableDeviceSensor(SENSOR_GYROSCOPE); break; case eDeviceProximity: - case NS_USER_PROXIMITY: + case eUserProximity: window->DisableDeviceSensor(SENSOR_PROXIMITY); break; case NS_DEVICE_LIGHT: diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 4e3f4f666816..e4a816b69950 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -540,7 +540,7 @@ WINDOW_ONLY_EVENT(deviceproximity, EventNameType_None, eBasicEventClass) WINDOW_ONLY_EVENT(userproximity, - NS_USER_PROXIMITY, + eUserProximity, EventNameType_None, eBasicEventClass) WINDOW_ONLY_EVENT(devicelight, diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 4d2f65570499..83ebaefdade6 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -359,7 +359,7 @@ NS_EVENT_MESSAGE(eDeviceEventFirst, 4900) NS_EVENT_MESSAGE(eDeviceOrientation, eDeviceEventFirst) NS_EVENT_MESSAGE(eDeviceMotion, eDeviceEventFirst + 1) NS_EVENT_MESSAGE(eDeviceProximity, eDeviceEventFirst + 2) -NS_EVENT_MESSAGE(NS_USER_PROXIMITY, eDeviceEventFirst + 3) +NS_EVENT_MESSAGE(eUserProximity, eDeviceEventFirst + 3) NS_EVENT_MESSAGE(NS_DEVICE_LIGHT, eDeviceEventFirst + 4) NS_EVENT_MESSAGE(NS_SHOW_EVENT, 5000) From 28e9bfed09d25ee0f0eaed01a693ab4193dc8a8a Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sat, 12 Sep 2015 01:19:29 +0900 Subject: [PATCH 090/131] Bug 895274 part.228 Rename NS_DEVICE_LIGHT to eDeviceLight r=smaug --- dom/events/EventListenerManager.cpp | 8 ++++---- dom/events/EventNameList.h | 2 +- widget/EventMessageList.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dom/events/EventListenerManager.cpp b/dom/events/EventListenerManager.cpp index e3214a87e807..6ba3f0925da6 100644 --- a/dom/events/EventListenerManager.cpp +++ b/dom/events/EventListenerManager.cpp @@ -322,7 +322,7 @@ EventListenerManager::AddEventListenerInternal( } else if (aTypeAtom == nsGkAtoms::ondeviceproximity || aTypeAtom == nsGkAtoms::onuserproximity) { EnableDevice(eDeviceProximity); } else if (aTypeAtom == nsGkAtoms::ondevicelight) { - EnableDevice(NS_DEVICE_LIGHT); + EnableDevice(eDeviceLight); } else if (aTypeAtom == nsGkAtoms::ondevicemotion) { EnableDevice(eDeviceMotion); #ifdef MOZ_B2G @@ -421,7 +421,7 @@ EventListenerManager::IsDeviceType(EventMessage aEventMessage) switch (aEventMessage) { case eDeviceOrientation: case eDeviceMotion: - case NS_DEVICE_LIGHT: + case eDeviceLight: case eDeviceProximity: case eUserProximity: return true; @@ -447,7 +447,7 @@ EventListenerManager::EnableDevice(EventMessage aEventMessage) case eUserProximity: window->EnableDeviceSensor(SENSOR_PROXIMITY); break; - case NS_DEVICE_LIGHT: + case eDeviceLight: window->EnableDeviceSensor(SENSOR_LIGHT); break; case eDeviceMotion: @@ -482,7 +482,7 @@ EventListenerManager::DisableDevice(EventMessage aEventMessage) case eUserProximity: window->DisableDeviceSensor(SENSOR_PROXIMITY); break; - case NS_DEVICE_LIGHT: + case eDeviceLight: window->DisableDeviceSensor(SENSOR_LIGHT); break; default: diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index e4a816b69950..8b67e98f15f4 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -544,7 +544,7 @@ WINDOW_ONLY_EVENT(userproximity, EventNameType_None, eBasicEventClass) WINDOW_ONLY_EVENT(devicelight, - NS_DEVICE_LIGHT, + eDeviceLight, EventNameType_None, eBasicEventClass) diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index 83ebaefdade6..8ec6acc762cb 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -360,7 +360,7 @@ NS_EVENT_MESSAGE(eDeviceOrientation, eDeviceEventFirst) NS_EVENT_MESSAGE(eDeviceMotion, eDeviceEventFirst + 1) NS_EVENT_MESSAGE(eDeviceProximity, eDeviceEventFirst + 2) NS_EVENT_MESSAGE(eUserProximity, eDeviceEventFirst + 3) -NS_EVENT_MESSAGE(NS_DEVICE_LIGHT, eDeviceEventFirst + 4) +NS_EVENT_MESSAGE(eDeviceLight, eDeviceEventFirst + 4) NS_EVENT_MESSAGE(NS_SHOW_EVENT, 5000) From 3c4d6d3a3b0dfa3ffea179e7c789c570527df4e2 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Thu, 20 Aug 2015 12:26:45 -0700 Subject: [PATCH 091/131] Bug 1202048 - Root JSONParser explicitly; r=sfink --HG-- extra : rebase_source : 432ac026a3bfb4498b1a88e645e0e7468d6ec64a --- js/src/builtin/Eval.cpp | 2 +- js/src/gc/RootMarking.cpp | 4 ---- js/src/json.cpp | 2 +- js/src/jspubtd.h | 1 - js/src/vm/JSONParser.h | 43 +++++++++++++++++++++++++++++++++------ 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp index 345a0f95d9e6..59fb11156063 100644 --- a/js/src/builtin/Eval.cpp +++ b/js/src/builtin/Eval.cpp @@ -183,7 +183,7 @@ ParseEvalStringAsJSON(JSContext* cx, const mozilla::Range chars, Mu ? chars : mozilla::Range(chars.start().get() + 1U, len - 2); - JSONParser parser(cx, jsonChars, JSONParserBase::NoError); + Rooted> parser(cx, JSONParser(cx, jsonChars, JSONParserBase::NoError)); if (!parser.parse(rval)) return EvalJSON_Failure; diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 8fade7de3974..9d1e82f31be9 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -146,10 +146,6 @@ AutoGCRooter::trace(JSTracer* trc) return; } - case JSONPARSER: - static_cast(this)->trace(trc); - return; - case CUSTOM: static_cast(this)->trace(trc); return; diff --git a/js/src/json.cpp b/js/src/json.cpp index 1e36e7516623..f97914a418e0 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -822,7 +822,7 @@ js::ParseJSONWithReviver(JSContext* cx, const mozilla::Range chars, MutableHandleValue vp) { /* 15.12.2 steps 2-3. */ - JSONParser parser(cx, chars); + Rooted> parser(cx, JSONParser(cx, chars)); if (!parser.parse(vp)) return false; diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index aa9b246853e9..ca5fc7cb77a3 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -224,7 +224,6 @@ class JS_PUBLIC_API(AutoGCRooter) IONMASM = -19, /* js::jit::MacroAssembler */ WRAPVECTOR = -20, /* js::AutoWrapperVector */ WRAPPER = -21, /* js::AutoWrapperRooter */ - JSONPARSER = -25, /* js::JSONParser */ CUSTOM = -26 /* js::CustomAutoRooter */ }; diff --git a/js/src/vm/JSONParser.h b/js/src/vm/JSONParser.h index ddeddad6379a..687972392b02 100644 --- a/js/src/vm/JSONParser.h +++ b/js/src/vm/JSONParser.h @@ -20,7 +20,7 @@ namespace js { // JSONParser base class. JSONParser is templatized to work on either Latin1 // or TwoByte input strings, JSONParserBase holds all state and methods that // can be shared between the two encodings. -class MOZ_STACK_CLASS JSONParserBase : private JS::AutoGCRooter +class MOZ_STACK_CLASS JSONParserBase { public: enum ErrorHandling { RaiseError, NoError }; @@ -108,8 +108,7 @@ class MOZ_STACK_CLASS JSONParserBase : private JS::AutoGCRooter #endif JSONParserBase(JSContext* cx, ErrorHandling errorHandling) - : JS::AutoGCRooter(cx, JSONPARSER), - cx(cx), + : cx(cx), errorHandling(errorHandling), stack(cx), freeElements(cx), @@ -120,6 +119,20 @@ class MOZ_STACK_CLASS JSONParserBase : private JS::AutoGCRooter {} ~JSONParserBase(); + // Allow move construction for use with Rooted. + JSONParserBase(JSONParserBase&& other) + : v(other.v), + cx(other.cx), + errorHandling(other.errorHandling), + stack(mozilla::Move(other.stack)), + freeElements(mozilla::Move(other.freeElements)), + freeProperties(mozilla::Move(other.freeProperties)) +#ifdef DEBUG + , lastToken(mozilla::Move(other.lastToken)) +#endif + {} + + Value numberValue() const { MOZ_ASSERT(lastToken == Number); MOZ_ASSERT(v.isNumber()); @@ -169,16 +182,16 @@ class MOZ_STACK_CLASS JSONParserBase : private JS::AutoGCRooter bool finishObject(MutableHandleValue vp, PropertyVector& properties); bool finishArray(MutableHandleValue vp, ElementVector& elements); - private: - friend void AutoGCRooter::trace(JSTracer* trc); void trace(JSTracer* trc); + private: JSONParserBase(const JSONParserBase& other) = delete; void operator=(const JSONParserBase& other) = delete; }; template -class MOZ_STACK_CLASS JSONParser : public JSONParserBase +class MOZ_STACK_CLASS JSONParser : public JSONParserBase, + public JS::Traceable { private: typedef mozilla::RangedPtr CharPtr; @@ -200,6 +213,14 @@ class MOZ_STACK_CLASS JSONParser : public JSONParserBase MOZ_ASSERT(current <= end); } + /* Allow move construction for use with Rooted. */ + JSONParser(JSONParser&& other) + : JSONParserBase(mozilla::Forward(other)), + current(other.current), + begin(other.begin), + end(other.end) + {} + /* * Parse the JSON data specified at construction time. If it parses * successfully, store the prescribed value in *vp and return true. If an @@ -212,6 +233,9 @@ class MOZ_STACK_CLASS JSONParser : public JSONParserBase */ bool parse(MutableHandleValue vp); + static void trace(JSONParser* parser, JSTracer* trc) { parser->trace(trc); } + void trace(JSTracer* trc) { JSONParserBase::trace(trc); } + private: template Token readString(); @@ -233,6 +257,13 @@ class MOZ_STACK_CLASS JSONParser : public JSONParserBase void operator=(const JSONParser& other) = delete; }; +template +struct RootedBase> { + bool parse(MutableHandleValue vp) { + return static_cast>*>(this)->get().parse(vp); + } +}; + } /* namespace js */ #endif /* vm_JSONParser_h */ From 0444ddb08d63d7164e79c25e44a2d38777067a98 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Fri, 4 Sep 2015 13:40:59 -0700 Subject: [PATCH 092/131] Bug 1202051 - Use a PersistentRooted to automate tracing of unwrappedException_; r=sfink --HG-- extra : rebase_source : 4dfee1e96619eeaa0b5b5d3558f4ca50ba6dc493 --- js/src/jscntxt.cpp | 6 +----- js/src/jscntxt.h | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 6d2712f192cd..e3d5de043a69 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -947,7 +947,7 @@ ExclusiveContext::recoverFromOutOfMemory() JSContext::JSContext(JSRuntime* rt) : ExclusiveContext(rt, &rt->mainThread, Context_JS), throwing(false), - unwrappedException_(UndefinedValue()), + unwrappedException_(this), options_(), overRecursed_(false), propagatingForcedReturn_(false), @@ -1136,10 +1136,6 @@ JSContext::mark(JSTracer* trc) { /* Stack frames and slots are traced by StackSpace::mark. */ - /* Mark other roots-by-definition in the JSContext. */ - if (isExceptionPending()) - TraceRoot(trc, &unwrappedException_, "unwrapped exception"); - TraceCycleDetectionSet(trc, cycleDetectorSet); if (compartment_) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 8b2ee8e58dfd..f8adbb60c2d0 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -305,7 +305,7 @@ struct JSContext : public js::ExclusiveContext, private: /* Exception state -- the exception member is a GC root by definition. */ bool throwing; /* is there a pending exception? */ - js::Value unwrappedException_; /* most-recently-thrown exception */ + JS::PersistentRooted unwrappedException_; /* most-recently-thrown exception */ /* Per-context options. */ JS::ContextOptions options_; From 1e692144916f061468816df710ac201d2e11f88e Mon Sep 17 00:00:00 2001 From: James Willcox Date: Fri, 11 Sep 2015 11:27:24 -0500 Subject: [PATCH 093/131] Back out 69e7d484b749452e7c7ba2ab01f66f71c6339a6b due to Android 4.0 debug reftest failures --- gfx/tests/reftest/reftest.list | 4 ++-- layout/reftests/text-overflow/reftest.list | 2 +- modules/libpref/init/all.js | 5 ----- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/gfx/tests/reftest/reftest.list b/gfx/tests/reftest/reftest.list index 95303aa33727..c9eed7b0c2d0 100644 --- a/gfx/tests/reftest/reftest.list +++ b/gfx/tests/reftest/reftest.list @@ -4,5 +4,5 @@ fuzzy-if(winWidget,175,443) == 611498-1.html 611498-ref.html skip-if(B2G) fuzzy-if(Android&&AndroidVersion>=15,8,1000) == 709477-1.html 709477-1-ref.html # bug 773482 skip-if(!asyncPan) == 1086723.html 1086723-ref.html == 853889-1.html 853889-1-ref.html -skip-if(Android) == 1143303-1.svg pass.svg -fuzzy(100,30) == 1149923.html 1149923-ref.html # use fuzzy due to few distorted pixels caused by border-radius +== 1143303-1.svg pass.svg +fuzzy(100,30) == 1149923.html 1149923-ref.html # use fuzzy due to few distorted pixels caused by border-radius \ No newline at end of file diff --git a/layout/reftests/text-overflow/reftest.list b/layout/reftests/text-overflow/reftest.list index 9978c6b6e445..42313a5faee2 100644 --- a/layout/reftests/text-overflow/reftest.list +++ b/layout/reftests/text-overflow/reftest.list @@ -4,7 +4,7 @@ fuzzy-if(Android,16,244) skip-if(B2G||Mulet) HTTP(..) == marker-basic.html marke skip-if(B2G||Mulet) HTTP(..) == marker-string.html marker-string-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(Android||B2G) HTTP(..) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing skip-if(!gtkWidget) fuzzy-if(gtkWidget,2,289) HTTP(..) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing -skip-if(B2G||Mulet) fuzzy-if(Android&&AndroidVersion<15,206,41) fuzzy-if(Android&&AndroidVersion>=15,24,4000) fuzzy-if(cocoaWidget,1,40) fuzzy-if(asyncPan&&!layersGPUAccelerated,102,1770) HTTP(..) == scroll-rounding.html scroll-rounding-ref.html # bug 760264 # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet) fuzzy-if(Android&&AndroidVersion<15,9,2545) fuzzy-if(Android&&AndroidVersion>=15,24,4000) fuzzy-if(cocoaWidget,1,40) fuzzy-if(asyncPan&&!layersGPUAccelerated,102,1770) HTTP(..) == scroll-rounding.html scroll-rounding-ref.html # bug 760264 # Initial mulet triage: parity with B2G/B2G Desktop fuzzy-if(OSX==1008,1,1) HTTP(..) == anonymous-block.html anonymous-block-ref.html skip-if(B2G||Mulet) HTTP(..) == false-marker-overlap.html false-marker-overlap-ref.html # Initial mulet triage: parity with B2G/B2G Desktop HTTP(..) == visibility-hidden.html visibility-hidden-ref.html diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index ec93faa95219..fa1a6c5c4d9b 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4280,11 +4280,6 @@ pref("layers.tiles.edge-padding", false); pref("layers.tiled-drawtarget.enabled", true); #endif -#ifdef MOZ_WIDGET_ANDROID -pref("layers.tiled-drawtarget.enabled", true); -pref("layers.tiles.edge-padding", true); -#endif - // same effect as layers.offmainthreadcomposition.enabled, but specifically for // use with tests. pref("layers.offmainthreadcomposition.testing.enabled", false); From 6ccbf567367e59ab09beecac6d65a135eac6f721 Mon Sep 17 00:00:00 2001 From: Maja Frydrychowicz Date: Thu, 10 Sep 2015 15:13:52 -0400 Subject: [PATCH 094/131] Bug 1197224 - Add mozharness script to run firefox-media-tests in buildbot, r=jgriffin, DONTBUILD because NPOTB --HG-- extra : commitid : EpjkyzIb7Gy --- .../mediatests/buildbot_posix_config.py | 49 ++++ .../mediatests/buildbot_windows_config.py | 57 +++++ .../mozilla/testing/firefox_media_tests.py | 239 ++++++++++++++++++ .../scripts/firefox_media_tests_buildbot.py | 142 +++++++++++ 4 files changed, 487 insertions(+) create mode 100644 testing/mozharness/configs/mediatests/buildbot_posix_config.py create mode 100644 testing/mozharness/configs/mediatests/buildbot_windows_config.py create mode 100644 testing/mozharness/mozharness/mozilla/testing/firefox_media_tests.py create mode 100644 testing/mozharness/scripts/firefox_media_tests_buildbot.py diff --git a/testing/mozharness/configs/mediatests/buildbot_posix_config.py b/testing/mozharness/configs/mediatests/buildbot_posix_config.py new file mode 100644 index 000000000000..bcf2c8962eac --- /dev/null +++ b/testing/mozharness/configs/mediatests/buildbot_posix_config.py @@ -0,0 +1,49 @@ +import os +import mozharness + +external_tools_path = os.path.join( + os.path.abspath(os.path.dirname(os.path.dirname(mozharness.__file__))), + 'external_tools', +) + +config = { + "virtualenv_path": 'venv', + "exes": { + 'python': '/tools/buildbot/bin/python', + 'virtualenv': ['/tools/buildbot/bin/python', '/tools/misc-python/virtualenv.py'], + 'tooltool.py': "/tools/tooltool.py", + 'gittool.py': os.path.join(external_tools_path, 'gittool.py'), + }, + + "find_links": [ + "http://pypi.pvt.build.mozilla.org/pub", + "http://pypi.pub.build.mozilla.org/pub", + ], + "pip_index": False, + + "buildbot_json_path": "buildprops.json", + + "default_actions": [ + 'clobber', + 'read-buildbot-config', + 'checkout', + 'download-and-extract', + 'create-virtualenv', + 'install', + 'run-media-tests', + ], + "default_blob_upload_servers": [ + "https://blobupload.elasticbeanstalk.com", + ], + "blob_uploader_auth_file" : os.path.join(os.getcwd(), "oauth.txt"), + "download_minidump_stackwalk": True, + "download_symbols": "ondemand", + + "firefox_media_repo": 'https://github.com/mjzffr/firefox-media-tests.git', + "firefox_media_branch": 'master', + "firefox_media_rev": '82c45fba24457b5fe447e967bbcaaec5eb14e3ee', + "firefox_ui_repo": 'https://github.com/mozilla/firefox-ui-tests.git', + "firefox_ui_branch": 'master', + "firefox_ui_rev": '6d6d57917f85399e903ac69b7e4297091b2d474c', + +} diff --git a/testing/mozharness/configs/mediatests/buildbot_windows_config.py b/testing/mozharness/configs/mediatests/buildbot_windows_config.py new file mode 100644 index 000000000000..b457678c88b6 --- /dev/null +++ b/testing/mozharness/configs/mediatests/buildbot_windows_config.py @@ -0,0 +1,57 @@ +import os +import sys +import mozharness + +external_tools_path = os.path.join( + os.path.abspath(os.path.dirname(os.path.dirname(mozharness.__file__))), + 'external_tools', +) + +config = { + "virtualenv_python_dll": 'c:/mozilla-build/python27/python27.dll', + "virtualenv_path": 'venv', + "exes": { + 'python': 'c:/mozilla-build/python27/python', + 'virtualenv': ['c:/mozilla-build/python27/python', 'c:/mozilla-build/buildbotve/virtualenv.py'], + 'hg': 'c:/mozilla-build/hg/hg', + 'mozinstall': ['%s/build/venv/scripts/python' % os.getcwd(), + '%s/build/venv/scripts/mozinstall-script.py' % os.getcwd()], + 'tooltool.py': [sys.executable, 'C:/mozilla-build/tooltool.py'], + 'gittool.py': os.path.join(external_tools_path, 'gittool.py'), + + + }, + + "find_links": [ + "http://pypi.pvt.build.mozilla.org/pub", + "http://pypi.pub.build.mozilla.org/pub", + ], + "pip_index": False, + + "buildbot_json_path": "buildprops.json", + + "default_actions": [ + 'clobber', + 'read-buildbot-config', + 'checkout', + 'download-and-extract', + 'create-virtualenv', + 'install', + 'run-media-tests', + ], + "default_blob_upload_servers": [ + "https://blobupload.elasticbeanstalk.com", + ], + "blob_uploader_auth_file" : os.path.join(os.getcwd(), "oauth.txt"), + "in_tree_config": "config/mozharness/marionette.py", + "download_minidump_stackwalk": True, + "download_symbols": "ondemand", + + "firefox_media_repo": 'https://github.com/mjzffr/firefox-media-tests.git', + "firefox_media_branch": 'master', + "firefox_media_rev": '82c45fba24457b5fe447e967bbcaaec5eb14e3ee', + "firefox_ui_repo": 'https://github.com/mozilla/firefox-ui-tests.git', + "firefox_ui_branch": 'master', + "firefox_ui_rev": '6d6d57917f85399e903ac69b7e4297091b2d474c', + +} diff --git a/testing/mozharness/mozharness/mozilla/testing/firefox_media_tests.py b/testing/mozharness/mozharness/mozilla/testing/firefox_media_tests.py new file mode 100644 index 000000000000..81fdf60c124e --- /dev/null +++ b/testing/mozharness/mozharness/mozilla/testing/firefox_media_tests.py @@ -0,0 +1,239 @@ +#!/usr/bin/env python +# ***** BEGIN LICENSE BLOCK ***** +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# ***** BEGIN LICENSE BLOCK ***** +"""firefox_media_tests.py + +Author: Maja Frydrychowicz +""" +import copy +import os +import re + +from mozharness.base.log import ERROR, WARNING +from mozharness.base.script import PreScriptAction +from mozharness.mozilla.testing.testbase import (TestingMixin, + testing_config_options) +from mozharness.mozilla.testing.unittest import TestSummaryOutputParserHelper +from mozharness.mozilla.vcstools import VCSToolsScript + +BUSTED = 'busted' +TESTFAILED = 'testfailed' +UNKNOWN = 'unknown' +EXCEPTION = 'exception' +SUCCESS = 'success' + +media_test_config_options = [ + [["--media-urls"], + {"action": "store", + "dest": "media_urls", + "help": "Path to ini file that lists media urls for tests.", + }], + [["--profile"], + {"action": "store", + "dest": "profile", + "default": None, + "help": "Path to FF profile that should be used by Marionette", + }], + [["--test-timeout"], + {"action": "store", + "dest": "test_timeout", + "default": 10000, + "help": ("Number of seconds without output before" + "firefox-media-tests is killed." + "Set this based on expected time for all media to play."), + }], + [["--tests"], + {"action": "store", + "dest": "tests", + "default": None, + "help": ("Test(s) to run. Path to test_*.py or " + "test manifest (*.ini)"), + }], + [["--e10s"], + {"dest": "e10s", + "action": "store_true", + "default": False, + "help": "Enable e10s when running marionette tests." + }], + [['--firefox-media-repo'], { + 'dest': 'firefox_media_repo', + 'default': 'https://github.com/mjzffr/firefox-media-tests.git', + 'help': 'which firefox_media_tests repo to use', + }], + [['--firefox-media-branch'], { + 'dest': 'firefox_media_branch', + 'default': 'master', + 'help': 'which branch to use for firefox_media_tests', + }], + [['--firefox-media-rev'], { + 'dest': 'firefox_media_rev', + 'help': 'which firefox_media_tests revision to use', + }], + [['--firefox-ui-repo'], { + 'dest': 'firefox_ui_repo', + 'default': 'https://github.com/mozilla/firefox-ui-tests.git', + 'help': 'which firefox_ui_tests repo to use', + }], + [['--firefox-ui-branch'], { + 'dest': 'firefox_ui_branch', + 'default': 'master', + 'help': 'which branch to use for firefox_ui_tests', + }], + [['--firefox-ui-rev'], { + 'dest': 'firefox_ui_rev', + 'help': 'which firefox_ui_tests revision to use', + }], +] + (copy.deepcopy(testing_config_options)) + + +class JobResultParser(TestSummaryOutputParserHelper): + """ Parses test output to determine overall result.""" + def __init__(self, **kwargs): + super(JobResultParser, self).__init__(**kwargs) + self.return_code = 0 + # External-resource errors that should not count as test failures + self.exception_re = re.compile(r'^TEST-UNEXPECTED-ERROR.*' + r'TimeoutException: Error loading page,' + r' timed out') + self.exceptions = [] + + def parse_single_line(self, line): + super(JobResultParser, self).parse_single_line(line) + if self.exception_re.match(line): + self.exceptions.append(line) + + @property + def status(self): + status = UNKNOWN + if self.passed and self.failed == 0: + status = SUCCESS + elif self.exceptions: + status = EXCEPTION + elif self.failed: + status = TESTFAILED + elif self.return_code: + status = BUSTED + return status + + +class FirefoxMediaTestsBase(TestingMixin, VCSToolsScript): + job_result_parser = None + + error_list = [ + {'substr': 'FAILED (errors=', 'level': WARNING}, + {'substr': r'''Could not successfully complete transport of message to Gecko, socket closed''', 'level': ERROR}, + {'substr': r'''Connection to Marionette server is lost. Check gecko''', 'level': ERROR}, + {'substr': 'Timeout waiting for marionette on port', 'level': ERROR}, + {'regex': re.compile(r'''(TEST-UNEXPECTED|PROCESS-CRASH|CRASH|ERROR|FAIL)'''), 'level': ERROR}, + {'regex': re.compile(r'''(\b\w*Exception)'''), 'level': ERROR}, + {'regex': re.compile(r'''(\b\w*Error)'''), 'level': ERROR}, + ] + + def __init__(self, config_options=None, all_actions=None, + default_actions=None, **kwargs): + self.config_options = media_test_config_options + (config_options or []) + actions = [ + 'clobber', + 'checkout', + 'create-virtualenv', + 'run-media-tests', + ] + super(FirefoxMediaTestsBase, self).__init__( + config_options=self.config_options, + all_actions=all_actions or actions, + default_actions=default_actions or actions, + **kwargs + ) + c = self.config + self.media_urls = c.get('media_urls') + self.profile = c.get('profile') + self.test_timeout = int(c.get('test_timeout')) + self.tests = c.get('tests') + self.e10s = c.get('e10s') + + @PreScriptAction('create-virtualenv') + def _pre_create_virtualenv(self, action): + dirs = self.query_abs_dirs() + # cwd is $workspace/build + self.register_virtualenv_module(name='firefox-ui-tests', + url=dirs['firefox_ui_dir'], + method='pip', + editable='true') + self.register_virtualenv_module(name='firefox-media-tests', + url=dirs['firefox_media_dir'], + method='pip', + editable='true') + + def query_abs_dirs(self): + if self.abs_dirs: + return self.abs_dirs + abs_dirs = super(FirefoxMediaTestsBase, self).query_abs_dirs() + dirs = { + 'firefox_media_dir': os.path.join(abs_dirs['abs_work_dir'], + 'firefox-media-tests') + } + dirs['firefox_ui_dir'] = os.path.join(dirs['firefox_media_dir'], + 'firefox-ui-tests') + abs_dirs.update(dirs) + self.abs_dirs = abs_dirs + return self.abs_dirs + + @PreScriptAction('checkout') + def _pre_checkout(self, action): + super(FirefoxMediaTestsBase, self)._pre_checkout(action) + c = self.config + dirs = self.query_abs_dirs() + self.firefox_media_vc = { + 'branch': c['firefox_media_branch'], + 'repo': c['firefox_media_repo'], + 'revision': c['firefox_media_rev'], + 'dest': dirs['firefox_media_dir'], + } + self.firefox_ui_vc = { + 'branch': c['firefox_ui_branch'], + 'repo': c['firefox_ui_repo'], + 'revision': c['firefox_ui_rev'], + 'dest': dirs['firefox_ui_dir'] + } + + def checkout(self): + revision = self.vcs_checkout(vcs='gittool', **self.firefox_media_vc) + if revision: + self.vcs_checkout(vcs='gittool', **self.firefox_ui_vc) + + def _query_cmd(self): + """ Determine how to call firefox-media-tests """ + if not self.binary_path: + self.fatal("Binary path could not be determined. " + "Should be set by default during 'install' action.") + cmd = ['firefox-media-tests'] + cmd += ['--binary', self.binary_path] + if self.symbols_path: + cmd += ['--symbols-path', self.symbols_path] + if self.media_urls: + cmd += ['--urls', self.media_urls] + if self.profile: + cmd += ['--profile', self.profile] + if self.tests: + cmd.append(self.tests) + if self.e10s: + cmd.append('--e10s') + return cmd + + def run_media_tests(self): + cmd = self._query_cmd() + self.job_result_parser = JobResultParser( + config=self.config, + log_obj=self.log_obj, + error_list=self.error_list + ) + return_code = self.run_command( + cmd, + output_timeout=self.test_timeout, + output_parser=self.job_result_parser + ) + self.job_result_parser.return_code = return_code + return self.job_result_parser.status diff --git a/testing/mozharness/scripts/firefox_media_tests_buildbot.py b/testing/mozharness/scripts/firefox_media_tests_buildbot.py new file mode 100644 index 000000000000..cf54c75eb1af --- /dev/null +++ b/testing/mozharness/scripts/firefox_media_tests_buildbot.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python +# ***** BEGIN LICENSE BLOCK ***** +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# ***** BEGIN LICENSE BLOCK ***** +"""firefox_media_tests_buildbot.py + +Author: Maja Frydrychowicz +""" +import copy +import glob +import os +import sys + +sys.path.insert(1, os.path.dirname(sys.path[0])) + +from mozharness.base.log import ERROR, DEBUG, INFO +from mozharness.base.script import PreScriptAction, PostScriptAction +from mozharness.mozilla.blob_upload import ( + BlobUploadMixin, + blobupload_config_options +) +from mozharness.mozilla.buildbot import ( + TBPL_SUCCESS, TBPL_WARNING, TBPL_FAILURE +) +from mozharness.mozilla.testing.firefox_media_tests import ( + FirefoxMediaTestsBase, BUSTED, TESTFAILED, UNKNOWN, EXCEPTION, SUCCESS +) + + +class FirefoxMediaTestsBuildbot(FirefoxMediaTestsBase, BlobUploadMixin): + + def __init__(self): + config_options = copy.deepcopy(blobupload_config_options) + super(FirefoxMediaTestsBuildbot, self).__init__( + config_options=config_options, + all_actions=['clobber', + 'read-buildbot-config', + 'checkout', + 'download-and-extract', + 'create-virtualenv', + 'install', + 'run-media-tests', + ], + ) + c = self.config + self.installer_url = c.get('installer_url') + self.installer_path = c.get('installer_path') + self.binary_path = c.get('binary_path') + self.test_packages_url = c.get('test_packages_url') + + @PreScriptAction('create-virtualenv') + def _pre_create_virtualenv(self, action): + dirs = self.query_abs_dirs() + requirements = os.path.join(dirs['abs_test_install_dir'], + 'config', + 'marionette_requirements.txt') + if os.access(requirements, os.F_OK): + self.register_virtualenv_module(requirements=[requirements], + two_pass=True) + super(FirefoxMediaTestsBuildbot, self)._pre_create_virtualenv(action) + + def query_abs_dirs(self): + if self.abs_dirs: + return self.abs_dirs + dirs = super(FirefoxMediaTestsBuildbot, self).query_abs_dirs() + dirs['abs_blob_upload_dir'] = os.path.join(dirs['abs_work_dir'], + 'blobber_upload_dir') + dirs['abs_test_install_dir'] = os.path.join(dirs['abs_work_dir'], + 'tests') + self.abs_dirs = dirs + return self.abs_dirs + + def _query_cmd(self): + """ Determine how to call firefox-media-tests """ + cmd = super(FirefoxMediaTestsBuildbot, self)._query_cmd() + # configure logging + dirs = self.query_abs_dirs() + blob_upload_dir = dirs.get('abs_blob_upload_dir') + cmd += ['--gecko-log', os.path.join(blob_upload_dir, + 'gecko.log')] + cmd += ['--log-html', os.path.join(blob_upload_dir, + 'media_tests.html')] + cmd += ['--log-mach', os.path.join(blob_upload_dir, + 'media_tests_mach.log')] + return cmd + + def run_media_tests(self): + status = super(FirefoxMediaTestsBuildbot, self).run_media_tests() + if status == SUCCESS: + tbpl_status = TBPL_SUCCESS + else: + tbpl_status = TBPL_FAILURE + if status == TESTFAILED: + tbpl_status = TBPL_WARNING + self.buildbot_status(tbpl_status) + + @PostScriptAction('run-media-tests') + def _collect_uploads(self, action, success=None): + """ Copy extra (log) files to blob upload dir. """ + dirs = self.query_abs_dirs() + log_dir = dirs.get('abs_log_dir') + blob_upload_dir = dirs.get('abs_blob_upload_dir') + if not log_dir or not blob_upload_dir: + return + self.mkdir_p(blob_upload_dir) + # Move firefox-media-test screenshots into log_dir + screenshots_dir = os.path.join(dirs['base_work_dir'], + 'screenshots') + log_screenshots_dir = os.path.join(log_dir, 'screenshots') + if os.access(log_screenshots_dir, os.F_OK): + self.rmtree(log_screenshots_dir) + if os.access(screenshots_dir, os.F_OK): + self.move(screenshots_dir, log_screenshots_dir) + + # logs to upload: broadest level (info), error, screenshots + uploads = glob.glob(os.path.join(log_screenshots_dir, '*')) + log_files = self.log_obj.log_files + log_level = self.log_obj.log_level + + def append_path(filename, dir=log_dir): + if filename: + uploads.append(os.path.join(dir, filename)) + + append_path(log_files.get(ERROR)) + # never upload debug logs + if log_level == DEBUG: + append_path(log_files.get(INFO)) + else: + append_path(log_files.get(log_level)) + # in case of SimpleFileLogger + append_path(log_files.get('default')) + for f in uploads: + if os.access(f, os.F_OK): + dest = os.path.join(blob_upload_dir, os.path.basename(f)) + self.copyfile(f, dest) + + +if __name__ == '__main__': + media_test = FirefoxMediaTestsBuildbot() + media_test.run_and_exit() From 7e4893bc7a75a3173a5312f641972051a372a9ac Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 11 Sep 2015 13:23:29 -0400 Subject: [PATCH 095/131] Bug 1198544 - Prevent FetchDriver from creating multiple responses if OnStopRequest yields a failing status code. r=nsm --- dom/fetch/Fetch.cpp | 8 ++++---- dom/fetch/FetchDriver.cpp | 14 +++++++------ dom/fetch/FetchDriver.h | 15 +++++++++++++- .../test/serviceworkers/fetch/fetch_tests.js | 17 ++++++++++++++++ .../test/serviceworkers/fetch/interrupt.sjs | 20 +++++++++++++++++++ dom/workers/test/serviceworkers/mochitest.ini | 1 + 6 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 dom/workers/test/serviceworkers/fetch/interrupt.sjs diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp index 47c1c5e5166d..556bb1f31925 100644 --- a/dom/fetch/Fetch.cpp +++ b/dom/fetch/Fetch.cpp @@ -72,7 +72,7 @@ public: } void - OnResponseAvailable(InternalResponse* aResponse) override; + OnResponseAvailableInternal(InternalResponse* aResponse) override; void OnResponseEnd() override; @@ -99,7 +99,7 @@ public: explicit MainThreadFetchResolver(Promise* aPromise); void - OnResponseAvailable(InternalResponse* aResponse) override; + OnResponseAvailableInternal(InternalResponse* aResponse) override; private: ~MainThreadFetchResolver(); @@ -237,7 +237,7 @@ MainThreadFetchResolver::MainThreadFetchResolver(Promise* aPromise) } void -MainThreadFetchResolver::OnResponseAvailable(InternalResponse* aResponse) +MainThreadFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse) { NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver); AssertIsOnMainThread(); @@ -317,7 +317,7 @@ public: }; void -WorkerFetchResolver::OnResponseAvailable(InternalResponse* aResponse) +WorkerFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse) { AssertIsOnMainThread(); diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index 81d91b7b958f..390f934c21d8 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -883,13 +883,15 @@ FetchDriver::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) { workers::AssertIsOnMainThread(); - if (mPipeOutputStream) { - mPipeOutputStream->Close(); - } - if (NS_FAILED(aStatusCode)) { - FailWithNetworkError(); - return aStatusCode; + nsCOMPtr outputStream = do_QueryInterface(mPipeOutputStream); + if (outputStream) { + outputStream->CloseWithStatus(NS_BINDING_FAILED); + } + // We proceed as usual here, since we've already created a successful response + // from OnStartRequest. + } else if (mPipeOutputStream) { + mPipeOutputStream->Close(); } ContinueHttpFetchAfterNetworkFetch(); diff --git a/dom/fetch/FetchDriver.h b/dom/fetch/FetchDriver.h index 96b8f848f200..9a5648579816 100644 --- a/dom/fetch/FetchDriver.h +++ b/dom/fetch/FetchDriver.h @@ -32,14 +32,27 @@ class InternalResponse; class FetchDriverObserver { public: + FetchDriverObserver() : mGotResponseAvailable(false) + { } + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchDriverObserver); - virtual void OnResponseAvailable(InternalResponse* aResponse) = 0; + void OnResponseAvailable(InternalResponse* aResponse) + { + MOZ_ASSERT(!mGotResponseAvailable); + mGotResponseAvailable = true; + OnResponseAvailableInternal(aResponse); + } virtual void OnResponseEnd() { }; protected: virtual ~FetchDriverObserver() { }; + + virtual void OnResponseAvailableInternal(InternalResponse* aResponse) = 0; + +private: + bool mGotResponseAvailable; }; class FetchDriver final : public nsIStreamListener, diff --git a/dom/workers/test/serviceworkers/fetch/fetch_tests.js b/dom/workers/test/serviceworkers/fetch/fetch_tests.js index c10fd1b87aa7..ec65f79bb5e0 100644 --- a/dom/workers/test/serviceworkers/fetch/fetch_tests.js +++ b/dom/workers/test/serviceworkers/fetch/fetch_tests.js @@ -319,6 +319,23 @@ fetch(new Request('body-blob', {method: 'POST', body: new Blob(new String('my bo finish(); }); +expectAsyncResult(); +fetch('interrupt.sjs') +.then(function(res) { + my_ok(true, "interrupted fetch succeeded"); + res.text().then(function(body) { + my_ok(false, "interrupted fetch shouldn't have complete body"); + finish(); + }, + function() { + my_ok(true, "interrupted fetch shouldn't have complete body"); + finish(); + }) +}, function(e) { + my_ok(false, "interrupted fetch failed"); + finish(); +}); + ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'].forEach(function(method) { fetchXHRWithMethod('xhr-method-test.txt', method, function(xhr) { my_ok(xhr.status == 200, method + " load should be successful"); diff --git a/dom/workers/test/serviceworkers/fetch/interrupt.sjs b/dom/workers/test/serviceworkers/fetch/interrupt.sjs new file mode 100644 index 000000000000..f6fe870efa29 --- /dev/null +++ b/dom/workers/test/serviceworkers/fetch/interrupt.sjs @@ -0,0 +1,20 @@ +function handleRequest(request, response) { + var body = "a"; + for (var i = 0; i < 20; i++) { + body += body; + } + + response.seizePower(); + response.write("HTTP/1.1 200 OK\r\n") + var count = 10; + response.write("Content-Length: " + body.length * count + "\r\n"); + response.write("Content-Type: text/plain; charset=utf-8\r\n"); + response.write("Cache-Control: no-cache, must-revalidate\r\n"); + response.write("\r\n"); + + for (var i = 0; i < count; i++) { + response.write(body); + } + + throw Components.results.NS_BINDING_ABORTED; +} diff --git a/dom/workers/test/serviceworkers/mochitest.ini b/dom/workers/test/serviceworkers/mochitest.ini index c89ca8c374f4..caa53aff9136 100644 --- a/dom/workers/test/serviceworkers/mochitest.ini +++ b/dom/workers/test/serviceworkers/mochitest.ini @@ -50,6 +50,7 @@ support-files = fetch/https/clonedresponse/register.html fetch/https/clonedresponse/unregister.html fetch/https/clonedresponse/https_test.js + fetch/interrupt.sjs fetch/origin/index.sjs fetch/origin/index-to-https.sjs fetch/origin/realindex.html From a48d20d52039b1c49add0ca894e40d5c298263cf Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 11 Sep 2015 10:58:47 -0700 Subject: [PATCH 096/131] Backed out changeset f0fbe3de27cb (bug 1127270) for b2g debug mochitest failures CLOSED TREE --- gfx/layers/ipc/CompositorParent.cpp | 3 +-- gfx/layers/ipc/ImageBridgeParent.cpp | 7 +------ gfx/layers/ipc/ImageBridgeParent.h | 3 --- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index b48aac4b7cbb..147e293462fd 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -1636,6 +1636,7 @@ class CrossProcessCompositorParent final : public PCompositorParent, public: explicit CrossProcessCompositorParent(Transport* aTransport) : mTransport(aTransport) + , mCompositorThreadHolder(sCompositorThreadHolder) , mNotifyAfterRemotePaint(false) { MOZ_ASSERT(NS_IsMainThread()); @@ -1725,8 +1726,6 @@ public: TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd); -protected: - void OnChannelConnected(int32_t pid) override { mCompositorThreadHolder = sCompositorThreadHolder; } private: // Private destructor, to discourage deletion outside of Release(): virtual ~CrossProcessCompositorParent(); diff --git a/gfx/layers/ipc/ImageBridgeParent.cpp b/gfx/layers/ipc/ImageBridgeParent.cpp index af990683416b..1b488c2f863c 100644 --- a/gfx/layers/ipc/ImageBridgeParent.cpp +++ b/gfx/layers/ipc/ImageBridgeParent.cpp @@ -58,6 +58,7 @@ ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop, : mMessageLoop(aLoop) , mTransport(aTransport) , mSetChildThreadPriority(false) + , mCompositorThreadHolder(GetCompositorThreadHolder()) { MOZ_ASSERT(NS_IsMainThread()); sMainLoop = MessageLoop::current(); @@ -384,12 +385,6 @@ ImageBridgeParent::CloneToplevel(const InfallibleTArray& aFds return nullptr; } -void -ImageBridgeParent::OnChannelConnected(int32_t aPid) -{ - mCompositorThreadHolder = GetCompositorThreadHolder(); -} - bool ImageBridgeParent::IsSameProcess() const { return OtherPid() == base::GetCurrentProcId(); diff --git a/gfx/layers/ipc/ImageBridgeParent.h b/gfx/layers/ipc/ImageBridgeParent.h index 9cfba1a20bae..bf9c9e4ebf4b 100644 --- a/gfx/layers/ipc/ImageBridgeParent.h +++ b/gfx/layers/ipc/ImageBridgeParent.h @@ -151,9 +151,6 @@ public: base::ProcessHandle aPeerProcess, mozilla::ipc::ProtocolCloneContext* aCtx) override; -protected: - void OnChannelConnected(int32_t pid) override; - private: void DeferredDestroy(); MessageLoop* mMessageLoop; From 2fddaed099412c8b1277a448a0081e73a8e7dec6 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 11 Sep 2015 11:20:23 -0700 Subject: [PATCH 097/131] Backed out 3 changesets (bug 1178376) for android reftest bustage CLOSED TREE Backed out changeset 9394c5f63b56 (bug 1178376) Backed out changeset 83295d5f54a9 (bug 1178376) Backed out changeset 5e1c6511123a (bug 1178376) --- gfx/layers/Layers.h | 2 +- gfx/layers/client/ClientTiledPaintedLayer.cpp | 22 +++--- .../client/SingleTiledContentClient.cpp | 9 +-- gfx/layers/client/SingleTiledContentClient.h | 4 +- gfx/layers/client/TiledContentClient.cpp | 30 ++++---- gfx/layers/client/TiledContentClient.h | 15 +--- gfx/layers/composite/ContentHost.h | 2 - .../composite/PaintedLayerComposite.cpp | 11 --- gfx/layers/composite/PaintedLayerComposite.h | 2 - gfx/layers/composite/TiledContentHost.cpp | 69 +------------------ gfx/layers/composite/TiledContentHost.h | 13 ---- gfx/layers/ipc/LayersMessages.ipdlh | 2 - gfx/thebes/gfxPrefs.h | 2 - 13 files changed, 30 insertions(+), 153 deletions(-) diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 087c0adb8ece..1409837157fd 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -1593,7 +1593,7 @@ public: * Returns the current area of the layer (in layer-space coordinates) * marked as needed to be recomposited. */ - const virtual nsIntRegion GetInvalidRegion() { return mInvalidRegion; } + const nsIntRegion& GetInvalidRegion() { return mInvalidRegion; } const void SetInvalidRegion(const nsIntRegion& aRect) { mInvalidRegion = aRect; } /** diff --git a/gfx/layers/client/ClientTiledPaintedLayer.cpp b/gfx/layers/client/ClientTiledPaintedLayer.cpp index 234c19e9ba91..c9b59e00b9f4 100644 --- a/gfx/layers/client/ClientTiledPaintedLayer.cpp +++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp @@ -169,8 +169,7 @@ ClientTiledPaintedLayer::BeginPaint() // on this layer. If there is an OMT animation then we need to draw the whole // visible region of this layer as determined by layout, because we don't know // what parts of it might move into view in the compositor. - mPaintData.mHasTransformAnimation = hasTransformAnimation; - if (!mPaintData.mHasTransformAnimation && + if (!hasTransformAnimation && mContentClient->GetLowPrecisionTiledBuffer()) { ParentLayerRect criticalDisplayPort = (displayportMetrics.GetCriticalDisplayPort() * displayportMetrics.GetZoom()) @@ -257,6 +256,15 @@ ClientTiledPaintedLayer::UseProgressiveDraw() { return false; } + if (mPaintData.mCriticalDisplayPort.IsEmpty()) { + // This catches three scenarios: + // 1) This layer doesn't have a scrolling ancestor + // 2) This layer is subject to OMTA transforms + // 3) Low-precision painting is disabled + // In all of these cases, we don't want to draw this layer progressively. + return false; + } + if (GetIsFixedPosition() || GetParent()->GetIsFixedPosition()) { // This layer is fixed-position and so even if it does have a scrolling // ancestor it will likely be entirely on-screen all the time, so we @@ -264,18 +272,10 @@ ClientTiledPaintedLayer::UseProgressiveDraw() { return false; } - if (mPaintData.mHasTransformAnimation) { - // The compositor is going to animate this somehow, so we want it all - // on the screen at once. - return false; - } - if (ClientManager()->AsyncPanZoomEnabled()) { LayerMetricsWrapper scrollAncestor; GetAncestorLayers(&scrollAncestor, nullptr, nullptr); - if (!scrollAncestor) { - return false; - } + MOZ_ASSERT(scrollAncestor); // because mPaintData.mCriticalDisplayPort is non-empty const FrameMetrics& parentMetrics = scrollAncestor.Metrics(); if (!IsScrollingOnCompositor(parentMetrics)) { return false; diff --git a/gfx/layers/client/SingleTiledContentClient.cpp b/gfx/layers/client/SingleTiledContentClient.cpp index ec5b15b43339..b195fd9abfd0 100644 --- a/gfx/layers/client/SingleTiledContentClient.cpp +++ b/gfx/layers/client/SingleTiledContentClient.cpp @@ -45,7 +45,6 @@ ClientSingleTiledLayerBuffer::ClientSingleTiledLayerBuffer(ClientTiledPaintedLay ClientLayerManager* aManager) : ClientTiledLayerBuffer(aPaintedLayer, aCompositableClient) , mManager(aManager) - , mWasLastPaintProgressive(false) { } @@ -90,8 +89,7 @@ ClientSingleTiledLayerBuffer::GetSurfaceDescriptorTiles() 0, 0, 1, 1, 1.0, mFrameResolution.xScale, - mFrameResolution.yScale, - mWasLastPaintProgressive); + mFrameResolution.yScale); } already_AddRefed @@ -107,11 +105,8 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData, - bool aIsProgressive) + void* aCallbackData) { - mWasLastPaintProgressive = aIsProgressive; - // Compare layer visible region size to current backbuffer size, discard if not matching. IntSize size = mPaintedLayer->GetVisibleRegion().GetBounds().Size(); IntPoint origin = mPaintedLayer->GetVisibleRegion().GetBounds().TopLeft(); diff --git a/gfx/layers/client/SingleTiledContentClient.h b/gfx/layers/client/SingleTiledContentClient.h index c3d84618f772..33a01c5c44cc 100644 --- a/gfx/layers/client/SingleTiledContentClient.h +++ b/gfx/layers/client/SingleTiledContentClient.h @@ -41,8 +41,7 @@ public: const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData, - bool aIsProgressive = false) override; + void* aCallbackData) override; bool SupportsProgressiveUpdate() override { return false; } bool ProgressiveUpdate(nsIntRegion& aValidRegion, @@ -89,7 +88,6 @@ private: nsIntRegion mPaintedRegion; nsIntRegion mValidRegion; - bool mWasLastPaintProgressive; /** * While we're adding tiles, this is used to keep track of the position of diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index 92b1a29b6bc9..861cfc065cca 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -497,7 +497,7 @@ TileClient::PrivateProtector::Set(TileClient * const aContainer, TextureClient* // Placeholder TileClient::TileClient() - : mCompositableClient(nullptr), mWasPlaceholder(false) + : mCompositableClient(nullptr) { } @@ -518,7 +518,6 @@ TileClient::TileClient(const TileClient& o) mBackLock = o.mBackLock; mFrontLock = o.mFrontLock; mCompositableClient = o.mCompositableClient; - mWasPlaceholder = o.mWasPlaceholder; mUpdateRect = o.mUpdateRect; #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY mLastUpdate = o.mLastUpdate; @@ -540,7 +539,6 @@ TileClient::operator=(const TileClient& o) mBackLock = o.mBackLock; mFrontLock = o.mFrontLock; mCompositableClient = o.mCompositableClient; - mWasPlaceholder = o.mWasPlaceholder; mUpdateRect = o.mUpdateRect; #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY mLastUpdate = o.mLastUpdate; @@ -844,12 +842,9 @@ TileDescriptor TileClient::GetTileDescriptor() { if (IsPlaceholderTile()) { - mWasPlaceholder = true; return PlaceholderTileDescriptor(); } MOZ_ASSERT(mFrontLock); - bool wasPlaceholder = mWasPlaceholder; - mWasPlaceholder = false; if (mFrontLock->GetType() == gfxSharedReadLock::TYPE_MEMORY) { // AddRef here and Release when receiving on the host side to make sure the // reference count doesn't go to zero before the host receives the message. @@ -861,15 +856,13 @@ TileClient::GetTileDescriptor() return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(), mFrontBufferOnWhite ? MaybeTexture(mFrontBufferOnWhite->GetIPDLActor()) : MaybeTexture(null_t()), mUpdateRect, - TileLock(uintptr_t(mFrontLock.get())), - wasPlaceholder); + TileLock(uintptr_t(mFrontLock.get()))); } else { gfxShmSharedReadLock *lock = static_cast(mFrontLock.get()); return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(), mFrontBufferOnWhite ? MaybeTexture(mFrontBufferOnWhite->GetIPDLActor()) : MaybeTexture(null_t()), mUpdateRect, - TileLock(lock->GetShmemSection()), - wasPlaceholder); + TileLock(lock->GetShmemSection())); } } @@ -896,7 +889,12 @@ ClientMultiTiledLayerBuffer::GetSurfaceDescriptorTiles() InfallibleTArray tiles; for (TileClient& tile : mRetainedTiles) { - TileDescriptor tileDesc = tile.GetTileDescriptor(); + TileDescriptor tileDesc; + if (tile.IsPlaceholderTile()) { + tileDesc = PlaceholderTileDescriptor(); + } else { + tileDesc = tile.GetTileDescriptor(); + } tiles.AppendElement(tileDesc); // Reset the update rect tile.mUpdateRect = IntRect(); @@ -907,8 +905,7 @@ ClientMultiTiledLayerBuffer::GetSurfaceDescriptorTiles() mTiles.mFirst.x, mTiles.mFirst.y, mTiles.mSize.width, mTiles.mSize.height, mResolution, mFrameResolution.xScale, - mFrameResolution.yScale, - mWasLastPaintProgressive); + mFrameResolution.yScale); } void @@ -916,15 +913,13 @@ ClientMultiTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData, - bool aIsProgressive) + void* aCallbackData) { TILING_LOG("TILING %p: PaintThebes painting region %s\n", mPaintedLayer, Stringify(aPaintRegion).c_str()); TILING_LOG("TILING %p: PaintThebes new valid region %s\n", mPaintedLayer, Stringify(aNewValidRegion).c_str()); mCallback = aCallback; mCallbackData = aCallbackData; - mWasLastPaintProgressive = aIsProgressive; #ifdef GFX_TILEDLAYER_PREF_WARNINGS long start = PR_IntervalNow(); @@ -1658,7 +1653,7 @@ ClientMultiTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion, // Paint the computed region and subtract it from the invalid region. PaintThebes(validOrStale, regionToPaint, aInvalidRegion, - aCallback, aCallbackData, true); + aCallback, aCallbackData); aInvalidRegion.Sub(aInvalidRegion, regionToPaint); } while (repeat); @@ -1697,7 +1692,6 @@ BasicTiledLayerPaintData::ResetPaintData() { mLowPrecisionPaintCount = 0; mPaintFinished = false; - mHasTransformAnimation = false; mCompositionBounds.SetEmpty(); mCriticalDisplayPort.SetEmpty(); } diff --git a/gfx/layers/client/TiledContentClient.h b/gfx/layers/client/TiledContentClient.h index b63dabc6680d..1ce96533a265 100644 --- a/gfx/layers/client/TiledContentClient.h +++ b/gfx/layers/client/TiledContentClient.h @@ -275,7 +275,6 @@ struct TileClient RefPtr mAllocator; gfx::IntRect mUpdateRect; CompositableClient* mCompositableClient; - bool mWasPlaceholder; #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY TimeStamp mLastUpdate; #endif @@ -354,11 +353,6 @@ struct BasicTiledLayerPaintData { */ bool mPaintFinished : 1; - /* - * Whether or not there is an async transform animation active - */ - bool mHasTransformAnimation : 1; - /* * Initializes/clears data to prepare for paint action. */ @@ -413,15 +407,13 @@ public: , mCompositableClient(aCompositableClient) , mLastPaintContentType(gfxContentType::COLOR) , mLastPaintSurfaceMode(SurfaceMode::SURFACE_OPAQUE) - , mWasLastPaintProgressive(false) {} virtual void PaintThebes(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData, - bool aIsProgressive = false) = 0; + void* aCallbackData) = 0; virtual bool SupportsProgressiveUpdate() = 0; virtual bool ProgressiveUpdate(nsIntRegion& aValidRegion, @@ -455,8 +447,6 @@ protected: gfxContentType mLastPaintContentType; SurfaceMode mLastPaintSurfaceMode; CSSToParentLayerScale2D mFrameResolution; - - bool mWasLastPaintProgressive; }; class ClientMultiTiledLayerBuffer @@ -483,8 +473,7 @@ public: const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, - void* aCallbackData, - bool aIsProgressive = false) override; + void* aCallbackData) override; virtual bool SupportsProgressiveUpdate() override { return true; } /** diff --git a/gfx/layers/composite/ContentHost.h b/gfx/layers/composite/ContentHost.h index 3f1550ff5775..544236fb487d 100644 --- a/gfx/layers/composite/ContentHost.h +++ b/gfx/layers/composite/ContentHost.h @@ -61,8 +61,6 @@ public: virtual void SetPaintWillResample(bool aResample) { mPaintWillResample = aResample; } bool PaintWillResample() { return mPaintWillResample; } - virtual void InvalidateForAnimation(nsIntRegion& aRegion) { } - protected: explicit ContentHost(const TextureInfo& aTextureInfo) : CompositableHost(aTextureInfo) diff --git a/gfx/layers/composite/PaintedLayerComposite.cpp b/gfx/layers/composite/PaintedLayerComposite.cpp index 725218d1a14c..476b88e182ea 100644 --- a/gfx/layers/composite/PaintedLayerComposite.cpp +++ b/gfx/layers/composite/PaintedLayerComposite.cpp @@ -179,16 +179,5 @@ PaintedLayerComposite::PrintInfo(std::stringstream& aStream, const char* aPrefix } } -const nsIntRegion -PaintedLayerComposite::GetInvalidRegion() -{ - nsIntRegion region = mInvalidRegion; - if (mBuffer) { - mBuffer->InvalidateForAnimation(region); - } - return region; -} - - } // namespace layers } // namespace mozilla diff --git a/gfx/layers/composite/PaintedLayerComposite.h b/gfx/layers/composite/PaintedLayerComposite.h index 39fa6fd0dbb6..c4107d6a9b20 100644 --- a/gfx/layers/composite/PaintedLayerComposite.h +++ b/gfx/layers/composite/PaintedLayerComposite.h @@ -73,8 +73,6 @@ public: Mutated(); } - const virtual nsIntRegion GetInvalidRegion() override; - MOZ_LAYER_DECL_NAME("PaintedLayerComposite", TYPE_PAINTED) protected: diff --git a/gfx/layers/composite/TiledContentHost.cpp b/gfx/layers/composite/TiledContentHost.cpp index 1cf4f1bc82e9..f876970bcc53 100644 --- a/gfx/layers/composite/TiledContentHost.cpp +++ b/gfx/layers/composite/TiledContentHost.cpp @@ -10,7 +10,6 @@ #include "mozilla/gfx/Matrix.h" // for Matrix4x4 #include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/layers/Compositor.h" // for Compositor -#include "mozilla/layers/CompositorParent.h" // for CompositorParent #include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL @@ -29,26 +28,6 @@ namespace layers { class Layer; -float -TileHost::GetFadeInOpacity(float aOpacity) -{ - TimeStamp now = TimeStamp::Now(); - if (!gfxPrefs::LayerTileFadeInEnabled() || - mFadeStart.IsNull() || - now < mFadeStart) - { - return aOpacity; - } - - float duration = gfxPrefs::LayerTileFadeInDuration(); - float elapsed = (now - mFadeStart).ToMilliseconds(); - if (elapsed > duration) { - mFadeStart = TimeStamp(); - return aOpacity; - } - return aOpacity * (elapsed / duration); -} - TiledLayerBufferComposite::TiledLayerBufferComposite() : mFrameResolution() {} @@ -77,21 +56,6 @@ TiledLayerBufferComposite::SetCompositor(Compositor* aCompositor) } } -void -TiledLayerBufferComposite::InvalidateForAnimation(nsIntRegion& aRegion) -{ - // We need to invalidate rects where we have a tile that is in the - // process of fading in. - for (size_t i = 0; i < mRetainedTiles.Length(); i++) { - if (!mRetainedTiles[i].mFadeStart.IsNull()) { - TileIntPoint position = mTiles.TilePosition(i); - IntPoint offset = GetTileOffset(position); - nsIntRegion tileRegion = IntRect(offset, GetScaledTileSize()); - aRegion.OrWith(tileRegion); - } - } -} - TiledContentHost::TiledContentHost(const TextureInfo& aTextureInfo) : ContentHost(aTextureInfo) , mTiledBuffer(TiledLayerBufferComposite()) @@ -269,14 +233,6 @@ public: } } - void RecycleTileFading(TileHost& aTile) { - for (size_t i = 0; i < mTiles.Length(); i++) { - if (mTiles[i].mTextureHost == aTile.mTextureHost) { - aTile.mFadeStart = mTiles[i].mFadeStart; - } - } - } - protected: nsTArray mTiles; size_t mFirstPossibility; @@ -354,20 +310,6 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles, // If this same tile texture existed in the old tile set then this will move the texture // source into our new tile. oldRetainedTiles.RecycleTextureSourceForTile(tile); - - // If this tile is in the process of fading, we need to keep that going - oldRetainedTiles.RecycleTileFading(tile); - - if (aTiles.isProgressive() && - texturedDesc.wasPlaceholder()) - { - // This is a progressive paint, and the tile used to be a placeholder. - // We need to begin fading it in (if enabled via layers.tiles.fade-in.enabled) - tile.mFadeStart = TimeStamp::Now(); - - aCompositor->CompositeUntil(tile.mFadeStart + - TimeDuration::FromMilliseconds(gfxPrefs::LayerTileFadeInDuration())); - } } // Step 3, attempt to recycle unused texture sources from the old tile set into new tiles. @@ -545,8 +487,6 @@ TiledContentHost::RenderTile(TileHost& aTile, return; } - float opacity = aTile.GetFadeInOpacity(aOpacity); - aEffectChain.mPrimaryEffect = effect; nsIntRegionRectIterator it(aScreenRegion); @@ -559,7 +499,7 @@ TiledContentHost::RenderTile(TileHost& aTile, textureRect.y / aTextureBounds.height, textureRect.width / aTextureBounds.width, textureRect.height / aTextureBounds.height); - mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, opacity, aTransform, aVisibleRect); + mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, aOpacity, aTransform, aVisibleRect); } DiagnosticFlags flags = DiagnosticFlags::CONTENT | DiagnosticFlags::TILE; if (aTile.mTextureHostOnWhite) { @@ -694,12 +634,5 @@ TiledContentHost::Dump(std::stringstream& aStream, mTiledBuffer.Dump(aStream, aPrefix, aDumpHtml); } -void -TiledContentHost::InvalidateForAnimation(nsIntRegion& aRegion) -{ - return mTiledBuffer.InvalidateForAnimation(aRegion); -} - - } // namespace layers } // namespace mozilla diff --git a/gfx/layers/composite/TiledContentHost.h b/gfx/layers/composite/TiledContentHost.h index f74433def407..1291fb1a0b85 100644 --- a/gfx/layers/composite/TiledContentHost.h +++ b/gfx/layers/composite/TiledContentHost.h @@ -113,14 +113,6 @@ public: CompositableHost::DumpTextureHost(aStream, mTextureHost); } - /** - * This does a linear tween of the passed opacity (which is assumed - * to be between 0.0 and 1.0). The duration of the fade is controlled - * by the 'layers.tiles.fade-in.duration-ms' preference. It is enabled - * via 'layers.tiles.fade-in.enabled' - */ - float GetFadeInOpacity(float aOpacity); - RefPtr mSharedLock; CompositableTextureHostRef mTextureHost; CompositableTextureHostRef mTextureHostOnWhite; @@ -128,7 +120,6 @@ public: mutable CompositableTextureSourceRef mTextureSourceOnWhite; // This is not strictly necessary but makes debugging whole lot easier. TileIntPoint mTilePosition; - TimeStamp mFadeStart; }; class TiledLayerBufferComposite @@ -161,8 +152,6 @@ public: // Used when TiledContentClient is present in client side. static void RecycleCallback(TextureHost* textureHost, void* aClosure); - void InvalidateForAnimation(nsIntRegion& aRegion); - protected: CSSToParentLayerScale2D mFrameResolution; @@ -278,8 +267,6 @@ public: virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override; - virtual void InvalidateForAnimation(nsIntRegion& aRegion) override; - private: void RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer, diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index 16563e4691c5..091b0a03e141 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -319,7 +319,6 @@ struct TexturedTileDescriptor { MaybeTexture textureOnWhite; IntRect updateRect; TileLock sharedLock; - bool wasPlaceholder; }; struct PlaceholderTileDescriptor { @@ -342,7 +341,6 @@ struct SurfaceDescriptorTiles { float resolution; float frameXResolution; float frameYResolution; - bool isProgressive; }; struct OpUseTiledLayerBuffer { diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index ac3012b6ffd8..50d60d4f7fa7 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -352,8 +352,6 @@ private: DECL_GFX_PREF(Once, "layers.tiled-drawtarget.enabled", TiledDrawTargetEnabled, bool, false); DECL_GFX_PREF(Once, "layers.tiles.adjust", LayersTilesAdjust, bool, true); DECL_GFX_PREF(Once, "layers.tiles.edge-padding", TileEdgePaddingEnabled, bool, true); - DECL_GFX_PREF(Live, "layers.tiles.fade-in.enabled", LayerTileFadeInEnabled, bool, false); - DECL_GFX_PREF(Live, "layers.tiles.fade-in.duration-ms", LayerTileFadeInDuration, uint32_t, 100); DECL_GFX_PREF(Live, "layers.transaction.warning-ms", LayerTransactionWarning, uint32_t, 200); DECL_GFX_PREF(Once, "layers.uniformity-info", UniformityInfo, bool, false); DECL_GFX_PREF(Once, "layers.use-image-offscreen-surfaces", UseImageOffscreenSurfaces, bool, false); From bd52f994bf292f4681be2af5ec97a135e6741793 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 11 Sep 2015 11:21:04 -0700 Subject: [PATCH 098/131] Backed out changeset 4b301ec04c21 (bug 1182665) for android reftest orange CLOSED TREE --- widget/android/nsScreenManagerAndroid.cpp | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/widget/android/nsScreenManagerAndroid.cpp b/widget/android/nsScreenManagerAndroid.cpp index f661bc77edca..9a8b3651fe79 100644 --- a/widget/android/nsScreenManagerAndroid.cpp +++ b/widget/android/nsScreenManagerAndroid.cpp @@ -32,12 +32,6 @@ nsScreenAndroid::GetId(uint32_t *outId) NS_IMETHODIMP nsScreenAndroid::GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) { - if (!mozilla::jni::IsAvailable()) { - // xpcshell most likely - *outLeft = *outTop = *outWidth = *outHeight = 0; - return NS_ERROR_FAILURE; - } - widget::sdk::Rect::LocalRef rect = widget::GeckoAppShell::GetScreenSize(); rect->Left(outLeft); rect->Top(outTop); @@ -59,13 +53,7 @@ nsScreenAndroid::GetAvailRect(int32_t *outLeft, int32_t *outTop, int32_t *outWid NS_IMETHODIMP nsScreenAndroid::GetPixelDepth(int32_t *aPixelDepth) { - if (!mozilla::jni::IsAvailable()) { - // xpcshell most likely - *aPixelDepth = 16; - return NS_ERROR_FAILURE; - } - - *aPixelDepth = widget::GeckoAppShell::GetScreenDepthWrapper(); + *aPixelDepth = AndroidBridge::Bridge()->GetScreenDepth(); return NS_OK; } @@ -79,9 +67,7 @@ nsScreenAndroid::GetColorDepth(int32_t *aColorDepth) void nsScreenAndroid::ApplyMinimumBrightness(uint32_t aBrightness) { - if (mozilla::jni::IsAvailable()) { - widget::GeckoAppShell::SetKeepScreenOn(aBrightness == BRIGHTNESS_FULL); - } + widget::GeckoAppShell::SetKeepScreenOn(aBrightness == BRIGHTNESS_FULL); } NS_IMPL_ISUPPORTS(nsScreenManagerAndroid, nsIScreenManager) From bbe3773db128136bca6ef07ada48fca82b7aa48a Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 11 Sep 2015 11:21:22 -0700 Subject: [PATCH 099/131] Backed out changeset 5b9886673514 (bug 1201541) for android reftest orange CLOSED TREE --- gfx/layers/client/ClientTiledPaintedLayer.cpp | 9 ++++++++- layout/base/FrameLayerBuilder.cpp | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/gfx/layers/client/ClientTiledPaintedLayer.cpp b/gfx/layers/client/ClientTiledPaintedLayer.cpp index c9b59e00b9f4..8de49052dd43 100644 --- a/gfx/layers/client/ClientTiledPaintedLayer.cpp +++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp @@ -411,9 +411,12 @@ ClientTiledPaintedLayer::RenderLayer() void *data = ClientManager()->GetPaintedLayerCallbackData(); if (!mContentClient) { +#if defined(MOZ_B2G) || defined(XP_MACOSX) if (mCreationHint == LayerManager::NONE) { mContentClient = new SingleTiledContentClient(this, ClientManager()); - } else { + } else +#endif + { mContentClient = new MultiTiledContentClient(this, ClientManager()); } @@ -557,6 +560,7 @@ ClientTiledPaintedLayer::RenderLayer() bool ClientTiledPaintedLayer::IsOptimizedFor(LayerManager::PaintedLayerCreationHint aHint) { +#if defined(MOZ_B2G) || defined(XP_MACOSX) // The only creation hint is whether the layer is scrollable or not, and this // is only respected on B2G and OSX, where it's used to determine whether to // use a tiled content client or not. @@ -564,6 +568,9 @@ ClientTiledPaintedLayer::IsOptimizedFor(LayerManager::PaintedLayerCreationHint a // large, scrollable layers, so we want the layer to be recreated in this // situation. return aHint == GetCreationHint(); +#else + return true; +#endif } void diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 0764089c6199..8f7ceaa04edd 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -2040,6 +2040,9 @@ ContainerState::GetLayerCreationHint(const nsIFrame* aAnimatedGeometryRoot) { // Check whether the layer will be scrollable. This is used as a hint to // influence whether tiled layers are used or not. + if (mParameters.mInLowPrecisionDisplayPort) { + return LayerManager::SCROLLABLE; + } nsIFrame* animatedGeometryRootParent = aAnimatedGeometryRoot->GetParent(); nsIScrollableFrame* scrollable = do_QueryFrame(animatedGeometryRootParent); if (scrollable From ca0fa7c1cb9a3d5159ae10c73a282de1103af004 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 11 Sep 2015 11:21:56 -0700 Subject: [PATCH 100/131] Backed out 4 changesets (bug 1182665) for android reftest orange CLOSED TREE Backed out changeset 719a4fbded10 (bug 1182665) Backed out changeset 9559cead8d08 (bug 1182665) Backed out changeset 4080fb4b9a7f (bug 1182665) Backed out changeset c8549221c366 (bug 1182665) --- dom/ipc/ScreenManagerParent.cpp | 4 - gfx/layers/client/ContentClient.cpp | 22 ++++- gfx/thebes/gfxAndroidPlatform.cpp | 14 ++- gfx/thebes/gfxAndroidPlatform.h | 2 + gfx/thebes/gfxPlatform.cpp | 90 +++++++------------ gfx/thebes/gfxPlatform.h | 16 +--- gfx/thebes/gfxPlatformGtk.cpp | 18 ++++ gfx/thebes/gfxPlatformGtk.h | 2 + gfx/thebes/gfxQtPlatform.cpp | 10 ++- gfx/thebes/gfxQtPlatform.h | 2 + gfx/thebes/gfxWindowsPlatform.cpp | 20 +++++ gfx/thebes/gfxWindowsPlatform.h | 2 + mobile/android/base/GeckoAppShell.java | 8 -- widget/android/GeneratedJNIWrappers.cpp | 8 -- widget/android/GeneratedJNIWrappers.h | 17 ---- .../android/bindings/AndroidRect-classes.txt | 2 - widget/android/bindings/Makefile.in | 1 - widget/android/bindings/moz.build | 3 +- widget/android/nsScreenManagerAndroid.cpp | 15 ++-- widget/gtk/nsScreenManagerGtk.cpp | 5 -- 20 files changed, 129 insertions(+), 132 deletions(-) delete mode 100644 widget/android/bindings/AndroidRect-classes.txt diff --git a/dom/ipc/ScreenManagerParent.cpp b/dom/ipc/ScreenManagerParent.cpp index ecf5a595b3be..058709edeadf 100644 --- a/dom/ipc/ScreenManagerParent.cpp +++ b/dom/ipc/ScreenManagerParent.cpp @@ -169,10 +169,6 @@ ScreenManagerParent::RecvScreenForBrowser(const TabId& aTabId, bool ScreenManagerParent::ExtractScreenDetails(nsIScreen* aScreen, ScreenDetails &aDetails) { - if (!aScreen) { - return false; - } - uint32_t id; nsresult rv = aScreen->GetId(&id); NS_ENSURE_SUCCESS(rv, false); diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp index 4d02a90e0faa..1efa41da06af 100644 --- a/gfx/layers/client/ContentClient.cpp +++ b/gfx/layers/client/ContentClient.cpp @@ -69,7 +69,27 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder) return nullptr; } - if (gfxPlatform::GetPlatform()->CanUseDoubleBufferedContent(backend)) { + bool useDoubleBuffering = false; + +#ifdef XP_WIN + if (backend == LayersBackend::LAYERS_D3D11) { + useDoubleBuffering = !!gfxWindowsPlatform::GetPlatform()->GetD3D10Device(); + } else +#endif +#ifdef MOZ_WIDGET_GTK + // We can't use double buffering when using image content with + // Xrender support on Linux, as ContentHostDoubleBuffered is not + // suited for direct uploads to the server. + if (!gfxPlatformGtk::GetPlatform()->UseImageOffscreenSurfaces() || + !gfxPlatformGtk::GetPlatform()->UseXRender()) +#endif + { + useDoubleBuffering = (LayerManagerComposite::SupportsDirectTexturing() && + backend != LayersBackend::LAYERS_D3D9) || + backend == LayersBackend::LAYERS_BASIC; + } + + if (useDoubleBuffering || PR_GetEnv("MOZ_FORCE_DOUBLE_BUFFERING")) { return MakeAndAddRef(aForwarder); } return MakeAndAddRef(aForwarder); diff --git a/gfx/thebes/gfxAndroidPlatform.cpp b/gfx/thebes/gfxAndroidPlatform.cpp index def0438f9b6f..215946c2f365 100644 --- a/gfx/thebes/gfxAndroidPlatform.cpp +++ b/gfx/thebes/gfxAndroidPlatform.cpp @@ -100,7 +100,13 @@ gfxAndroidPlatform::gfxAndroidPlatform() RegisterStrongMemoryReporter(new FreetypeReporter()); - mOffscreenFormat = GetScreenDepth() == 16 + nsCOMPtr screenMgr = do_GetService("@mozilla.org/gfx/screenmanager;1"); + nsCOMPtr screen; + screenMgr->GetPrimaryScreen(getter_AddRefs(screen)); + mScreenDepth = 24; + screen->GetColorDepth(&mScreenDepth); + + mOffscreenFormat = mScreenDepth == 16 ? gfxImageFormat::RGB16_565 : gfxImageFormat::RGB24; @@ -412,6 +418,12 @@ gfxAndroidPlatform::RequiresLinearZoom() return gfxPlatform::RequiresLinearZoom(); } +int +gfxAndroidPlatform::GetScreenDepth() const +{ + return mScreenDepth; +} + bool gfxAndroidPlatform::UseAcceleratedSkiaCanvas() { diff --git a/gfx/thebes/gfxAndroidPlatform.h b/gfx/thebes/gfxAndroidPlatform.h index 3b93b0cd7d39..b87b0a222b64 100644 --- a/gfx/thebes/gfxAndroidPlatform.h +++ b/gfx/thebes/gfxAndroidPlatform.h @@ -80,6 +80,8 @@ public: FT_Library GetFTLibrary(); + virtual int GetScreenDepth() const; + virtual bool CanRenderContentToDataSurface() const override { return true; } diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index f76b8082e754..b696e7b0f105 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -9,7 +9,6 @@ #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/SharedBufferManagerChild.h" #include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter -#include "mozilla/layers/LayerManagerComposite.h" #include "mozilla/Logging.h" #include "mozilla/Services.h" @@ -53,7 +52,6 @@ #include "gfxGraphiteShaper.h" #include "gfx2DGlue.h" #include "gfxGradientCache.h" -#include "gfxUtils.h" // for NextPowerOfTwo #include "nsUnicodeRange.h" #include "nsServiceManagerUtils.h" @@ -388,7 +386,6 @@ gfxPlatform::gfxPlatform() , mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureBackendInfo) , mApzSupportCollector(this, &gfxPlatform::GetApzSupportInfo) , mCompositorBackend(layers::LayersBackend::LAYERS_NONE) - , mScreenDepth(0) { mAllowDownloadableFonts = UNINITIALIZED_VALUE; mFallbackUsesCmaps = UNINITIALIZED_VALUE; @@ -509,7 +506,6 @@ gfxPlatform::Init() InitLayersAccelerationPrefs(); InitLayersIPC(); - gPlatform->PopulateScreenInfo(); gPlatform->ComputeTileSize(); nsresult rv; @@ -1016,45 +1012,43 @@ gfxPlatform::ComputeTileSize() int32_t w = gfxPrefs::LayersTileWidth(); int32_t h = gfxPrefs::LayersTileHeight(); + // TODO We may want to take the screen size into consideration here. if (gfxPrefs::LayersTilesAdjust()) { - gfx::IntSize screenSize = GetScreenSize(); - if (screenSize.width > 0) { - w = h = std::max(std::min(NextPowerOfTwo(screenSize.width) / 2, 1024), 256); - } - #ifdef MOZ_WIDGET_GONK + int32_t format = android::PIXEL_FORMAT_RGBA_8888; android::sp alloc = - new android::GraphicBuffer(w, h, android::PIXEL_FORMAT_RGBA_8888, - android::GraphicBuffer::USAGE_SW_READ_OFTEN | - android::GraphicBuffer::USAGE_SW_WRITE_OFTEN | - android::GraphicBuffer::USAGE_HW_TEXTURE); + new android::GraphicBuffer(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight(), + format, + android::GraphicBuffer::USAGE_SW_READ_OFTEN | + android::GraphicBuffer::USAGE_SW_WRITE_OFTEN | + android::GraphicBuffer::USAGE_HW_TEXTURE); if (alloc.get()) { w = alloc->getStride(); // We want the tiles to be gralloc stride aligned. + // No need to adjust the height here. } #endif } - SetTileSize(w, h); -} - -void -gfxPlatform::PopulateScreenInfo() -{ - nsCOMPtr manager = do_GetService("@mozilla.org/gfx/screenmanager;1"); - MOZ_ASSERT(manager, "failed to get nsIScreenManager"); - - nsCOMPtr screen; - manager->GetPrimaryScreen(getter_AddRefs(screen)); - if (!screen) { - // This can happen in xpcshell, for instance - return; +#ifdef XP_MACOSX + // Use double sized tiles for HiDPI screens. + nsCOMPtr screenManager = + do_GetService("@mozilla.org/gfx/screenmanager;1"); + if (screenManager) { + nsCOMPtr primaryScreen; + screenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen)); + double scaleFactor = 1.0; + if (primaryScreen) { + primaryScreen->GetContentsScaleFactor(&scaleFactor); + } + if (scaleFactor > 1.0) { + w *= 2; + h *= 2; + } } +#endif - screen->GetColorDepth(&mScreenDepth); - - int left, top; - screen->GetRect(&left, &top, &mScreenSize.width, &mScreenSize.height); + SetTileSize(w, h); } bool @@ -2087,6 +2081,13 @@ gfxPlatform::GetLog(eGfxLog aWhichLog) return nullptr; } +int +gfxPlatform::GetScreenDepth() const +{ + NS_WARNING("GetScreenDepth not implemented on this platform -- returning 0!"); + return 0; +} + mozilla::gfx::SurfaceFormat gfxPlatform::Optimal2DFormatForContent(gfxContentType aContent) { @@ -2290,33 +2291,6 @@ gfxPlatform::DisableBufferRotation() sBufferRotationCheckPref = false; } -bool -gfxPlatform::CanUseDoubleBufferedContent(LayersBackend aBackend) const -{ - bool useDoubleBuffering = false; - -#ifdef XP_WIN - if (aBackend == LayersBackend::LAYERS_D3D11) { - useDoubleBuffering = !!gfxWindowsPlatform::GetPlatform()->GetD3D10Device(); - } else -#endif -#ifdef MOZ_WIDGET_GTK - // We can't use double buffering when using image content with - // Xrender support on Linux, as ContentHostDoubleBuffered is not - // suited for direct uploads to the server. - if (!gfxPlatformGtk::GetPlatform()->UseImageOffscreenSurfaces() || - !gfxPlatformGtk::GetPlatform()->UseXRender()) -#endif - { - useDoubleBuffering = (LayerManagerComposite::SupportsDirectTexturing() && - aBackend != LayersBackend::LAYERS_D3D9) || - aBackend == LayersBackend::LAYERS_BASIC; - } - - return useDoubleBuffering || PR_GetEnv("MOZ_FORCE_DOUBLE_BUFFERING"); -} - - already_AddRefed gfxPlatform::GetScaledFontForFontWithCairoSkia(DrawTarget* aTarget, gfxFont* aFont) { diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 156b50ed56ca..b992a6f98a8c 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -496,11 +496,6 @@ public: static bool BufferRotationEnabled(); static void DisableBufferRotation(); - /** - * Check to see if we should use double buffered content client - */ - bool CanUseDoubleBufferedContent(mozilla::layers::LayersBackend aBackend) const; - /** * Are we going to try color management? */ @@ -573,8 +568,7 @@ public: */ static PRLogModuleInfo* GetLog(eGfxLog aWhichLog); - int GetScreenDepth() const { return mScreenDepth; } - mozilla::gfx::IntSize GetScreenSize() const { return mScreenSize; } + virtual int GetScreenDepth() const; /** * Return the layer debugging options to use browser-wide. @@ -768,11 +762,6 @@ private: */ void ComputeTileSize(); - /** - * This uses nsIScreenManager to determine the screen size and color depth - */ - void PopulateScreenInfo(); - nsRefPtr mScreenReferenceSurface; nsTArray mCJKPrefLangs; nsCOMPtr mSRGBOverrideObserver; @@ -800,9 +789,6 @@ private: // Backend that we are compositing with. NONE, if no compositor has been // created yet. mozilla::layers::LayersBackend mCompositorBackend; - - int32_t mScreenDepth; - mozilla::gfx::IntSize mScreenSize; }; #endif /* GFX_PLATFORM_H */ diff --git a/gfx/thebes/gfxPlatformGtk.cpp b/gfx/thebes/gfxPlatformGtk.cpp index dc1bde896dfe..9c8642a151e4 100644 --- a/gfx/thebes/gfxPlatformGtk.cpp +++ b/gfx/thebes/gfxPlatformGtk.cpp @@ -363,6 +363,24 @@ gfxPlatformGtk::GetOffscreenFormat() return gfxImageFormat::RGB24; } +static int sDepth = 0; + +int +gfxPlatformGtk::GetScreenDepth() const +{ + if (!sDepth) { + GdkScreen *screen = gdk_screen_get_default(); + if (screen) { + sDepth = gdk_visual_get_depth(gdk_visual_get_system()); + } else { + sDepth = 24; + } + + } + + return sDepth; +} + void gfxPlatformGtk::GetPlatformCMSOutputProfile(void *&mem, size_t &size) { diff --git a/gfx/thebes/gfxPlatformGtk.h b/gfx/thebes/gfxPlatformGtk.h index 9adac7f39bb5..6f5fa09d0ed2 100644 --- a/gfx/thebes/gfxPlatformGtk.h +++ b/gfx/thebes/gfxPlatformGtk.h @@ -122,6 +122,8 @@ public: virtual gfxImageFormat GetOffscreenFormat() override; + virtual int GetScreenDepth() const override; + bool SupportsApzWheelInput() const override { return true; } diff --git a/gfx/thebes/gfxQtPlatform.cpp b/gfx/thebes/gfxQtPlatform.cpp index 272a6996e742..f0efd8f66594 100644 --- a/gfx/thebes/gfxQtPlatform.cpp +++ b/gfx/thebes/gfxQtPlatform.cpp @@ -53,8 +53,8 @@ gfxQtPlatform::gfxQtPlatform() if (!sFontconfigUtils) sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils(); - int32_t depth = GetScreenDepth(); - if (depth == 16) { + mScreenDepth = qApp->primaryScreen()->depth(); + if (mScreenDepth == 16) { sOffscreenFormat = gfxImageFormat::RGB16_565; } uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA); @@ -195,6 +195,12 @@ gfxQtPlatform::GetOffscreenFormat() return sOffscreenFormat; } +int +gfxQtPlatform::GetScreenDepth() const +{ + return mScreenDepth; +} + already_AddRefed gfxQtPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont* aFont) { diff --git a/gfx/thebes/gfxQtPlatform.h b/gfx/thebes/gfxQtPlatform.h index fad09180df53..5a209d422808 100644 --- a/gfx/thebes/gfxQtPlatform.h +++ b/gfx/thebes/gfxQtPlatform.h @@ -82,6 +82,8 @@ public: static Screen* GetXScreen(QWindow* aWindow = 0); #endif + virtual int GetScreenDepth() const override; + bool AccelerateLayersByDefault() override { return true; } diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index dc63dea98661..4be0acf4c2d9 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -1595,6 +1595,26 @@ gfxWindowsPlatform::IsOptimus() return knowIsOptimus; } +int +gfxWindowsPlatform::GetScreenDepth() const +{ + // if the system doesn't have all displays with the same + // pixel format, just return 24 and move on with life. + if (!GetSystemMetrics(SM_SAMEDISPLAYFORMAT)) + return 24; + + HDC hdc = GetDC(nullptr); + if (!hdc) + return 24; + + int depth = GetDeviceCaps(hdc, BITSPIXEL) * + GetDeviceCaps(hdc, PLANES); + + ReleaseDC(nullptr, hdc); + + return depth; +} + IDXGIAdapter1* gfxWindowsPlatform::GetDXGIAdapter() { diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index 51773691f504..c5dc0efd8dcd 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -139,6 +139,8 @@ public: RENDER_MODE_MAX }; + int GetScreenDepth() const; + RenderMode GetRenderMode() { return mRenderMode; } void SetRenderMode(RenderMode rmode) { mRenderMode = rmode; } diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index b8e9feaaa587..2094c05a0f9c 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -81,7 +81,6 @@ import android.graphics.RectF; import android.graphics.SurfaceTexture; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.hardware.display.DisplayManager; import android.hardware.Sensor; import android.hardware.SensorEventListener; import android.hardware.SensorManager; @@ -108,7 +107,6 @@ import android.util.Base64; import android.util.DisplayMetrics; import android.util.Log; import android.view.ContextThemeWrapper; -import android.view.Display; import android.view.HapticFeedbackConstants; import android.view.Surface; import android.view.SurfaceView; @@ -2673,10 +2671,4 @@ public class GeckoAppShell } return 0; } - - @WrapForJNI - static Rect getScreenSize() { - Display disp = getGeckoInterface().getActivity().getWindowManager().getDefaultDisplay(); - return new Rect(0, 0, disp.getWidth(), disp.getHeight()); - } } diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index 285cf4c8372b..7664ce8deaf4 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -393,14 +393,6 @@ auto GeckoAppShell::GetScreenOrientationWrapper() -> int16_t return mozilla::jni::Method::Call(nullptr, nullptr); } -constexpr char GeckoAppShell::GetScreenSize_t::name[]; -constexpr char GeckoAppShell::GetScreenSize_t::signature[]; - -auto GeckoAppShell::GetScreenSize() -> mozilla::jni::Object::LocalRef -{ - return mozilla::jni::Method::Call(nullptr, nullptr); -} - constexpr char GeckoAppShell::GetShowPasswordSetting_t::name[]; constexpr char GeckoAppShell::GetShowPasswordSetting_t::signature[]; diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index 1523c7588d70..b77c60d5f434 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -944,23 +944,6 @@ public: static auto GetScreenOrientationWrapper() -> int16_t; -public: - struct GetScreenSize_t { - typedef GeckoAppShell Owner; - typedef mozilla::jni::Object::LocalRef ReturnType; - typedef mozilla::jni::Object::Param SetterType; - typedef mozilla::jni::Args<> Args; - static constexpr char name[] = "getScreenSize"; - static constexpr char signature[] = - "()Landroid/graphics/Rect;"; - static const bool isStatic = true; - static const bool isMultithreaded = false; - static const mozilla::jni::ExceptionMode exceptionMode = - mozilla::jni::ExceptionMode::ABORT; - }; - - static auto GetScreenSize() -> mozilla::jni::Object::LocalRef; - public: struct GetShowPasswordSetting_t { typedef GeckoAppShell Owner; diff --git a/widget/android/bindings/AndroidRect-classes.txt b/widget/android/bindings/AndroidRect-classes.txt deleted file mode 100644 index cbacca81e1a4..000000000000 --- a/widget/android/bindings/AndroidRect-classes.txt +++ /dev/null @@ -1,2 +0,0 @@ -android.graphics.Rect -android.graphics.RectF diff --git a/widget/android/bindings/Makefile.in b/widget/android/bindings/Makefile.in index 644c2e19688a..c42ce48862d1 100644 --- a/widget/android/bindings/Makefile.in +++ b/widget/android/bindings/Makefile.in @@ -24,7 +24,6 @@ sdk_processor := \ # We'd like these to be defined in a future GENERATED_EXPORTS list. bindings_exports_FILES := \ - AndroidRect.h \ Bundle.h \ MediaCodec.h \ SurfaceTexture.h \ diff --git a/widget/android/bindings/moz.build b/widget/android/bindings/moz.build index a70bf79ac61a..622e4f6394a6 100644 --- a/widget/android/bindings/moz.build +++ b/widget/android/bindings/moz.build @@ -7,10 +7,9 @@ # List of stems to generate .cpp and .h files for. To add a stem, add it to # this list and ensure that $(stem)-classes.txt exists in this directory. generated = [ - 'AndroidRect', 'Bundle', 'MediaCodec', - 'SurfaceTexture' + 'SurfaceTexture', ] SOURCES += ['!%s.cpp' % stem for stem in generated] diff --git a/widget/android/nsScreenManagerAndroid.cpp b/widget/android/nsScreenManagerAndroid.cpp index 9a8b3651fe79..4cc09728299b 100644 --- a/widget/android/nsScreenManagerAndroid.cpp +++ b/widget/android/nsScreenManagerAndroid.cpp @@ -8,9 +8,6 @@ #include "nsScreenManagerAndroid.h" #include "nsWindow.h" #include "AndroidBridge.h" -#include "GeneratedJNIWrappers.h" -#include "AndroidRect.h" -#include using namespace mozilla; @@ -32,11 +29,13 @@ nsScreenAndroid::GetId(uint32_t *outId) NS_IMETHODIMP nsScreenAndroid::GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) { - widget::sdk::Rect::LocalRef rect = widget::GeckoAppShell::GetScreenSize(); - rect->Left(outLeft); - rect->Top(outTop); - rect->Width(outWidth); - rect->Height(outHeight); + gfxIntSize sz = nsWindow::GetAndroidScreenBounds(); + + *outLeft = 0; + *outTop = 0; + + *outWidth = sz.width; + *outHeight = sz.height; return NS_OK; } diff --git a/widget/gtk/nsScreenManagerGtk.cpp b/widget/gtk/nsScreenManagerGtk.cpp index 236748553d46..8d8d8424d868 100644 --- a/widget/gtk/nsScreenManagerGtk.cpp +++ b/widget/gtk/nsScreenManagerGtk.cpp @@ -99,11 +99,6 @@ nsScreenManagerGtk :: EnsureInit() return NS_OK; mRootWindow = gdk_get_default_root_window(); - if (!mRootWindow) { - // Sometimes we don't initial X (e.g., xpcshell) - return NS_OK; - } - g_object_ref(mRootWindow); // GDK_PROPERTY_CHANGE_MASK ==> PropertyChangeMask, for PropertyNotify From dd94c3ca0641b21b9efa7d51d74ef786680034fc Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Fri, 11 Sep 2015 11:37:05 -0700 Subject: [PATCH 101/131] Backout 13654c18b57f (Bug 1202048) for cgc bustage on a CLOSED TREE. --- js/src/builtin/Eval.cpp | 2 +- js/src/gc/RootMarking.cpp | 4 ++++ js/src/json.cpp | 2 +- js/src/jspubtd.h | 1 + js/src/vm/JSONParser.h | 43 ++++++--------------------------------- 5 files changed, 13 insertions(+), 39 deletions(-) diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp index 59fb11156063..345a0f95d9e6 100644 --- a/js/src/builtin/Eval.cpp +++ b/js/src/builtin/Eval.cpp @@ -183,7 +183,7 @@ ParseEvalStringAsJSON(JSContext* cx, const mozilla::Range chars, Mu ? chars : mozilla::Range(chars.start().get() + 1U, len - 2); - Rooted> parser(cx, JSONParser(cx, jsonChars, JSONParserBase::NoError)); + JSONParser parser(cx, jsonChars, JSONParserBase::NoError); if (!parser.parse(rval)) return EvalJSON_Failure; diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 9d1e82f31be9..8fade7de3974 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -146,6 +146,10 @@ AutoGCRooter::trace(JSTracer* trc) return; } + case JSONPARSER: + static_cast(this)->trace(trc); + return; + case CUSTOM: static_cast(this)->trace(trc); return; diff --git a/js/src/json.cpp b/js/src/json.cpp index f97914a418e0..1e36e7516623 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -822,7 +822,7 @@ js::ParseJSONWithReviver(JSContext* cx, const mozilla::Range chars, MutableHandleValue vp) { /* 15.12.2 steps 2-3. */ - Rooted> parser(cx, JSONParser(cx, chars)); + JSONParser parser(cx, chars); if (!parser.parse(vp)) return false; diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index ca5fc7cb77a3..aa9b246853e9 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -224,6 +224,7 @@ class JS_PUBLIC_API(AutoGCRooter) IONMASM = -19, /* js::jit::MacroAssembler */ WRAPVECTOR = -20, /* js::AutoWrapperVector */ WRAPPER = -21, /* js::AutoWrapperRooter */ + JSONPARSER = -25, /* js::JSONParser */ CUSTOM = -26 /* js::CustomAutoRooter */ }; diff --git a/js/src/vm/JSONParser.h b/js/src/vm/JSONParser.h index 687972392b02..ddeddad6379a 100644 --- a/js/src/vm/JSONParser.h +++ b/js/src/vm/JSONParser.h @@ -20,7 +20,7 @@ namespace js { // JSONParser base class. JSONParser is templatized to work on either Latin1 // or TwoByte input strings, JSONParserBase holds all state and methods that // can be shared between the two encodings. -class MOZ_STACK_CLASS JSONParserBase +class MOZ_STACK_CLASS JSONParserBase : private JS::AutoGCRooter { public: enum ErrorHandling { RaiseError, NoError }; @@ -108,7 +108,8 @@ class MOZ_STACK_CLASS JSONParserBase #endif JSONParserBase(JSContext* cx, ErrorHandling errorHandling) - : cx(cx), + : JS::AutoGCRooter(cx, JSONPARSER), + cx(cx), errorHandling(errorHandling), stack(cx), freeElements(cx), @@ -119,20 +120,6 @@ class MOZ_STACK_CLASS JSONParserBase {} ~JSONParserBase(); - // Allow move construction for use with Rooted. - JSONParserBase(JSONParserBase&& other) - : v(other.v), - cx(other.cx), - errorHandling(other.errorHandling), - stack(mozilla::Move(other.stack)), - freeElements(mozilla::Move(other.freeElements)), - freeProperties(mozilla::Move(other.freeProperties)) -#ifdef DEBUG - , lastToken(mozilla::Move(other.lastToken)) -#endif - {} - - Value numberValue() const { MOZ_ASSERT(lastToken == Number); MOZ_ASSERT(v.isNumber()); @@ -182,16 +169,16 @@ class MOZ_STACK_CLASS JSONParserBase bool finishObject(MutableHandleValue vp, PropertyVector& properties); bool finishArray(MutableHandleValue vp, ElementVector& elements); + private: + friend void AutoGCRooter::trace(JSTracer* trc); void trace(JSTracer* trc); - private: JSONParserBase(const JSONParserBase& other) = delete; void operator=(const JSONParserBase& other) = delete; }; template -class MOZ_STACK_CLASS JSONParser : public JSONParserBase, - public JS::Traceable +class MOZ_STACK_CLASS JSONParser : public JSONParserBase { private: typedef mozilla::RangedPtr CharPtr; @@ -213,14 +200,6 @@ class MOZ_STACK_CLASS JSONParser : public JSONParserBase, MOZ_ASSERT(current <= end); } - /* Allow move construction for use with Rooted. */ - JSONParser(JSONParser&& other) - : JSONParserBase(mozilla::Forward(other)), - current(other.current), - begin(other.begin), - end(other.end) - {} - /* * Parse the JSON data specified at construction time. If it parses * successfully, store the prescribed value in *vp and return true. If an @@ -233,9 +212,6 @@ class MOZ_STACK_CLASS JSONParser : public JSONParserBase, */ bool parse(MutableHandleValue vp); - static void trace(JSONParser* parser, JSTracer* trc) { parser->trace(trc); } - void trace(JSTracer* trc) { JSONParserBase::trace(trc); } - private: template Token readString(); @@ -257,13 +233,6 @@ class MOZ_STACK_CLASS JSONParser : public JSONParserBase, void operator=(const JSONParser& other) = delete; }; -template -struct RootedBase> { - bool parse(MutableHandleValue vp) { - return static_cast>*>(this)->get().parse(vp); - } -}; - } /* namespace js */ #endif /* vm_JSONParser_h */ From 54d08c8ea7227525d968807ac6f72f795db0399a Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Fri, 11 Sep 2015 11:37:37 -0700 Subject: [PATCH 102/131] Backout 148cab7775e5 (Bug 1202051) for cgc bustage on a CLOSED TREE. --- js/src/jscntxt.cpp | 6 +++++- js/src/jscntxt.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index e3d5de043a69..6d2712f192cd 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -947,7 +947,7 @@ ExclusiveContext::recoverFromOutOfMemory() JSContext::JSContext(JSRuntime* rt) : ExclusiveContext(rt, &rt->mainThread, Context_JS), throwing(false), - unwrappedException_(this), + unwrappedException_(UndefinedValue()), options_(), overRecursed_(false), propagatingForcedReturn_(false), @@ -1136,6 +1136,10 @@ JSContext::mark(JSTracer* trc) { /* Stack frames and slots are traced by StackSpace::mark. */ + /* Mark other roots-by-definition in the JSContext. */ + if (isExceptionPending()) + TraceRoot(trc, &unwrappedException_, "unwrapped exception"); + TraceCycleDetectionSet(trc, cycleDetectorSet); if (compartment_) diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index f8adbb60c2d0..8b2ee8e58dfd 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -305,7 +305,7 @@ struct JSContext : public js::ExclusiveContext, private: /* Exception state -- the exception member is a GC root by definition. */ bool throwing; /* is there a pending exception? */ - JS::PersistentRooted unwrappedException_; /* most-recently-thrown exception */ + js::Value unwrappedException_; /* most-recently-thrown exception */ /* Per-context options. */ JS::ContextOptions options_; From bab9b5abf4702f00b1e3c28bde08c5de3648b041 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 11 Sep 2015 11:53:52 -0700 Subject: [PATCH 103/131] Backed out changeset 132aa442af95 (bug 1198544) for browser_ManifestObtainer_obtain.js failures CLOSED TREE --- dom/fetch/Fetch.cpp | 8 ++++---- dom/fetch/FetchDriver.cpp | 14 ++++++------- dom/fetch/FetchDriver.h | 15 +------------- .../test/serviceworkers/fetch/fetch_tests.js | 17 ---------------- .../test/serviceworkers/fetch/interrupt.sjs | 20 ------------------- dom/workers/test/serviceworkers/mochitest.ini | 1 - 6 files changed, 11 insertions(+), 64 deletions(-) delete mode 100644 dom/workers/test/serviceworkers/fetch/interrupt.sjs diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp index 556bb1f31925..47c1c5e5166d 100644 --- a/dom/fetch/Fetch.cpp +++ b/dom/fetch/Fetch.cpp @@ -72,7 +72,7 @@ public: } void - OnResponseAvailableInternal(InternalResponse* aResponse) override; + OnResponseAvailable(InternalResponse* aResponse) override; void OnResponseEnd() override; @@ -99,7 +99,7 @@ public: explicit MainThreadFetchResolver(Promise* aPromise); void - OnResponseAvailableInternal(InternalResponse* aResponse) override; + OnResponseAvailable(InternalResponse* aResponse) override; private: ~MainThreadFetchResolver(); @@ -237,7 +237,7 @@ MainThreadFetchResolver::MainThreadFetchResolver(Promise* aPromise) } void -MainThreadFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse) +MainThreadFetchResolver::OnResponseAvailable(InternalResponse* aResponse) { NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver); AssertIsOnMainThread(); @@ -317,7 +317,7 @@ public: }; void -WorkerFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse) +WorkerFetchResolver::OnResponseAvailable(InternalResponse* aResponse) { AssertIsOnMainThread(); diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index 390f934c21d8..81d91b7b958f 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -883,17 +883,15 @@ FetchDriver::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) { workers::AssertIsOnMainThread(); - if (NS_FAILED(aStatusCode)) { - nsCOMPtr outputStream = do_QueryInterface(mPipeOutputStream); - if (outputStream) { - outputStream->CloseWithStatus(NS_BINDING_FAILED); - } - // We proceed as usual here, since we've already created a successful response - // from OnStartRequest. - } else if (mPipeOutputStream) { + if (mPipeOutputStream) { mPipeOutputStream->Close(); } + if (NS_FAILED(aStatusCode)) { + FailWithNetworkError(); + return aStatusCode; + } + ContinueHttpFetchAfterNetworkFetch(); return NS_OK; } diff --git a/dom/fetch/FetchDriver.h b/dom/fetch/FetchDriver.h index 9a5648579816..96b8f848f200 100644 --- a/dom/fetch/FetchDriver.h +++ b/dom/fetch/FetchDriver.h @@ -32,27 +32,14 @@ class InternalResponse; class FetchDriverObserver { public: - FetchDriverObserver() : mGotResponseAvailable(false) - { } - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchDriverObserver); - void OnResponseAvailable(InternalResponse* aResponse) - { - MOZ_ASSERT(!mGotResponseAvailable); - mGotResponseAvailable = true; - OnResponseAvailableInternal(aResponse); - } + virtual void OnResponseAvailable(InternalResponse* aResponse) = 0; virtual void OnResponseEnd() { }; protected: virtual ~FetchDriverObserver() { }; - - virtual void OnResponseAvailableInternal(InternalResponse* aResponse) = 0; - -private: - bool mGotResponseAvailable; }; class FetchDriver final : public nsIStreamListener, diff --git a/dom/workers/test/serviceworkers/fetch/fetch_tests.js b/dom/workers/test/serviceworkers/fetch/fetch_tests.js index ec65f79bb5e0..c10fd1b87aa7 100644 --- a/dom/workers/test/serviceworkers/fetch/fetch_tests.js +++ b/dom/workers/test/serviceworkers/fetch/fetch_tests.js @@ -319,23 +319,6 @@ fetch(new Request('body-blob', {method: 'POST', body: new Blob(new String('my bo finish(); }); -expectAsyncResult(); -fetch('interrupt.sjs') -.then(function(res) { - my_ok(true, "interrupted fetch succeeded"); - res.text().then(function(body) { - my_ok(false, "interrupted fetch shouldn't have complete body"); - finish(); - }, - function() { - my_ok(true, "interrupted fetch shouldn't have complete body"); - finish(); - }) -}, function(e) { - my_ok(false, "interrupted fetch failed"); - finish(); -}); - ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'].forEach(function(method) { fetchXHRWithMethod('xhr-method-test.txt', method, function(xhr) { my_ok(xhr.status == 200, method + " load should be successful"); diff --git a/dom/workers/test/serviceworkers/fetch/interrupt.sjs b/dom/workers/test/serviceworkers/fetch/interrupt.sjs deleted file mode 100644 index f6fe870efa29..000000000000 --- a/dom/workers/test/serviceworkers/fetch/interrupt.sjs +++ /dev/null @@ -1,20 +0,0 @@ -function handleRequest(request, response) { - var body = "a"; - for (var i = 0; i < 20; i++) { - body += body; - } - - response.seizePower(); - response.write("HTTP/1.1 200 OK\r\n") - var count = 10; - response.write("Content-Length: " + body.length * count + "\r\n"); - response.write("Content-Type: text/plain; charset=utf-8\r\n"); - response.write("Cache-Control: no-cache, must-revalidate\r\n"); - response.write("\r\n"); - - for (var i = 0; i < count; i++) { - response.write(body); - } - - throw Components.results.NS_BINDING_ABORTED; -} diff --git a/dom/workers/test/serviceworkers/mochitest.ini b/dom/workers/test/serviceworkers/mochitest.ini index caa53aff9136..c89ca8c374f4 100644 --- a/dom/workers/test/serviceworkers/mochitest.ini +++ b/dom/workers/test/serviceworkers/mochitest.ini @@ -50,7 +50,6 @@ support-files = fetch/https/clonedresponse/register.html fetch/https/clonedresponse/unregister.html fetch/https/clonedresponse/https_test.js - fetch/interrupt.sjs fetch/origin/index.sjs fetch/origin/index-to-https.sjs fetch/origin/realindex.html From 9985fe899c722cf2fa065eb04f22080ac077d445 Mon Sep 17 00:00:00 2001 From: Botond Ballo Date: Fri, 11 Sep 2015 14:40:09 -0400 Subject: [PATCH 104/131] Bug 1198451 - Add a type-erased callable wrapper, mozilla::Function, to MFBT. r=froydnj --HG-- extra : source : 90ac08992195f6e818a83019567e55e17a350901 --- mfbt/Function.h | 113 ++++++++++++++++++++++++++++++++++++++++++++++++ mfbt/moz.build | 1 + 2 files changed, 114 insertions(+) create mode 100644 mfbt/Function.h diff --git a/mfbt/Function.h b/mfbt/Function.h new file mode 100644 index 000000000000..40b025602060 --- /dev/null +++ b/mfbt/Function.h @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* A type-erased callable wrapper. */ + +#ifndef mozilla_Function_h +#define mozilla_Function_h + +#include "mozilla/Attributes.h" // for MOZ_IMPLICIT +#include "mozilla/Move.h" +#include "mozilla/UniquePtr.h" + +// |Function| is a wrapper that can hold any type of callable +// object that can be invoked in a way that's compatible with |Signature|. +// The standard "type erasure" technique is used to avoid the type of the +// wrapper depending on the concrete type of the wrapped callable. +// +// Supported callable types include non-member functions, static member +// functions, and function objects (that is to say, objects with an overloaded +// call operator; this includes C++11 lambdas). Member functions aren't +// directly supported; they first need to be wrapped into a function object +// using |std::mem_fn()| or an equivalent. +// +// |Signature| is a type of the form |ReturnType(Arguments...)|. Syntactically, +// this is a function type; it's not used in any way other than serving as a +// vehicle to encode the return and argument types into a single type. +// +// |Function| is default-constructible. A default-constructed instance is +// considered "empty". Invoking an empty instance is undefined behaviour. +// An empty instance can be populated with a callable by assigning to it. +// +// This class is intended to provide functionality similar to the C++11 +// standard library class |std::function|. + +namespace mozilla { + +namespace detail { + +template +class FunctionImplBase +{ +public: + virtual ~FunctionImplBase() {} + virtual ReturnType call(Arguments... arguments) = 0; +}; + +template +class FunctionImpl : public FunctionImplBase +{ +public: + explicit FunctionImpl(const Callable& aCallable) : mCallable(aCallable) {} + + ReturnType call(Arguments... aArguments) override + { + return mCallable(Forward(aArguments)...); + } +private: + Callable mCallable; +}; + +} // namespace detail + +// The primary template is never defined. As |Signature| is required to be +// of the form |ReturnType(Arguments...)|, we only define a partial +// specialization that matches this form. This allows us to use |ReturnType| +// and |Arguments| in the definition of the specialization without having to +// introspect |Signature|. +template +class Function; + +template +class Function +{ +public: + Function() {} + + // This constructor is implicit to match the interface of |std::function|. + template + MOZ_IMPLICIT Function(const Callable& aCallable) + : mImpl(MakeUnique>(aCallable)) + {} + + // Move constructor and move assingment operator. + // These should be generated automatically, but MSVC doesn't do that yet. + Function(Function&& aOther) : mImpl(Move(aOther.mImpl)) {} + Function& operator=(Function&& aOther) { + mImpl = Move(aOther.mImpl); + return *this; + } + + template + Function& operator=(const Callable& aCallable) + { + mImpl = MakeUnique>(aCallable); + return *this; + } + + ReturnType operator()(Arguments... aArguments) const + { + MOZ_ASSERT(mImpl); + return mImpl->call(Forward(aArguments)...); + } +private: + // TODO: Consider implementing a small object optimization. + UniquePtr> mImpl; +}; + +} // namespace mozilla + +#endif /* mozilla_Function_h */ diff --git a/mfbt/moz.build b/mfbt/moz.build index 33adee6eefb6..18ae47637e22 100644 --- a/mfbt/moz.build +++ b/mfbt/moz.build @@ -40,6 +40,7 @@ EXPORTS.mozilla = [ 'EnumeratedRange.h', 'EnumSet.h', 'FloatingPoint.h', + 'Function.h', 'GuardObjects.h', 'HashFunctions.h', 'IndexSequence.h', From 78627e8b5d3ee26cf7733167b8318e37a64c76ea Mon Sep 17 00:00:00 2001 From: Botond Ballo Date: Sun, 6 Sep 2015 21:43:34 -0400 Subject: [PATCH 105/131] Bug 1198451 - Tests for mozilla::Function. r=froydnj --HG-- extra : source : 11a2cd3e5c1e051c6bef843b45fe3701364e826a --- mfbt/tests/TestFunction.cpp | 95 +++++++++++++++++++++++++++++++++++++ mfbt/tests/moz.build | 1 + 2 files changed, 96 insertions(+) create mode 100644 mfbt/tests/TestFunction.cpp diff --git a/mfbt/tests/TestFunction.cpp b/mfbt/tests/TestFunction.cpp new file mode 100644 index 000000000000..3a531eb6d74a --- /dev/null +++ b/mfbt/tests/TestFunction.cpp @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + /* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/Assertions.h" +#include "mozilla/Function.h" + +using mozilla::Function; + +#define CHECK(c) \ + do { \ + bool cond = !!(c); \ + MOZ_RELEASE_ASSERT(cond, "Failed assertion: " #c); \ + } while (false) + +struct ConvertibleToInt +{ + operator int() const { return 42; } +}; + +int increment(int arg) { return arg + 1; } + +struct S { + static int increment(int arg) { return arg + 1; } +}; + +struct Incrementor { + int operator()(int arg) { return arg + 1; } +}; + +static void +TestNonmemberFunction() +{ + Function f = &increment; + CHECK(f(42) == 43); +} + +static void +TestStaticMemberFunction() +{ + Function f = &S::increment; + CHECK(f(42) == 43); +} + +static void +TestFunctionObject() +{ + Function f = Incrementor(); + CHECK(f(42) == 43); +} + +static void +TestLambda() +{ + // Test non-capturing lambda + Function f = [](int arg){ return arg + 1; }; + CHECK(f(42) == 43); + + // Test capturing lambda + int one = 1; + Function g = [one](int arg){ return arg + one; }; + CHECK(g(42) == 43); +} + +static void +TestDefaultConstructionAndAssignmentLater() +{ + Function f; // allowed + // Would get an assertion if we tried calling f now. + f = &increment; + CHECK(f(42) == 43); +} + +static void +TestReassignment() +{ + Function f = &increment; + CHECK(f(42) == 43); + f = [](int arg){ return arg + 2; }; + CHECK(f(42) == 44); +} + +int +main() +{ + TestNonmemberFunction(); + TestStaticMemberFunction(); + TestFunctionObject(); + TestLambda(); + TestDefaultConstructionAndAssignmentLater(); + TestReassignment(); + return 0; +} diff --git a/mfbt/tests/moz.build b/mfbt/tests/moz.build index d8a30600a73b..ade09f5aa94b 100644 --- a/mfbt/tests/moz.build +++ b/mfbt/tests/moz.build @@ -17,6 +17,7 @@ CppUnitTests([ 'TestEndian', 'TestEnumSet', 'TestFloatingPoint', + 'TestFunction', 'TestIntegerPrintfMacros', 'TestIntegerRange', 'TestJSONWriter', From 04bf303d99f5c547408e067414be6eb71a418137 Mon Sep 17 00:00:00 2001 From: Botond Ballo Date: Fri, 11 Sep 2015 17:25:23 -0400 Subject: [PATCH 106/131] Bug 1198451 - Disambiguate mozilla::dom::Function from mozilla::Function. r=froydnj --HG-- extra : source : aa0c472e2f7ed9ca9f71682c47f19d5f4b880e7d --- dom/workers/WorkerPrivate.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index e12df9b5066f..5b9f729479a8 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -1103,11 +1103,11 @@ private: class DebuggerImmediateRunnable : public WorkerRunnable { - nsRefPtr mHandler; + nsRefPtr mHandler; public: explicit DebuggerImmediateRunnable(WorkerPrivate* aWorkerPrivate, - Function& aHandler) + dom::Function& aHandler) : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), mHandler(&aHandler) { } @@ -5666,7 +5666,7 @@ WorkerPrivate::PostMessageToDebugger(const nsAString& aMessage) } void -WorkerPrivate::SetDebuggerImmediate(JSContext* aCx, Function& aHandler, +WorkerPrivate::SetDebuggerImmediate(JSContext* aCx, dom::Function& aHandler, ErrorResult& aRv) { AssertIsOnWorkerThread(); @@ -5904,7 +5904,7 @@ WorkerPrivate::ReportError(JSContext* aCx, const char* aMessage, int32_t WorkerPrivate::SetTimeout(JSContext* aCx, - Function* aHandler, + dom::Function* aHandler, const nsAString& aStringHandler, int32_t aTimeout, const Sequence& aArguments, From 3a3a37d45271f7656fc572964958b7867a07abb8 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Fri, 11 Sep 2015 18:52:16 -0700 Subject: [PATCH 107/131] Bug 1200809 part 6 - Convert various natives to new InlinableNatives system. r=nbp --- js/src/builtin/Object.cpp | 3 ++- js/src/builtin/TestingFunctions.cpp | 15 ++++++----- js/src/builtin/TestingFunctions.h | 9 ------- js/src/jit/InlinableNatives.h | 10 +++++++ js/src/jit/MCallOptimize.cpp | 42 ++++++++++++++--------------- js/src/jsarray.cpp | 2 +- js/src/jsfriendapi.cpp | 3 +++ js/src/jsfriendapi.h | 6 ++++- js/src/jsfun.cpp | 3 +++ js/src/jsstr.cpp | 3 ++- js/src/shell/js.cpp | 6 +++-- js/src/vm/GlobalObject.cpp | 11 ++++++-- js/src/vm/GlobalObject.h | 7 ++--- 13 files changed, 71 insertions(+), 49 deletions(-) diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index 5ccb45ac4ff0..039e702eeafd 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -13,6 +13,7 @@ #include "builtin/Eval.h" #include "frontend/BytecodeCompiler.h" +#include "jit/InlinableNatives.h" #include "vm/StringBuffer.h" #include "jsobjinlines.h" @@ -1016,7 +1017,7 @@ static const JSFunctionSpec object_static_methods[] = { JS_FN("is", obj_is, 2, 0), JS_FN("defineProperty", obj_defineProperty, 3, 0), JS_FN("defineProperties", obj_defineProperties, 2, 0), - JS_FN("create", obj_create, 2, 0), + JS_INLINABLE_FN("create", obj_create, 2, 0, ObjectCreate), JS_FN("getOwnPropertyNames", obj_getOwnPropertyNames, 1, 0), JS_FN("getOwnPropertySymbols", obj_getOwnPropertySymbols, 1, 0), JS_SELF_HOSTED_FN("isExtensible", "ObjectIsExtensible", 1, JSPROP_DEFINE_LATE), diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index e20fd269b3df..4875eddd7c07 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -19,6 +19,7 @@ #include "asmjs/AsmJSLink.h" #include "asmjs/AsmJSValidate.h" +#include "jit/InlinableNatives.h" #include "jit/JitFrameIterator.h" #include "js/Debug.h" #include "js/HashTable.h" @@ -1449,8 +1450,8 @@ GetObjectMetadata(JSContext* cx, unsigned argc, Value* vp) return true; } -bool -js::testingFunc_bailout(JSContext* cx, unsigned argc, Value* vp) +static bool +testingFunc_bailout(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); @@ -1459,8 +1460,8 @@ js::testingFunc_bailout(JSContext* cx, unsigned argc, Value* vp) return true; } -bool -js::testingFunc_inJit(JSContext* cx, unsigned argc, Value* vp) +static bool +testingFunc_inJit(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); @@ -1487,8 +1488,8 @@ js::testingFunc_inJit(JSContext* cx, unsigned argc, Value* vp) return true; } -bool -js::testingFunc_inIon(JSContext* cx, unsigned argc, Value* vp) +static bool +testingFunc_inIon(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); @@ -3059,7 +3060,7 @@ gc::ZealModeHelpText), "getObjectMetadata(obj)", " Get the metadata for an object."), - JS_FN_HELP("bailout", testingFunc_bailout, 0, 0, + JS_INLINABLE_FN_HELP("bailout", testingFunc_bailout, 0, 0, TestBailout, "bailout()", " Force a bailout out of ionmonkey (if running in ionmonkey)."), diff --git a/js/src/builtin/TestingFunctions.h b/js/src/builtin/TestingFunctions.h index 325c690e955b..5e7a6e1a3b6e 100644 --- a/js/src/builtin/TestingFunctions.h +++ b/js/src/builtin/TestingFunctions.h @@ -14,21 +14,12 @@ namespace js { bool DefineTestingFunctions(JSContext* cx, HandleObject obj, bool fuzzingSafe); -bool -testingFunc_bailout(JSContext* cx, unsigned argc, Value* vp); - bool testingFunc_assertFloat32(JSContext* cx, unsigned argc, Value* vp); bool testingFunc_assertRecoveredOnBailout(JSContext* cx, unsigned argc, Value* vp); -bool -testingFunc_inJit(JSContext* cx, unsigned argc, Value* vp); - -bool -testingFunc_inIon(JSContext* cx, unsigned argc, Value* vp); - } /* namespace js */ #endif /* builtin_TestingFunctions_h */ diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h index 05bcada40ad0..3216fde8a5ee 100644 --- a/js/src/jit/InlinableNatives.h +++ b/js/src/jit/InlinableNatives.h @@ -8,6 +8,7 @@ #define jit_InlinableNatives_h #define INLINABLE_NATIVE_LIST(_) \ + _(Array) \ _(ArrayIsArray) \ _(ArrayPop) \ _(ArrayShift) \ @@ -67,12 +68,21 @@ _(RegExpExec) \ _(RegExpTest) \ \ + _(String) \ _(StringSplit) \ _(StringCharCodeAt) \ _(StringFromCharCode) \ _(StringCharAt) \ _(StringReplace) \ \ + _(ObjectCreate) \ + \ + _(CallBoundFunction) \ + \ + _(TestBailout) \ + _(TestAssertFloat32) \ + _(TestAssertRecoveredOnBailout) \ + \ _(IntrinsicUnsafeSetReservedSlot) \ _(IntrinsicUnsafeGetReservedSlot) \ _(IntrinsicUnsafeGetObjectFromReservedSlot) \ diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 2d42f0b483b6..31e8620420b7 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -56,28 +56,6 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) return InliningStatus_NotInlined; } - if (native == ArrayConstructor) - return inlineArray(callInfo); - - if (native == StringConstructor) - return inlineStringObject(callInfo); - - // Object natives. - if (native == obj_create) - return inlineObjectCreate(callInfo); - - // Testing Functions - if (native == testingFunc_bailout) - return inlineBailout(callInfo); - if (native == testingFunc_assertFloat32) - return inlineAssertFloat32(callInfo); - if (native == testingFunc_assertRecoveredOnBailout) - return inlineAssertRecoveredOnBailout(callInfo); - - // Bound function - if (native == js::CallOrConstructBoundFunction) - return inlineBoundFunction(callInfo, target); - // Simd functions #define INLINE_FLOAT32X4_SIMD_ARITH_(OP) \ if (native == js::simd_float32x4_##OP) \ @@ -232,6 +210,8 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) switch (InlinableNative inlNative = target->jitInfo()->inlinableNative) { // Array natives. + case InlinableNative::Array: + return inlineArray(callInfo); case InlinableNative::ArrayIsArray: return inlineArrayIsArray(callInfo); case InlinableNative::ArrayPop: @@ -346,6 +326,8 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) return inlineRegExpTest(callInfo); // String natives. + case InlinableNative::String: + return inlineStringObject(callInfo); case InlinableNative::StringSplit: return inlineStringSplit(callInfo); case InlinableNative::StringCharCodeAt: @@ -357,6 +339,22 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) case InlinableNative::StringReplace: return inlineStrReplace(callInfo); + // Object natives. + case InlinableNative::ObjectCreate: + return inlineObjectCreate(callInfo); + + // Bound function. + case InlinableNative::CallBoundFunction: + return inlineBoundFunction(callInfo, target); + + // Testing functions. + case InlinableNative::TestBailout: + return inlineBailout(callInfo); + case InlinableNative::TestAssertFloat32: + return inlineAssertFloat32(callInfo); + case InlinableNative::TestAssertRecoveredOnBailout: + return inlineAssertRecoveredOnBailout(callInfo); + // Slot intrinsics. case InlinableNative::IntrinsicUnsafeSetReservedSlot: return inlineUnsafeSetReservedSlot(callInfo); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 830c665f6a10..b01cc76f630d 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -3234,7 +3234,7 @@ const Class ArrayObject::class_ = { nullptr, /* construct */ nullptr, /* trace */ { - GenericCreateConstructor, + GenericCreateConstructor, CreateArrayPrototype, array_static_methods, nullptr, diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index aea12012b810..fb431d7acbca 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -244,6 +244,9 @@ JS_DefineFunctionsWithHelp(JSContext* cx, HandleObject obj, const JSFunctionSpec if (!fun) return false; + if (fs->jitInfo) + fun->setJitInfo(fs->jitInfo); + if (fs->usage) { if (!DefineHelpProperty(cx, fun, "usage", fs->usage)) return false; diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index a436d279d5ef..bd75bf74a93c 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -280,12 +280,16 @@ struct JSFunctionSpecWithHelp { JSNative call; uint16_t nargs; uint16_t flags; + const JSJitInfo* jitInfo; const char* usage; const char* help; }; #define JS_FN_HELP(name,call,nargs,flags,usage,help) \ - {name, call, nargs, (flags) | JSPROP_ENUMERATE | JSFUN_STUB_GSOPS, usage, help} + {name, call, nargs, (flags) | JSPROP_ENUMERATE | JSFUN_STUB_GSOPS, nullptr, usage, help} +#define JS_INLINABLE_FN_HELP(name,call,nargs,flags,native,usage,help) \ + {name, call, nargs, (flags) | JSPROP_ENUMERATE | JSFUN_STUB_GSOPS, &js::jit::JitInfo_##native,\ + usage, help} #define JS_FS_HELP_END \ {nullptr, nullptr, 0, 0, nullptr, nullptr} diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 2cfd7e14473e..41b6e85617a5 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -31,6 +31,7 @@ #include "frontend/BytecodeCompiler.h" #include "frontend/TokenStream.h" #include "gc/Marking.h" +#include "jit/InlinableNatives.h" #include "jit/Ion.h" #include "jit/JitFrameIterator.h" #include "js/CallNonGenericMethod.h" @@ -1278,6 +1279,8 @@ JSFunction::initBoundFunction(JSContext* cx, HandleObject target, HandleValue th self->initSlotRange(BOUND_FUNCTION_RESERVED_SLOTS, args, argslen); + self->setJitInfo(&jit::JitInfo_CallBoundFunction); + return true; } diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 495c09389a71..6b97938cc482 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -4192,7 +4192,8 @@ js::InitStringClass(JSContext* cx, HandleObject obj) /* Now create the String function. */ RootedFunction ctor(cx); - ctor = global->createConstructor(cx, StringConstructor, cx->names().String, 1); + ctor = global->createConstructor(cx, StringConstructor, cx->names().String, 1, + AllocKind::FUNCTION, &jit::JitInfo_String); if (!ctor) return nullptr; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index b999cd3a1e00..a05928680ec8 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -61,6 +61,7 @@ #include "frontend/Parser.h" #include "gc/GCInternals.h" #include "jit/arm/Simulator-arm.h" +#include "jit/InlinableNatives.h" #include "jit/Ion.h" #include "jit/JitcodeMap.h" #include "jit/OptimizationTracking.h" @@ -4878,11 +4879,12 @@ static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = { " arguments[0] (of the call to nestedShell) will be argv[1], arguments[1] will\n" " be argv[2], etc."), - JS_FN_HELP("assertFloat32", testingFunc_assertFloat32, 2, 0, + JS_INLINABLE_FN_HELP("assertFloat32", testingFunc_assertFloat32, 2, 0, TestAssertFloat32, "assertFloat32(value, isFloat32)", " In IonMonkey only, asserts that value has (resp. hasn't) the MIRType_Float32 if isFloat32 is true (resp. false)."), - JS_FN_HELP("assertRecoveredOnBailout", testingFunc_assertRecoveredOnBailout, 2, 0, + JS_INLINABLE_FN_HELP("assertRecoveredOnBailout", testingFunc_assertRecoveredOnBailout, 2, 0, +TestAssertRecoveredOnBailout, "assertRecoveredOnBailout(var)", " In IonMonkey only, asserts that variable has RecoveredOnBailout flag."), diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 90b8851b3f60..54af37add1b9 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -451,10 +451,17 @@ GlobalObject::warnOnceAbout(JSContext* cx, HandleObject obj, WarnOnceFlag flag, JSFunction* GlobalObject::createConstructor(JSContext* cx, Native ctor, JSAtom* nameArg, unsigned length, - gc::AllocKind kind) + gc::AllocKind kind, const JSJitInfo* jitInfo) { RootedAtom name(cx, nameArg); - return NewNativeConstructor(cx, ctor, length, name, kind); + JSFunction* fun = NewNativeConstructor(cx, ctor, length, name, kind); + if (!fun) + return nullptr; + + if (jitInfo) + fun->setJitInfo(jitInfo); + + return fun; } static NativeObject* diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index aa251cfe7b7f..b5de00e47a46 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -299,7 +299,8 @@ class GlobalObject : public NativeObject */ JSFunction* createConstructor(JSContext* cx, JSNative ctor, JSAtom* name, unsigned length, - gc::AllocKind kind = gc::AllocKind::FUNCTION); + gc::AllocKind kind = gc::AllocKind::FUNCTION, + const JSJitInfo* jitInfo = nullptr); /* * Create an object to serve as [[Prototype]] for instances of the given @@ -900,14 +901,14 @@ typedef HashSet, SystemAllocPolicy> * for ClassSpecs. */ -template +template JSObject* GenericCreateConstructor(JSContext* cx, JSProtoKey key) { // Note - We duplicate the trick from ClassName() so that we don't need to // include jsatominlines.h here. PropertyName* name = (&cx->names().Null)[key]; - return cx->global()->createConstructor(cx, ctor, name, length, kind); + return cx->global()->createConstructor(cx, ctor, name, length, kind, jitInfo); } inline JSObject* From 34f74c8efb1fc6b5bc4d868cfbff74966fa9ad9a Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Fri, 11 Sep 2015 18:52:32 -0700 Subject: [PATCH 108/131] Bug 1200809 part 7 - Convert SIMD natives to new InlinableNatives system. r=nbp --- js/src/builtin/SIMD.cpp | 5 +- js/src/jit/InlinableNatives.h | 3 + js/src/jit/IonBuilder.h | 3 + js/src/jit/MCallOptimize.cpp | 328 +++++++++++++++++++--------------- 4 files changed, 191 insertions(+), 148 deletions(-) diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index 8ed622d1b54a..594fb28ca4d5 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -21,6 +21,7 @@ #include "jsprf.h" #include "builtin/TypedObject.h" +#include "jit/InlinableNatives.h" #include "js/Value.h" #include "jsobjinlines.h" @@ -244,7 +245,7 @@ const JSFunctionSpec Float32x4Defn::TypedObjectMethods[] = { const JSFunctionSpec Float32x4Defn::Methods[] = { #define SIMD_FLOAT32X4_FUNCTION_ITEM(Name, Func, Operands) \ - JS_FN(#Name, js::simd_float32x4_##Name, Operands, 0), + JS_INLINABLE_FN(#Name, js::simd_float32x4_##Name, Operands, 0, SimdFloat32x4), FLOAT32X4_FUNCTION_LIST(SIMD_FLOAT32X4_FUNCTION_ITEM) #undef SIMD_FLOAT32x4_FUNCTION_ITEM JS_FS_END @@ -344,7 +345,7 @@ const JSFunctionSpec Int32x4Defn::TypedObjectMethods[] = { const JSFunctionSpec Int32x4Defn::Methods[] = { #define SIMD_INT32X4_FUNCTION_ITEM(Name, Func, Operands) \ - JS_FN(#Name, js::simd_int32x4_##Name, Operands, 0), + JS_INLINABLE_FN(#Name, js::simd_int32x4_##Name, Operands, 0, SimdInt32x4), INT32X4_FUNCTION_LIST(SIMD_INT32X4_FUNCTION_ITEM) #undef SIMD_INT32X4_FUNCTION_ITEM JS_FS_END diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h index 3216fde8a5ee..d3df3460e163 100644 --- a/js/src/jit/InlinableNatives.h +++ b/js/src/jit/InlinableNatives.h @@ -79,6 +79,9 @@ \ _(CallBoundFunction) \ \ + _(SimdInt32x4) \ + _(SimdFloat32x4) \ + \ _(TestBailout) \ _(TestAssertFloat32) \ _(TestAssertRecoveredOnBailout) \ diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 0f8f2053cb70..fbd56f86ac21 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -842,6 +842,9 @@ class IonBuilder IonBuilder::InliningStatus boxSimd(CallInfo& callInfo, MInstruction* ins, InlineTypedObject* templateObj); + InliningStatus inlineSimdInt32x4(CallInfo& callInfo, JSNative native); + InliningStatus inlineSimdFloat32x4(CallInfo& callInfo, JSNative native); + template InliningStatus inlineBinarySimd(CallInfo& callInfo, JSNative native, typename T::Operation op, SimdTypeDescr::Type type); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 31e8620420b7..c3bc3212fb78 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -39,7 +39,6 @@ IonBuilder::InliningStatus IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) { MOZ_ASSERT(target->isNative()); - JSNative native = target->native(); if (!optimizationInfo().inlineNative()) { trackOptimizationOutcome(TrackedOutcome::CantInlineDisabledIon); @@ -56,151 +55,6 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) return InliningStatus_NotInlined; } - // Simd functions -#define INLINE_FLOAT32X4_SIMD_ARITH_(OP) \ - if (native == js::simd_float32x4_##OP) \ - return inlineBinarySimd(callInfo, native, MSimdBinaryArith::Op_##OP, \ - SimdTypeDescr::Float32x4); - -#define INLINE_INT32X4_SIMD_ARITH_(OP) \ - if (native == js::simd_int32x4_##OP) \ - return inlineBinarySimd(callInfo, native, MSimdBinaryArith::Op_##OP, \ - SimdTypeDescr::Int32x4); - - ARITH_COMMONX4_SIMD_OP(INLINE_INT32X4_SIMD_ARITH_) - ARITH_COMMONX4_SIMD_OP(INLINE_FLOAT32X4_SIMD_ARITH_) - BINARY_ARITH_FLOAT32X4_SIMD_OP(INLINE_FLOAT32X4_SIMD_ARITH_) -#undef INLINE_SIMD_ARITH_ -#undef INLINE_FLOAT32X4_SIMD_ARITH_ - -#define INLINE_SIMD_BITWISE_(OP) \ - if (native == js::simd_int32x4_##OP) \ - return inlineBinarySimd(callInfo, native, MSimdBinaryBitwise::OP##_, \ - SimdTypeDescr::Int32x4); \ - if (native == js::simd_float32x4_##OP) \ - return inlineBinarySimd(callInfo, native, MSimdBinaryBitwise::OP##_, \ - SimdTypeDescr::Float32x4); - - BITWISE_COMMONX4_SIMD_OP(INLINE_SIMD_BITWISE_) -#undef INLINE_SIMD_BITWISE_ - - if (native == js::simd_int32x4_shiftLeftByScalar) - return inlineBinarySimd(callInfo, native, MSimdShift::lsh, SimdTypeDescr::Int32x4); - if (native == js::simd_int32x4_shiftRightArithmeticByScalar) - return inlineBinarySimd(callInfo, native, MSimdShift::rsh, SimdTypeDescr::Int32x4); - if (native == js::simd_int32x4_shiftRightLogicalByScalar) - return inlineBinarySimd(callInfo, native, MSimdShift::ursh, SimdTypeDescr::Int32x4); - -#define INLINE_SIMD_COMPARISON_(OP) \ - if (native == js::simd_int32x4_##OP) \ - return inlineCompSimd(callInfo, native, MSimdBinaryComp::OP, SimdTypeDescr::Int32x4); \ - if (native == js::simd_float32x4_##OP) \ - return inlineCompSimd(callInfo, native, MSimdBinaryComp::OP, SimdTypeDescr::Float32x4); - - COMP_COMMONX4_TO_INT32X4_SIMD_OP(INLINE_SIMD_COMPARISON_) -#undef INLINE_SIMD_COMPARISON_ - - if (native == js::simd_int32x4_extractLane) - return inlineSimdExtractLane(callInfo, native, SimdTypeDescr::Int32x4); - if (native == js::simd_float32x4_extractLane) - return inlineSimdExtractLane(callInfo, native, SimdTypeDescr::Float32x4); - - if (native == js::simd_int32x4_replaceLane) - return inlineSimdReplaceLane(callInfo, native, SimdTypeDescr::Int32x4); - if (native == js::simd_float32x4_replaceLane) - return inlineSimdReplaceLane(callInfo, native, SimdTypeDescr::Float32x4); - - if (native == js::simd_int32x4_not) - return inlineUnarySimd(callInfo, native, MSimdUnaryArith::not_, SimdTypeDescr::Int32x4); - if (native == js::simd_int32x4_neg) - return inlineUnarySimd(callInfo, native, MSimdUnaryArith::neg, SimdTypeDescr::Int32x4); - -#define INLINE_SIMD_FLOAT32X4_UNARY_(OP) \ - if (native == js::simd_float32x4_##OP) \ - return inlineUnarySimd(callInfo, native, MSimdUnaryArith::OP, SimdTypeDescr::Float32x4); - - UNARY_ARITH_FLOAT32X4_SIMD_OP(INLINE_SIMD_FLOAT32X4_UNARY_) - INLINE_SIMD_FLOAT32X4_UNARY_(neg) -#undef INLINE_SIMD_FLOAT32X4_UNARY_ - - if (native == js::simd_float32x4_not) - return inlineUnarySimd(callInfo, native, MSimdUnaryArith::not_, SimdTypeDescr::Float32x4); - - typedef bool IsCast; - if (native == js::simd_float32x4_fromInt32x4) - return inlineSimdConvert(callInfo, native, IsCast(false), SimdTypeDescr::Int32x4, SimdTypeDescr::Float32x4); - if (native == js::simd_int32x4_fromFloat32x4) - return inlineSimdConvert(callInfo, native, IsCast(false), SimdTypeDescr::Float32x4, SimdTypeDescr::Int32x4); - if (native == js::simd_float32x4_fromInt32x4Bits) - return inlineSimdConvert(callInfo, native, IsCast(true), SimdTypeDescr::Int32x4, SimdTypeDescr::Float32x4); - if (native == js::simd_int32x4_fromFloat32x4Bits) - return inlineSimdConvert(callInfo, native, IsCast(true), SimdTypeDescr::Float32x4, SimdTypeDescr::Int32x4); - - if (native == js::simd_int32x4_splat) - return inlineSimdSplat(callInfo, native, SimdTypeDescr::Int32x4); - if (native == js::simd_float32x4_splat) - return inlineSimdSplat(callInfo, native, SimdTypeDescr::Float32x4); - - if (native == js::simd_int32x4_check) - return inlineSimdCheck(callInfo, native, SimdTypeDescr::Int32x4); - if (native == js::simd_float32x4_check) - return inlineSimdCheck(callInfo, native, SimdTypeDescr::Float32x4); - - typedef bool IsElementWise; - if (native == js::simd_int32x4_select) - return inlineSimdSelect(callInfo, native, IsElementWise(true), SimdTypeDescr::Int32x4); - if (native == js::simd_int32x4_selectBits) - return inlineSimdSelect(callInfo, native, IsElementWise(false), SimdTypeDescr::Int32x4); - if (native == js::simd_float32x4_select) - return inlineSimdSelect(callInfo, native, IsElementWise(true), SimdTypeDescr::Float32x4); - - if (native == js::simd_int32x4_swizzle) - return inlineSimdShuffle(callInfo, native, SimdTypeDescr::Int32x4, 1, 4); - if (native == js::simd_float32x4_swizzle) - return inlineSimdShuffle(callInfo, native, SimdTypeDescr::Float32x4, 1, 4); - if (native == js::simd_int32x4_shuffle) - return inlineSimdShuffle(callInfo, native, SimdTypeDescr::Int32x4, 2, 4); - if (native == js::simd_float32x4_shuffle) - return inlineSimdShuffle(callInfo, native, SimdTypeDescr::Float32x4, 2, 4); - - if (native == js::simd_int32x4_load) - return inlineSimdLoad(callInfo, native, SimdTypeDescr::Int32x4, 4); - if (native == js::simd_int32x4_load1) - return inlineSimdLoad(callInfo, native, SimdTypeDescr::Int32x4, 1); - if (native == js::simd_int32x4_load2) - return inlineSimdLoad(callInfo, native, SimdTypeDescr::Int32x4, 2); - if (native == js::simd_int32x4_load3) - return inlineSimdLoad(callInfo, native, SimdTypeDescr::Int32x4, 3); - - if (native == js::simd_float32x4_load) - return inlineSimdLoad(callInfo, native, SimdTypeDescr::Float32x4, 4); - if (native == js::simd_float32x4_load1) - return inlineSimdLoad(callInfo, native, SimdTypeDescr::Float32x4, 1); - if (native == js::simd_float32x4_load2) - return inlineSimdLoad(callInfo, native, SimdTypeDescr::Float32x4, 2); - if (native == js::simd_float32x4_load3) - return inlineSimdLoad(callInfo, native, SimdTypeDescr::Float32x4, 3); - - if (native == js::simd_int32x4_store) - return inlineSimdStore(callInfo, native, SimdTypeDescr::Int32x4, 4); - if (native == js::simd_int32x4_store1) - return inlineSimdStore(callInfo, native, SimdTypeDescr::Int32x4, 1); - if (native == js::simd_int32x4_store2) - return inlineSimdStore(callInfo, native, SimdTypeDescr::Int32x4, 2); - if (native == js::simd_int32x4_store3) - return inlineSimdStore(callInfo, native, SimdTypeDescr::Int32x4, 3); - if (native == js::simd_float32x4_store) - return inlineSimdStore(callInfo, native, SimdTypeDescr::Float32x4, 4); - if (native == js::simd_float32x4_store1) - return inlineSimdStore(callInfo, native, SimdTypeDescr::Float32x4, 1); - if (native == js::simd_float32x4_store2) - return inlineSimdStore(callInfo, native, SimdTypeDescr::Float32x4, 2); - if (native == js::simd_float32x4_store3) - return inlineSimdStore(callInfo, native, SimdTypeDescr::Float32x4, 3); - - if (native == js::simd_int32x4_bool) - return inlineSimdBool(callInfo, native, SimdTypeDescr::Int32x4); - if (!target->jitInfo() || target->jitInfo()->type() != JSJitInfo::InlinableNative) { // Reaching here means we tried to inline a native for which there is no // Ion specialization. @@ -347,6 +201,12 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) case InlinableNative::CallBoundFunction: return inlineBoundFunction(callInfo, target); + // SIMD natives. + case InlinableNative::SimdInt32x4: + return inlineSimdInt32x4(callInfo, target->native()); + case InlinableNative::SimdFloat32x4: + return inlineSimdFloat32x4(callInfo, target->native()); + // Testing functions. case InlinableNative::TestBailout: return inlineBailout(callInfo); @@ -3163,6 +3023,182 @@ IonBuilder::inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* descr) return InliningStatus_Inlined; } +IonBuilder::InliningStatus +IonBuilder::inlineSimdInt32x4(CallInfo& callInfo, JSNative native) +{ +#define INLINE_INT32X4_SIMD_ARITH_(OP) \ + if (native == js::simd_int32x4_##OP) \ + return inlineBinarySimd(callInfo, native, MSimdBinaryArith::Op_##OP, \ + SimdTypeDescr::Int32x4); + + ARITH_COMMONX4_SIMD_OP(INLINE_INT32X4_SIMD_ARITH_) +#undef INLINE_INT32X4_SIMD_ARITH_ + +#define INLINE_SIMD_BITWISE_(OP) \ + if (native == js::simd_int32x4_##OP) \ + return inlineBinarySimd(callInfo, native, MSimdBinaryBitwise::OP##_, \ + SimdTypeDescr::Int32x4); + + BITWISE_COMMONX4_SIMD_OP(INLINE_SIMD_BITWISE_) +#undef INLINE_SIMD_BITWISE_ + + if (native == js::simd_int32x4_shiftLeftByScalar) + return inlineBinarySimd(callInfo, native, MSimdShift::lsh, SimdTypeDescr::Int32x4); + if (native == js::simd_int32x4_shiftRightArithmeticByScalar) + return inlineBinarySimd(callInfo, native, MSimdShift::rsh, SimdTypeDescr::Int32x4); + if (native == js::simd_int32x4_shiftRightLogicalByScalar) + return inlineBinarySimd(callInfo, native, MSimdShift::ursh, SimdTypeDescr::Int32x4); + +#define INLINE_SIMD_COMPARISON_(OP) \ + if (native == js::simd_int32x4_##OP) \ + return inlineCompSimd(callInfo, native, MSimdBinaryComp::OP, SimdTypeDescr::Int32x4); + + COMP_COMMONX4_TO_INT32X4_SIMD_OP(INLINE_SIMD_COMPARISON_) +#undef INLINE_SIMD_COMPARISON_ + + if (native == js::simd_int32x4_extractLane) + return inlineSimdExtractLane(callInfo, native, SimdTypeDescr::Int32x4); + if (native == js::simd_int32x4_replaceLane) + return inlineSimdReplaceLane(callInfo, native, SimdTypeDescr::Int32x4); + + if (native == js::simd_int32x4_not) + return inlineUnarySimd(callInfo, native, MSimdUnaryArith::not_, SimdTypeDescr::Int32x4); + if (native == js::simd_int32x4_neg) + return inlineUnarySimd(callInfo, native, MSimdUnaryArith::neg, SimdTypeDescr::Int32x4); + + typedef bool IsCast; + if (native == js::simd_int32x4_fromFloat32x4) + return inlineSimdConvert(callInfo, native, IsCast(false), SimdTypeDescr::Float32x4, SimdTypeDescr::Int32x4); + if (native == js::simd_int32x4_fromFloat32x4Bits) + return inlineSimdConvert(callInfo, native, IsCast(true), SimdTypeDescr::Float32x4, SimdTypeDescr::Int32x4); + + if (native == js::simd_int32x4_splat) + return inlineSimdSplat(callInfo, native, SimdTypeDescr::Int32x4); + + if (native == js::simd_int32x4_check) + return inlineSimdCheck(callInfo, native, SimdTypeDescr::Int32x4); + + typedef bool IsElementWise; + if (native == js::simd_int32x4_select) + return inlineSimdSelect(callInfo, native, IsElementWise(true), SimdTypeDescr::Int32x4); + if (native == js::simd_int32x4_selectBits) + return inlineSimdSelect(callInfo, native, IsElementWise(false), SimdTypeDescr::Int32x4); + + if (native == js::simd_int32x4_swizzle) + return inlineSimdShuffle(callInfo, native, SimdTypeDescr::Int32x4, 1, 4); + if (native == js::simd_int32x4_shuffle) + return inlineSimdShuffle(callInfo, native, SimdTypeDescr::Int32x4, 2, 4); + + if (native == js::simd_int32x4_load) + return inlineSimdLoad(callInfo, native, SimdTypeDescr::Int32x4, 4); + if (native == js::simd_int32x4_load1) + return inlineSimdLoad(callInfo, native, SimdTypeDescr::Int32x4, 1); + if (native == js::simd_int32x4_load2) + return inlineSimdLoad(callInfo, native, SimdTypeDescr::Int32x4, 2); + if (native == js::simd_int32x4_load3) + return inlineSimdLoad(callInfo, native, SimdTypeDescr::Int32x4, 3); + + if (native == js::simd_int32x4_store) + return inlineSimdStore(callInfo, native, SimdTypeDescr::Int32x4, 4); + if (native == js::simd_int32x4_store1) + return inlineSimdStore(callInfo, native, SimdTypeDescr::Int32x4, 1); + if (native == js::simd_int32x4_store2) + return inlineSimdStore(callInfo, native, SimdTypeDescr::Int32x4, 2); + if (native == js::simd_int32x4_store3) + return inlineSimdStore(callInfo, native, SimdTypeDescr::Int32x4, 3); + + if (native == js::simd_int32x4_bool) + return inlineSimdBool(callInfo, native, SimdTypeDescr::Int32x4); + + return InliningStatus_NotInlined; +} + +IonBuilder::InliningStatus +IonBuilder::inlineSimdFloat32x4(CallInfo& callInfo, JSNative native) +{ + // Simd functions +#define INLINE_FLOAT32X4_SIMD_ARITH_(OP) \ + if (native == js::simd_float32x4_##OP) \ + return inlineBinarySimd(callInfo, native, MSimdBinaryArith::Op_##OP, \ + SimdTypeDescr::Float32x4); + + ARITH_COMMONX4_SIMD_OP(INLINE_FLOAT32X4_SIMD_ARITH_) + BINARY_ARITH_FLOAT32X4_SIMD_OP(INLINE_FLOAT32X4_SIMD_ARITH_) +#undef INLINE_FLOAT32X4_SIMD_ARITH_ + +#define INLINE_SIMD_BITWISE_(OP) \ + if (native == js::simd_float32x4_##OP) \ + return inlineBinarySimd(callInfo, native, MSimdBinaryBitwise::OP##_, \ + SimdTypeDescr::Float32x4); + + BITWISE_COMMONX4_SIMD_OP(INLINE_SIMD_BITWISE_) +#undef INLINE_SIMD_BITWISE_ + +#define INLINE_SIMD_COMPARISON_(OP) \ + if (native == js::simd_float32x4_##OP) \ + return inlineCompSimd(callInfo, native, MSimdBinaryComp::OP, SimdTypeDescr::Float32x4); + + COMP_COMMONX4_TO_INT32X4_SIMD_OP(INLINE_SIMD_COMPARISON_) +#undef INLINE_SIMD_COMPARISON_ + + if (native == js::simd_float32x4_extractLane) + return inlineSimdExtractLane(callInfo, native, SimdTypeDescr::Float32x4); + if (native == js::simd_float32x4_replaceLane) + return inlineSimdReplaceLane(callInfo, native, SimdTypeDescr::Float32x4); + +#define INLINE_SIMD_FLOAT32X4_UNARY_(OP) \ + if (native == js::simd_float32x4_##OP) \ + return inlineUnarySimd(callInfo, native, MSimdUnaryArith::OP, SimdTypeDescr::Float32x4); + + UNARY_ARITH_FLOAT32X4_SIMD_OP(INLINE_SIMD_FLOAT32X4_UNARY_) + INLINE_SIMD_FLOAT32X4_UNARY_(neg) +#undef INLINE_SIMD_FLOAT32X4_UNARY_ + + if (native == js::simd_float32x4_not) + return inlineUnarySimd(callInfo, native, MSimdUnaryArith::not_, SimdTypeDescr::Float32x4); + + typedef bool IsCast; + if (native == js::simd_float32x4_fromInt32x4) + return inlineSimdConvert(callInfo, native, IsCast(false), SimdTypeDescr::Int32x4, SimdTypeDescr::Float32x4); + if (native == js::simd_float32x4_fromInt32x4Bits) + return inlineSimdConvert(callInfo, native, IsCast(true), SimdTypeDescr::Int32x4, SimdTypeDescr::Float32x4); + + if (native == js::simd_float32x4_splat) + return inlineSimdSplat(callInfo, native, SimdTypeDescr::Float32x4); + + if (native == js::simd_float32x4_check) + return inlineSimdCheck(callInfo, native, SimdTypeDescr::Float32x4); + + typedef bool IsElementWise; + if (native == js::simd_float32x4_select) + return inlineSimdSelect(callInfo, native, IsElementWise(true), SimdTypeDescr::Float32x4); + + if (native == js::simd_float32x4_swizzle) + return inlineSimdShuffle(callInfo, native, SimdTypeDescr::Float32x4, 1, 4); + if (native == js::simd_float32x4_shuffle) + return inlineSimdShuffle(callInfo, native, SimdTypeDescr::Float32x4, 2, 4); + + if (native == js::simd_float32x4_load) + return inlineSimdLoad(callInfo, native, SimdTypeDescr::Float32x4, 4); + if (native == js::simd_float32x4_load1) + return inlineSimdLoad(callInfo, native, SimdTypeDescr::Float32x4, 1); + if (native == js::simd_float32x4_load2) + return inlineSimdLoad(callInfo, native, SimdTypeDescr::Float32x4, 2); + if (native == js::simd_float32x4_load3) + return inlineSimdLoad(callInfo, native, SimdTypeDescr::Float32x4, 3); + + if (native == js::simd_float32x4_store) + return inlineSimdStore(callInfo, native, SimdTypeDescr::Float32x4, 4); + if (native == js::simd_float32x4_store1) + return inlineSimdStore(callInfo, native, SimdTypeDescr::Float32x4, 1); + if (native == js::simd_float32x4_store2) + return inlineSimdStore(callInfo, native, SimdTypeDescr::Float32x4, 2); + if (native == js::simd_float32x4_store3) + return inlineSimdStore(callInfo, native, SimdTypeDescr::Float32x4, 3); + + return InliningStatus_NotInlined; +} + IonBuilder::InliningStatus IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr) { From 0491a186c1048b403d9f7479921c605c2ebdcbab Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Fri, 11 Sep 2015 18:53:19 -0700 Subject: [PATCH 109/131] Bug 1200809 part 8 - Don't call shouldAbortOnPreliminaryGroups if we have an uninlinable native. r=bhackett --- js/src/jit/MCallOptimize.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index c3bc3212fb78..92a2cdc66b4c 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -45,6 +45,13 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) return InliningStatus_NotInlined; } + if (!target->jitInfo() || target->jitInfo()->type() != JSJitInfo::InlinableNative) { + // Reaching here means we tried to inline a native for which there is no + // Ion specialization. + trackOptimizationOutcome(TrackedOutcome::CantInlineNativeNoSpecialization); + return InliningStatus_NotInlined; + } + // Default failure reason is observing an unsupported type. trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadType); @@ -55,13 +62,6 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) return InliningStatus_NotInlined; } - if (!target->jitInfo() || target->jitInfo()->type() != JSJitInfo::InlinableNative) { - // Reaching here means we tried to inline a native for which there is no - // Ion specialization. - trackOptimizationOutcome(TrackedOutcome::CantInlineNativeNoSpecialization); - return InliningStatus_NotInlined; - } - switch (InlinableNative inlNative = target->jitInfo()->inlinableNative) { // Array natives. case InlinableNative::Array: From 653a1da394699c8da5501afcaf2cc3b975e81ce5 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 11 Sep 2015 21:58:15 -0400 Subject: [PATCH 110/131] Bug 1201529 - Fall back to rootmost metrics if there is no root content document metrics. r=botond --HG-- extra : commitid : IueYz1Pt0HX --- .../composite/AsyncCompositionManager.cpp | 55 +++++++++++-------- .../composite/AsyncCompositionManager.h | 7 ++- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index 66f36da1a3ee..b02ebf5bf6a1 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -586,13 +586,14 @@ AdjustForClip(const Matrix4x4& asyncTransform, Layer* aLayer) } bool -AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer) +AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer, + bool* aOutFoundRoot) { bool appliedTransform = false; for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { appliedTransform |= - ApplyAsyncContentTransformToTree(child); + ApplyAsyncContentTransformToTree(child, aOutFoundRoot); } Matrix4x4 oldTransform = aLayer->GetTransform(); @@ -647,29 +648,30 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer) // bug 1036967 removed the (dead) call. #if defined(MOZ_ANDROID_APZ) - bool rootContentLayer = metrics.IsRootContent(); -#ifdef MOZ_B2GDROID - // B2GDroid is a special snowflake since it doesn't seem to have any root - // content document. However we still need to send a setFirstPaintViewport - // message, so we use the root of the layer tree as the root content layer - // instead. For the most part this should work fine; the Java code will just - // think the root layer is the "main" content, which in a manner of speaking, - // it is. - rootContentLayer = (aLayer->GetParent() == nullptr); -#endif // MOZ_B2GDROID - if (rootContentLayer) { - if (mIsFirstPaint) { - CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel().ToScaleFactor(); - LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.GetScrollOffset() * geckoZoom); - mContentRect = metrics.GetScrollableRect(); - SetFirstPaintViewport(scrollOffsetLayerPixels, - geckoZoom, - mContentRect); + // If we find a metrics which is the root content doc, use that. If not, use + // the root layer. Since this function recurses on children first we should + // only end up using the root layer if the entire tree was devoid of a + // root content metrics. This is a temporary solution; in the long term we + // should not need the root content metrics at all. See bug 1201529 comment + // 6 for details. + if (!(*aOutFoundRoot)) { + *aOutFoundRoot = metrics.IsRootContent() || /* RCD */ + (aLayer->GetParent() == nullptr && /* rootmost metrics */ + i + 1 >= aLayer->GetFrameMetricsCount()); + if (*aOutFoundRoot) { + if (mIsFirstPaint) { + CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel().ToScaleFactor(); + LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.GetScrollOffset() * geckoZoom); + mContentRect = metrics.GetScrollableRect(); + SetFirstPaintViewport(scrollOffsetLayerPixels, + geckoZoom, + mContentRect); + } + mIsFirstPaint = false; + mLayersUpdated = false; } - mIsFirstPaint = false; - mLayersUpdated = false; } -#endif // MOZ_ANDROID_APZ +#endif // Transform the current local clip by this APZC's async transform. If we're // using containerful scrolling, then the clip is not part of the scrolled @@ -1160,7 +1162,12 @@ AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame, // its own platform-specific async rendering that is done partially // in Gecko and partially in Java. wantNextFrame |= SampleAPZAnimations(LayerMetricsWrapper(root), aCurrentFrame); - if (!ApplyAsyncContentTransformToTree(root)) { + bool foundRoot = false; + if (ApplyAsyncContentTransformToTree(root, &foundRoot)) { +#if defined(MOZ_ANDROID_APZ) + MOZ_ASSERT(foundRoot); +#endif + } else { nsAutoTArray scrollableLayers; #ifdef MOZ_WIDGET_ANDROID mLayerManager->GetRootScrollableLayers(scrollableLayers); diff --git a/gfx/layers/composite/AsyncCompositionManager.h b/gfx/layers/composite/AsyncCompositionManager.h index 694667e7da00..7deca1c93f1d 100644 --- a/gfx/layers/composite/AsyncCompositionManager.h +++ b/gfx/layers/composite/AsyncCompositionManager.h @@ -128,8 +128,11 @@ public: private: void TransformScrollableLayer(Layer* aLayer); // Return true if an AsyncPanZoomController content transform was - // applied for |aLayer|. - bool ApplyAsyncContentTransformToTree(Layer* aLayer); + // applied for |aLayer|. |*aOutFoundRoot| is set to true on Android only, if + // one of the metrics on one of the layers was determined to be the "root" + // and its state was synced to the Java front-end. |aOutFoundRoot| must be + // non-null. + bool ApplyAsyncContentTransformToTree(Layer* aLayer, bool* aOutFoundRoot); /** * Update the shadow transform for aLayer assuming that is a scrollbar, * so that it stays in sync with the content that is being scrolled by APZ. From 6630a65ba42d1070da760018d1c69cdd67c19af3 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 11 Sep 2015 21:58:16 -0400 Subject: [PATCH 111/131] Bug 1201529 - Ensure that zoomable scrollframes return true from WantAsyncScroll(). r=botond --HG-- extra : commitid : 29B0WVGYfId --- gfx/layers/apz/test/helper_bug982141.html | 3 ++- gfx/tests/reftest/1143303-1.svg | 5 +++++ layout/base/ZoomConstraintsClient.cpp | 8 ++++++++ layout/generic/nsGfxScrollFrame.cpp | 18 ++++++++++++++++++ layout/generic/nsGfxScrollFrame.h | 11 +++++++++++ layout/generic/nsIScrollableFrame.h | 5 +++++ .../reftests/reftest-sanity/async-zoom-2.html | 5 +++++ 7 files changed, 54 insertions(+), 1 deletion(-) diff --git a/gfx/layers/apz/test/helper_bug982141.html b/gfx/layers/apz/test/helper_bug982141.html index d81f65fd039f..a9fcfd010cfc 100644 --- a/gfx/layers/apz/test/helper_bug982141.html +++ b/gfx/layers/apz/test/helper_bug982141.html @@ -5,6 +5,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=982141 --> + Test for Bug 982141, helper page - + Mozilla Bug 982141
    diff --git a/gfx/tests/reftest/1143303-1.svg b/gfx/tests/reftest/1143303-1.svg index 0ef50874cf65..198111013361 100644 --- a/gfx/tests/reftest/1143303-1.svg +++ b/gfx/tests/reftest/1143303-1.svg @@ -4,6 +4,11 @@ --> + + Testcase for small circles diff --git a/layout/base/ZoomConstraintsClient.cpp b/layout/base/ZoomConstraintsClient.cpp index de6eb8aa6ede..b81323d0f7d0 100644 --- a/layout/base/ZoomConstraintsClient.cpp +++ b/layout/base/ZoomConstraintsClient.cpp @@ -215,6 +215,14 @@ ZoomConstraintsClient::RefreshZoomConstraints() } } + // We only ever create a ZoomConstraintsClient for an RCD, so the RSF of + // the presShell must be the RCD-RSF (if it exists). + MOZ_ASSERT(mPresShell->GetPresContext()->IsRootContentDocument()); + if (nsIScrollableFrame* rcdrsf = mPresShell->GetRootScrollFrameAsScrollable()) { + ZCC_LOG("Notifying RCD-RSF that it is zoomable: %d\n", zoomConstraints.mAllowZoom); + rcdrsf->SetZoomableByAPZ(zoomConstraints.mAllowZoom); + } + ScrollableLayerGuid newGuid(0, presShellId, viewId); if (mGuid && mGuid.value() != newGuid) { ZCC_LOG("Clearing old constraints in %p for { %u, %" PRIu64 " }\n", diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 257bc4f526a9..efa8979987e8 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1108,9 +1108,26 @@ static bool IsFocused(nsIContent* aContent) } #endif +void +ScrollFrameHelper::SetZoomableByAPZ(bool aZoomable) +{ + if (mZoomableByAPZ != aZoomable) { + // We might be changing the result of WantAsyncScroll() so schedule a + // paint to make sure we pick up the result of that change. + mZoomableByAPZ = aZoomable; + mOuter->SchedulePaint(); + } +} + bool ScrollFrameHelper::WantAsyncScroll() const { + // If zooming is allowed, and this is a frame that's allowed to zoom, then + // we want it to be async-scrollable or zooming will not be permitted. + if (mZoomableByAPZ) { + return true; + } + ScrollbarStyles styles = GetScrollbarStylesFromFrame(); uint32_t directions = mOuter->GetScrollTargetFrame()->GetPerceivedScrollingDirections(); bool isVScrollable = !!(directions & nsIScrollableFrame::VERTICAL) && @@ -1831,6 +1848,7 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter, , mIgnoreMomentumScroll(false) , mScaleToResolution(false) , mTransformingByAPZ(false) + , mZoomableByAPZ(false) , mVelocityQueue(aOuter->PresContext()) { if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) { diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index f02bcfb3db67..48d518a7ea7a 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -360,6 +360,8 @@ public: bool IsTransformingByAPZ() const { return mTransformingByAPZ; } + void SetZoomableByAPZ(bool aZoomable); + bool UsesContainerScrolling() const; void ScheduleSyntheticMouseMove(); @@ -534,6 +536,9 @@ public: // (as best as we can tell on the main thread, anyway). bool mTransformingByAPZ:1; + // True if the APZ is allowed to zoom this scrollframe. + bool mZoomableByAPZ:1; + mozilla::layout::ScrollVelocityQueue mVelocityQueue; protected: @@ -922,6 +927,9 @@ public: bool IsTransformingByAPZ() const override { return mHelper.IsTransformingByAPZ(); } + void SetZoomableByAPZ(bool aZoomable) override { + mHelper.SetZoomableByAPZ(aZoomable); + } #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override; @@ -1330,6 +1338,9 @@ public: bool IsTransformingByAPZ() const override { return mHelper.IsTransformingByAPZ(); } + void SetZoomableByAPZ(bool aZoomable) override { + mHelper.SetZoomableByAPZ(aZoomable); + } #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override; diff --git a/layout/generic/nsIScrollableFrame.h b/layout/generic/nsIScrollableFrame.h index 57ba49377c38..9adda26333ba 100644 --- a/layout/generic/nsIScrollableFrame.h +++ b/layout/generic/nsIScrollableFrame.h @@ -444,6 +444,11 @@ public: virtual void SetTransformingByAPZ(bool aTransforming) = 0; virtual bool IsTransformingByAPZ() const = 0; + /** + * Notify this scroll frame that it can be zoomed by APZ. + */ + virtual void SetZoomableByAPZ(bool aZoomable) = 0; + /** * Whether or not this frame uses containerful scrolling. */ diff --git a/layout/reftests/reftest-sanity/async-zoom-2.html b/layout/reftests/reftest-sanity/async-zoom-2.html index 6ca883678853..3d7a66b47050 100644 --- a/layout/reftests/reftest-sanity/async-zoom-2.html +++ b/layout/reftests/reftest-sanity/async-zoom-2.html @@ -1,5 +1,10 @@ + +
    From 2cb1884c191c29c7cc68e24736de1120fcae1acc Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 11 Sep 2015 21:58:16 -0400 Subject: [PATCH 112/131] Bug 1201529 - Prevent calls to set the resolution or displayport from browser.js when APZ is enabled. r=rbarker --HG-- extra : commitid : Bk7IbhdZ1GS --- mobile/android/chrome/content/browser.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 850050f7698e..c924ec5fdcb1 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -3742,6 +3742,12 @@ Tab.prototype = { }, setViewport: function(aViewport) { + if (AppConstants.MOZ_ANDROID_APZ) { + // This should already be getting short-circuited out in GeckoLayerClient, + // but this is an extra safety precaution + return; + } + // Transform coordinates based on zoom let x = aViewport.x / aViewport.zoom; let y = aViewport.y / aViewport.zoom; @@ -3761,6 +3767,9 @@ Tab.prototype = { }, setResolution: function(aZoom, aForce) { + if (AppConstants.MOZ_ANDROID_APZ) { + return; + } // Set zoom level if (aForce || !fuzzyEquals(aZoom, this._zoom)) { this._zoom = aZoom; @@ -3834,6 +3843,9 @@ Tab.prototype = { }, sendViewportUpdate: function(aPageSizeUpdate) { + if (AppConstants.MOZ_ANDROID_APZ) { + return; + } let viewport = this.getViewport(); let displayPort = Services.androidBridge.getDisplayPort(aPageSizeUpdate, BrowserApp.isBrowserContentDocumentDisplayed(), this.id, viewport); if (displayPort != null) From 9ebc137a8256cdf1d579740bff4086d82de40590 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 11 Sep 2015 21:58:16 -0400 Subject: [PATCH 113/131] Bug 1201581 - Extract a helper method. r=rbarker --HG-- extra : commitid : G3fI5OSxBKC --- .../composite/AsyncCompositionManager.cpp | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index b02ebf5bf6a1..c0adea4f26ed 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -585,6 +585,29 @@ AdjustForClip(const Matrix4x4& asyncTransform, Layer* aLayer) return result; } +static void +ExpandRootClipRect(Layer* aLayer, const ScreenMargin& aFixedLayerMargins) +{ + // For Fennec we want to expand the root scrollable layer clip rect based on + // the fixed position margins. In particular, we want this while the dynamic + // toolbar is in the process of sliding offscreen and the area of the + // LayerView visible to the user is larger than the viewport size that Gecko + // knows about (and therefore larger than the clip rect). We could also just + // clear the clip rect on aLayer entirely but this seems more precise. + Maybe rootClipRect = aLayer->AsLayerComposite()->GetShadowClipRect(); + if (rootClipRect && aFixedLayerMargins != ScreenMargin()) { +#ifndef MOZ_WIDGET_ANDROID + // We should never enter here on anything other than Fennec, since + // aFixedLayerMargins should be empty everywhere else. + MOZ_ASSERT(false); +#endif + ParentLayerRect rect(rootClipRect.value()); + rect.Deflate(ViewAs(aFixedLayerMargins, + PixelCastJustification::ScreenIsParentLayerForRoot)); + aLayer->AsLayerComposite()->SetShadowClipRect(Some(RoundedOut(rect))); + } +} + bool AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer, bool* aOutFoundRoot) @@ -1105,24 +1128,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer) AlignFixedAndStickyLayers(aLayer, aLayer, metrics.GetScrollId(), oldTransform, aLayer->GetLocalTransform(), fixedLayerMargins); - // For Fennec we want to expand the root scrollable layer clip rect based on - // the fixed position margins. In particular, we want this while the dynamic - // toolbar is in the process of sliding offscreen and the area of the - // LayerView visible to the user is larger than the viewport size that Gecko - // knows about (and therefore larger than the clip rect). We could also just - // clear the clip rect on aLayer entirely but this seems more precise. - Maybe rootClipRect = aLayer->AsLayerComposite()->GetShadowClipRect(); - if (rootClipRect && fixedLayerMargins != ScreenMargin()) { -#ifndef MOZ_WIDGET_ANDROID - // We should never enter here on anything other than Fennec, since - // fixedLayerMargins should be empty everywhere else. - MOZ_ASSERT(false); -#endif - ParentLayerRect rect(rootClipRect.value()); - rect.Deflate(ViewAs(fixedLayerMargins, - PixelCastJustification::ScreenIsParentLayerForRoot)); - aLayer->AsLayerComposite()->SetShadowClipRect(Some(RoundedOut(rect))); - } + ExpandRootClipRect(aLayer, fixedLayerMargins); } void From 711b35cb5667bbcaa0cd8b8f023ed853db79ab9c Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 11 Sep 2015 21:58:16 -0400 Subject: [PATCH 114/131] Bug 1201581 - Hook up the syncFrameMetrics call to sync metrics info from the compositor to Java-land on each composite. r=rbarker --HG-- extra : commitid : JByEVaIboTo --- .../composite/AsyncCompositionManager.cpp | 32 ++++++++++++------- .../composite/AsyncCompositionManager.h | 8 ++--- mobile/android/base/gfx/GeckoLayerClient.java | 20 +++++++----- widget/android/AndroidBridge.cpp | 24 +++++++------- widget/android/AndroidBridge.h | 10 ++++-- widget/android/GeneratedJNIWrappers.cpp | 2 +- widget/android/GeneratedJNIWrappers.h | 8 ++--- 7 files changed, 62 insertions(+), 42 deletions(-) diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index c0adea4f26ed..70bc2a10a2e2 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -623,7 +623,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer, Matrix4x4 combinedAsyncTransform; bool hasAsyncTransform = false; - ScreenMargin fixedLayerMargins(0, 0, 0, 0); + ScreenMargin fixedLayerMargins; // Each layer has multiple clips. Its local clip, which must move with async // transforms, and its scrollframe clips, which are the clips between each @@ -666,9 +666,6 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer, } const FrameMetrics& metrics = aLayer->GetFrameMetrics(i); - // TODO: When we enable APZ on Fennec, we'll need to call SyncFrameMetrics here. - // When doing so, it might be useful to look at how it was called here before - // bug 1036967 removed the (dead) call. #if defined(MOZ_ANDROID_APZ) // If we find a metrics which is the root content doc, use that. If not, use @@ -682,16 +679,27 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer, (aLayer->GetParent() == nullptr && /* rootmost metrics */ i + 1 >= aLayer->GetFrameMetricsCount()); if (*aOutFoundRoot) { + CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel().ToScaleFactor(); if (mIsFirstPaint) { - CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel().ToScaleFactor(); LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.GetScrollOffset() * geckoZoom); mContentRect = metrics.GetScrollableRect(); SetFirstPaintViewport(scrollOffsetLayerPixels, geckoZoom, mContentRect); + } else { + // Compute the painted displayport in document-relative CSS pixels. + CSSRect displayPort(metrics.GetCriticalDisplayPort().IsEmpty() ? + metrics.GetDisplayPort() : + metrics.GetCriticalDisplayPort()); + displayPort += metrics.GetScrollOffset(); + SyncFrameMetrics(scrollOffset, + geckoZoom * asyncTransformWithoutOverscroll.mScale, + metrics.GetScrollableRect(), displayPort, geckoZoom, mLayersUpdated, + mPaintSyncId, fixedLayerMargins); } mIsFirstPaint = false; mLayersUpdated = false; + mPaintSyncId = 0; } } #endif @@ -770,6 +778,8 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer, appliedTransform = true; } + ExpandRootClipRect(aLayer, fixedLayerMargins); + if (aLayer->GetScrollbarDirection() != Layer::NONE) { ApplyAsyncTransformToScrollbar(aLayer); } @@ -1242,18 +1252,18 @@ AsyncCompositionManager::SyncViewportInfo(const LayerIntRect& aDisplayPort, void AsyncCompositionManager::SyncFrameMetrics(const ParentLayerPoint& aScrollOffset, - float aZoom, + const CSSToParentLayerScale& aZoom, const CSSRect& aCssPageRect, - bool aLayersUpdated, const CSSRect& aDisplayPort, - const CSSToLayerScale& aDisplayResolution, - bool aIsFirstPaint, + const CSSToLayerScale& aPaintedResolution, + bool aLayersUpdated, + int32_t aPaintSyncId, ScreenMargin& aFixedLayerMargins) { #ifdef MOZ_WIDGET_ANDROID AndroidBridge::Bridge()->SyncFrameMetrics(aScrollOffset, aZoom, aCssPageRect, - aLayersUpdated, aDisplayPort, - aDisplayResolution, aIsFirstPaint, + aDisplayPort, aPaintedResolution, + aLayersUpdated, aPaintSyncId, aFixedLayerMargins); #endif } diff --git a/gfx/layers/composite/AsyncCompositionManager.h b/gfx/layers/composite/AsyncCompositionManager.h index 7deca1c93f1d..4432b125bd3e 100644 --- a/gfx/layers/composite/AsyncCompositionManager.h +++ b/gfx/layers/composite/AsyncCompositionManager.h @@ -151,12 +151,12 @@ private: CSSToParentLayerScale& aScale, ScreenMargin& aFixedLayerMargins); void SyncFrameMetrics(const ParentLayerPoint& aScrollOffset, - float aZoom, + const CSSToParentLayerScale& aZoom, const CSSRect& aCssPageRect, - bool aLayersUpdated, const CSSRect& aDisplayPort, - const CSSToLayerScale& aDisplayResolution, - bool aIsFirstPaint, + const CSSToLayerScale& aPaintedResolution, + bool aLayersUpdated, + int32_t aPaintSyncId, ScreenMargin& aFixedLayerMargins); /** diff --git a/mobile/android/base/gfx/GeckoLayerClient.java b/mobile/android/base/gfx/GeckoLayerClient.java index 1975a7d9e5e0..68b1635e1153 100644 --- a/mobile/android/base/gfx/GeckoLayerClient.java +++ b/mobile/android/base/gfx/GeckoLayerClient.java @@ -688,17 +688,21 @@ class GeckoLayerClient implements LayerView.Listener, PanZoomTarget } @WrapForJNI(allowMultithread = true) - public ViewTransform syncFrameMetrics(float offsetX, float offsetY, float zoom, + public ViewTransform syncFrameMetrics(float scrollX, float scrollY, float zoom, float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom, - boolean layersUpdated, int x, int y, int width, int height, float resolution, - boolean isFirstPaint) + int dpX, int dpY, int dpWidth, int dpHeight, float paintedResolution, + boolean layersUpdated, int paintSyncId) { - if (isFirstPaint) { - setFirstPaintViewport(offsetX, offsetY, zoom, - cssPageLeft, cssPageTop, cssPageRight, cssPageBottom); + // TODO: optimize this so it doesn't create so much garbage - it's a + // hot path + RectF cssPageRect = new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom); + synchronized (getLock()) { + mViewportMetrics = mViewportMetrics.setViewportOrigin(scrollX, scrollY) + .setZoomFactor(zoom) + .setPageRect(RectUtils.scale(cssPageRect, zoom), cssPageRect); } - - return syncViewportInfo(x, y, width, height, resolution, layersUpdated, 0); + return syncViewportInfo(dpX, dpY, dpWidth, dpHeight, paintedResolution, + layersUpdated, paintSyncId); } @WrapForJNI(allowMultithread = true) diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index 1eb2d3358065..569c6508d81a 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -1479,25 +1479,27 @@ AndroidBridge::SyncViewportInfo(const LayerIntRect& aDisplayPort, const CSSToLay aFixedLayerMargins.left = viewTransform->FixedLayerMarginLeft(); } -void AndroidBridge::SyncFrameMetrics(const ParentLayerPoint& aScrollOffset, float aZoom, const CSSRect& aCssPageRect, - bool aLayersUpdated, const CSSRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution, - bool aIsFirstPaint, ScreenMargin& aFixedLayerMargins) +void AndroidBridge::SyncFrameMetrics(const ParentLayerPoint& aScrollOffset, + const CSSToParentLayerScale& aZoom, + const CSSRect& aCssPageRect, + const CSSRect& aDisplayPort, + const CSSToLayerScale& aPaintedResolution, + bool aLayersUpdated, int32_t aPaintSyncId, + ScreenMargin& aFixedLayerMargins) { if (!mLayerClient) { ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__); return; } - // convert the displayport rect from scroll-relative CSS pixels to document-relative device pixels - LayerRect dpUnrounded = aDisplayPort * aDisplayResolution; - dpUnrounded += LayerPoint::FromUnknownPoint(aScrollOffset.ToUnknownPoint()); - LayerIntRect dp = gfx::RoundedToInt(dpUnrounded); - + // convert the displayport rect from document-relative CSS pixels to + // document-relative device pixels + LayerIntRect dp = gfx::RoundedToInt(aDisplayPort * aPaintedResolution); ViewTransform::LocalRef viewTransform = mLayerClient->SyncFrameMetrics( - aScrollOffset.x, aScrollOffset.y, aZoom, + aScrollOffset.x, aScrollOffset.y, aZoom.scale, aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost(), - aLayersUpdated, dp.x, dp.y, dp.width, dp.height, aDisplayResolution.scale, - aIsFirstPaint); + dp.x, dp.y, dp.width, dp.height, aPaintedResolution.scale, + aLayersUpdated, aPaintSyncId); MOZ_ASSERT(viewTransform, "No view transform object!"); diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index 7893fb592308..910c3897d0cf 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -253,9 +253,13 @@ public: void SyncViewportInfo(const LayerIntRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution, bool aLayersUpdated, int32_t aPaintSyncId, ParentLayerRect& aScrollRect, CSSToParentLayerScale& aScale, ScreenMargin& aFixedLayerMargins); - void SyncFrameMetrics(const ParentLayerPoint& aScrollOffset, float aZoom, const CSSRect& aCssPageRect, - bool aLayersUpdated, const CSSRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution, - bool aIsFirstPaint, ScreenMargin& aFixedLayerMargins); + void SyncFrameMetrics(const ParentLayerPoint& aScrollOffset, + const CSSToParentLayerScale& aZoom, + const CSSRect& aCssPageRect, + const CSSRect& aDisplayPort, + const CSSToLayerScale& aPaintedResolution, + bool aLayersUpdated, int32_t aPaintSyncId, + ScreenMargin& aFixedLayerMargins); void AddPluginView(jobject view, const LayoutDeviceRect& rect, bool isFullScreen); diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index 7664ce8deaf4..9ddd80864443 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -1138,7 +1138,7 @@ auto GeckoLayerClient::SetPageRect(float a0, float a1, float a2, float a3) const constexpr char GeckoLayerClient::SyncFrameMetrics_t::name[]; constexpr char GeckoLayerClient::SyncFrameMetrics_t::signature[]; -auto GeckoLayerClient::SyncFrameMetrics(float a0, float a1, float a2, float a3, float a4, float a5, float a6, bool a7, int32_t a8, int32_t a9, int32_t a10, int32_t a11, float a12, bool a13) const -> mozilla::jni::Object::LocalRef +auto GeckoLayerClient::SyncFrameMetrics(float a0, float a1, float a2, float a3, float a4, float a5, float a6, int32_t a7, int32_t a8, int32_t a9, int32_t a10, float a11, bool a12, int32_t a13) const -> mozilla::jni::Object::LocalRef { return mozilla::jni::Method::Call(this, nullptr, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); } diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index b77c60d5f434..a36ff9666db2 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -2718,23 +2718,23 @@ public: float, float, float, - bool, int32_t, int32_t, int32_t, int32_t, float, - bool> Args; + bool, + int32_t> Args; static constexpr char name[] = "syncFrameMetrics"; static constexpr char signature[] = - "(FFFFFFFZIIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;"; + "(FFFFFFFIIIIFZI)Lorg/mozilla/gecko/gfx/ViewTransform;"; static const bool isStatic = false; static const bool isMultithreaded = true; static const mozilla::jni::ExceptionMode exceptionMode = mozilla::jni::ExceptionMode::ABORT; }; - auto SyncFrameMetrics(float, float, float, float, float, float, float, bool, int32_t, int32_t, int32_t, int32_t, float, bool) const -> mozilla::jni::Object::LocalRef; + auto SyncFrameMetrics(float, float, float, float, float, float, float, int32_t, int32_t, int32_t, int32_t, float, bool, int32_t) const -> mozilla::jni::Object::LocalRef; public: struct SyncViewportInfo_t { From 138287abda3a29d0fe43f1ec9566a6ed017fdbae Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 11 Sep 2015 21:59:43 -0400 Subject: [PATCH 115/131] Bug 1182197 workaround. Add a null-check for mGlobal for now. r=nsm --- dom/promise/Promise.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index f15c0be6a949..197ccaf5b17d 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -1368,7 +1368,7 @@ Promise::Settle(JS::Handle aValue, PromiseState aState) } #endif - if (mGlobal->IsDying()) { + if (!mGlobal || mGlobal->IsDying()) { return; } From 494542fe41deedba2142210de654b84e802b2cc8 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 11 Sep 2015 21:59:43 -0400 Subject: [PATCH 116/131] Bug 1191942. Make sure to not schedule requestAnimationFrame callbacks if animations are paused. r=roc --- dom/base/nsDocument.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 360392e50c8a..7e380b4cbe8a 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -3886,7 +3886,7 @@ void nsDocument::DeleteShell() { mExternalResourceMap.HideViewers(); - if (IsEventHandlingEnabled()) { + if (IsEventHandlingEnabled() && !AnimationsPaused()) { RevokeAnimationFrameNotifications(); } if (nsPresContext* presContext = mPresShell->GetPresContext()) { @@ -4632,7 +4632,7 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject) // our layout history state now. mLayoutHistoryState = GetLayoutHistoryState(); - if (mPresShell && !EventHandlingSuppressed()) { + if (mPresShell && !EventHandlingSuppressed() && !AnimationsPaused()) { RevokeAnimationFrameNotifications(); } @@ -10318,7 +10318,8 @@ nsIDocument::ScheduleFrameRequestCallback(FrameRequestCallback& aCallback, DebugOnly request = mFrameRequestCallbacks.AppendElement(FrameRequest(aCallback, newHandle)); NS_ASSERTION(request, "This is supposed to be infallible!"); - if (!alreadyRegistered && mPresShell && IsEventHandlingEnabled()) { + if (!alreadyRegistered && mPresShell && IsEventHandlingEnabled() && + !AnimationsPaused()) { mPresShell->GetPresContext()->RefreshDriver()-> ScheduleFrameRequestCallbacks(this); } From 839f8d927dcf77aa1fceda6b191a3bf5b6d45437 Mon Sep 17 00:00:00 2001 From: Heiher Date: Sat, 12 Sep 2015 19:15:51 +0800 Subject: [PATCH 117/131] Bug 1194139 - IonMonkey: MIPS: Split shareable code to mips-shared in Assembler-mips32. r=nbp --- .../Assembler-mips-shared.cpp} | 753 +++--------- .../Assembler-mips-shared.h} | 145 +-- js/src/jit/mips32/Assembler-mips32.cpp | 1230 +------------------ js/src/jit/mips32/Assembler-mips32.h | 1246 +------------------- js/src/moz.build | 1 + 5 files changed, 195 insertions(+), 3180 deletions(-) copy js/src/jit/{mips32/Assembler-mips32.cpp => mips-shared/Assembler-mips-shared.cpp} (50%) copy js/src/jit/{mips32/Assembler-mips32.h => mips-shared/Assembler-mips-shared.h} (86%) --HG-- rename : js/src/jit/mips32/Assembler-mips32.cpp => js/src/jit/mips-shared/Assembler-mips-shared.cpp rename : js/src/jit/mips32/Assembler-mips32.h => js/src/jit/mips-shared/Assembler-mips-shared.h --- .../jit/mips-shared/Assembler-mips-shared.cpp | 1230 ++++++++++++++++ .../jit/mips-shared/Assembler-mips-shared.h | 1276 +++++++++++++++++ js/src/jit/mips32/Assembler-mips32.cpp | 1230 +--------------- js/src/jit/mips32/Assembler-mips32.h | 1246 +--------------- js/src/moz.build | 1 + 5 files changed, 2528 insertions(+), 2455 deletions(-) create mode 100644 js/src/jit/mips-shared/Assembler-mips-shared.cpp create mode 100644 js/src/jit/mips-shared/Assembler-mips-shared.h diff --git a/js/src/jit/mips-shared/Assembler-mips-shared.cpp b/js/src/jit/mips-shared/Assembler-mips-shared.cpp new file mode 100644 index 000000000000..1e332ed7544e --- /dev/null +++ b/js/src/jit/mips-shared/Assembler-mips-shared.cpp @@ -0,0 +1,1230 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jit/mips-shared/Assembler-mips-shared.h" + +#include "mozilla/DebugOnly.h" +#include "mozilla/MathAlgorithms.h" + +#include "jscompartment.h" +#include "jsutil.h" + +#include "gc/Marking.h" +#include "jit/ExecutableAllocator.h" +#include "jit/JitCompartment.h" + +using mozilla::DebugOnly; + +using namespace js; +using namespace js::jit; + +// Encode a standard register when it is being used as rd, the rs, and +// an extra register(rt). These should never be called with an InvalidReg. +uint32_t +js::jit::RS(Register r) +{ + MOZ_ASSERT((r.code() & ~RegMask) == 0); + return r.code() << RSShift; +} + +uint32_t +js::jit::RT(Register r) +{ + MOZ_ASSERT((r.code() & ~RegMask) == 0); + return r.code() << RTShift; +} + +uint32_t +js::jit::RD(Register r) +{ + MOZ_ASSERT((r.code() & ~RegMask) == 0); + return r.code() << RDShift; +} + +uint32_t +js::jit::SA(uint32_t value) +{ + MOZ_ASSERT(value < 32); + return value << SAShift; +} + +Register +js::jit::toRS(Instruction& i) +{ + return Register::FromCode((i.encode() & RSMask ) >> RSShift); +} + +Register +js::jit::toRT(Instruction& i) +{ + return Register::FromCode((i.encode() & RTMask ) >> RTShift); +} + +Register +js::jit::toRD(Instruction& i) +{ + return Register::FromCode((i.encode() & RDMask ) >> RDShift); +} + +Register +js::jit::toR(Instruction& i) +{ + return Register::FromCode(i.encode() & RegMask); +} + +void +InstImm::extractImm16(BOffImm16* dest) +{ + *dest = BOffImm16(*this); +} + +void +AssemblerMIPSShared::finish() +{ + MOZ_ASSERT(!isFinished); + isFinished = true; +} + +uint32_t +AssemblerMIPSShared::actualOffset(uint32_t off_) const +{ + return off_; +} + +uint32_t +AssemblerMIPSShared::actualIndex(uint32_t idx_) const +{ + return idx_; +} + +uint8_t* +AssemblerMIPSShared::PatchableJumpAddress(JitCode* code, uint32_t pe_) +{ + return code->raw() + pe_; +} + +Assembler& +AssemblerMIPSShared::asAsm() +{ + return *static_cast(this); +} + +class RelocationIterator +{ + CompactBufferReader reader_; + // offset in bytes + uint32_t offset_; + + public: + RelocationIterator(CompactBufferReader& reader) + : reader_(reader) + { } + + bool read() { + if (!reader_.more()) + return false; + offset_ = reader_.readUnsigned(); + return true; + } + + uint32_t offset() const { + return offset_; + } +}; + +void +AssemblerMIPSShared::copyJumpRelocationTable(uint8_t* dest) +{ + if (jumpRelocations_.length()) + memcpy(dest, jumpRelocations_.buffer(), jumpRelocations_.length()); +} + +void +AssemblerMIPSShared::copyDataRelocationTable(uint8_t* dest) +{ + if (dataRelocations_.length()) + memcpy(dest, dataRelocations_.buffer(), dataRelocations_.length()); +} + +void +AssemblerMIPSShared::copyPreBarrierTable(uint8_t* dest) +{ + if (preBarriers_.length()) + memcpy(dest, preBarriers_.buffer(), preBarriers_.length()); +} + +void +AssemblerMIPSShared::processCodeLabels(uint8_t* rawCode) +{ + for (size_t i = 0; i < codeLabels_.length(); i++) { + CodeLabel label = codeLabels_[i]; + asAsm().Bind(rawCode, label.dest(), rawCode + actualOffset(label.src()->offset())); + } +} + +AssemblerMIPSShared::Condition +AssemblerMIPSShared::InvertCondition(Condition cond) +{ + switch (cond) { + case Equal: + return NotEqual; + case NotEqual: + return Equal; + case Zero: + return NonZero; + case NonZero: + return Zero; + case LessThan: + return GreaterThanOrEqual; + case LessThanOrEqual: + return GreaterThan; + case GreaterThan: + return LessThanOrEqual; + case GreaterThanOrEqual: + return LessThan; + case Above: + return BelowOrEqual; + case AboveOrEqual: + return Below; + case Below: + return AboveOrEqual; + case BelowOrEqual: + return Above; + case Signed: + return NotSigned; + case NotSigned: + return Signed; + default: + MOZ_CRASH("unexpected condition"); + } +} + +AssemblerMIPSShared::DoubleCondition +AssemblerMIPSShared::InvertCondition(DoubleCondition cond) +{ + switch (cond) { + case DoubleOrdered: + return DoubleUnordered; + case DoubleEqual: + return DoubleNotEqualOrUnordered; + case DoubleNotEqual: + return DoubleEqualOrUnordered; + case DoubleGreaterThan: + return DoubleLessThanOrEqualOrUnordered; + case DoubleGreaterThanOrEqual: + return DoubleLessThanOrUnordered; + case DoubleLessThan: + return DoubleGreaterThanOrEqualOrUnordered; + case DoubleLessThanOrEqual: + return DoubleGreaterThanOrUnordered; + case DoubleUnordered: + return DoubleOrdered; + case DoubleEqualOrUnordered: + return DoubleNotEqual; + case DoubleNotEqualOrUnordered: + return DoubleEqual; + case DoubleGreaterThanOrUnordered: + return DoubleLessThanOrEqual; + case DoubleGreaterThanOrEqualOrUnordered: + return DoubleLessThan; + case DoubleLessThanOrUnordered: + return DoubleGreaterThanOrEqual; + case DoubleLessThanOrEqualOrUnordered: + return DoubleGreaterThan; + default: + MOZ_CRASH("unexpected condition"); + } +} + +BOffImm16::BOffImm16(InstImm inst) + : data(inst.encode() & Imm16Mask) +{ +} + +bool +AssemblerMIPSShared::oom() const +{ + return AssemblerShared::oom() || + m_buffer.oom() || + jumpRelocations_.oom() || + dataRelocations_.oom() || + preBarriers_.oom(); +} + +void +AssemblerMIPSShared::addCodeLabel(CodeLabel label) +{ + propagateOOM(codeLabels_.append(label)); +} + +// Size of the instruction stream, in bytes. +size_t +AssemblerMIPSShared::size() const +{ + return m_buffer.size(); +} + +// Size of the relocation table, in bytes. +size_t +AssemblerMIPSShared::jumpRelocationTableBytes() const +{ + return jumpRelocations_.length(); +} + +size_t +AssemblerMIPSShared::dataRelocationTableBytes() const +{ + return dataRelocations_.length(); +} + +size_t +AssemblerMIPSShared::preBarrierTableBytes() const +{ + return preBarriers_.length(); +} + +// Size of the data table, in bytes. +size_t +AssemblerMIPSShared::bytesNeeded() const +{ + return size() + + jumpRelocationTableBytes() + + dataRelocationTableBytes() + + preBarrierTableBytes(); +} + +// write a blob of binary into the instruction stream +BufferOffset +AssemblerMIPSShared::writeInst(uint32_t x, uint32_t* dest) +{ + if (dest == nullptr) + return m_buffer.putInt(x); + + WriteInstStatic(x, dest); + return BufferOffset(); +} + +void +AssemblerMIPSShared::WriteInstStatic(uint32_t x, uint32_t* dest) +{ + MOZ_ASSERT(dest != nullptr); + *dest = x; +} + +BufferOffset +AssemblerMIPSShared::haltingAlign(int alignment) +{ + // TODO: Implement a proper halting align. + return nopAlign(alignment); +} + +BufferOffset +AssemblerMIPSShared::nopAlign(int alignment) +{ + BufferOffset ret; + MOZ_ASSERT(m_buffer.isAligned(4)); + if (alignment == 8) { + if (!m_buffer.isAligned(alignment)) { + BufferOffset tmp = as_nop(); + if (!ret.assigned()) + ret = tmp; + } + } else { + MOZ_ASSERT((alignment & (alignment - 1)) == 0); + while (size() & (alignment - 1)) { + BufferOffset tmp = as_nop(); + if (!ret.assigned()) + ret = tmp; + } + } + return ret; +} + +BufferOffset +AssemblerMIPSShared::as_nop() +{ + return writeInst(op_special | ff_sll); +} + +// Logical operations. +BufferOffset +AssemblerMIPSShared::as_and(Register rd, Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_and).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_or(Register rd, Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_or).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_xor(Register rd, Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_xor).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_nor(Register rd, Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_nor).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_andi(Register rd, Register rs, int32_t j) +{ + MOZ_ASSERT(Imm16::IsInUnsignedRange(j)); + return writeInst(InstImm(op_andi, rs, rd, Imm16(j)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_ori(Register rd, Register rs, int32_t j) +{ + MOZ_ASSERT(Imm16::IsInUnsignedRange(j)); + return writeInst(InstImm(op_ori, rs, rd, Imm16(j)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_xori(Register rd, Register rs, int32_t j) +{ + MOZ_ASSERT(Imm16::IsInUnsignedRange(j)); + return writeInst(InstImm(op_xori, rs, rd, Imm16(j)).encode()); +} + +// Branch and jump instructions +BufferOffset +AssemblerMIPSShared::as_bal(BOffImm16 off) +{ + BufferOffset bo = writeInst(InstImm(op_regimm, zero, rt_bgezal, off).encode()); + return bo; +} + +BufferOffset +AssemblerMIPSShared::as_b(BOffImm16 off) +{ + BufferOffset bo = writeInst(InstImm(op_beq, zero, zero, off).encode()); + return bo; +} + +InstImm +AssemblerMIPSShared::getBranchCode(JumpOrCall jumpOrCall) +{ + if (jumpOrCall == BranchIsCall) + return InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0)); + + return InstImm(op_beq, zero, zero, BOffImm16(0)); +} + +InstImm +AssemblerMIPSShared::getBranchCode(Register s, Register t, Condition c) +{ + MOZ_ASSERT(c == AssemblerMIPSShared::Equal || c == AssemblerMIPSShared::NotEqual); + return InstImm(c == AssemblerMIPSShared::Equal ? op_beq : op_bne, s, t, BOffImm16(0)); +} + +InstImm +AssemblerMIPSShared::getBranchCode(Register s, Condition c) +{ + switch (c) { + case AssemblerMIPSShared::Equal: + case AssemblerMIPSShared::Zero: + case AssemblerMIPSShared::BelowOrEqual: + return InstImm(op_beq, s, zero, BOffImm16(0)); + case AssemblerMIPSShared::NotEqual: + case AssemblerMIPSShared::NonZero: + case AssemblerMIPSShared::Above: + return InstImm(op_bne, s, zero, BOffImm16(0)); + case AssemblerMIPSShared::GreaterThan: + return InstImm(op_bgtz, s, zero, BOffImm16(0)); + case AssemblerMIPSShared::GreaterThanOrEqual: + case AssemblerMIPSShared::NotSigned: + return InstImm(op_regimm, s, rt_bgez, BOffImm16(0)); + case AssemblerMIPSShared::LessThan: + case AssemblerMIPSShared::Signed: + return InstImm(op_regimm, s, rt_bltz, BOffImm16(0)); + case AssemblerMIPSShared::LessThanOrEqual: + return InstImm(op_blez, s, zero, BOffImm16(0)); + default: + MOZ_CRASH("Condition not supported."); + } +} + +InstImm +AssemblerMIPSShared::getBranchCode(FloatTestKind testKind, FPConditionBit fcc) +{ + MOZ_ASSERT(!(fcc && FccMask)); + uint32_t rtField = ((testKind == TestForTrue ? 1 : 0) | (fcc << FccShift)) << RTShift; + + return InstImm(op_cop1, rs_bc1, rtField, BOffImm16(0)); +} + +BufferOffset +AssemblerMIPSShared::as_j(JOffImm26 off) +{ + BufferOffset bo = writeInst(InstJump(op_j, off).encode()); + return bo; +} +BufferOffset +AssemblerMIPSShared::as_jal(JOffImm26 off) +{ + BufferOffset bo = writeInst(InstJump(op_jal, off).encode()); + return bo; +} + +BufferOffset +AssemblerMIPSShared::as_jr(Register rs) +{ + BufferOffset bo = writeInst(InstReg(op_special, rs, zero, zero, ff_jr).encode()); + return bo; +} +BufferOffset +AssemblerMIPSShared::as_jalr(Register rs) +{ + BufferOffset bo = writeInst(InstReg(op_special, rs, zero, ra, ff_jalr).encode()); + return bo; +} + + +// Arithmetic instructions +BufferOffset +AssemblerMIPSShared::as_addu(Register rd, Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_addu).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_addiu(Register rd, Register rs, int32_t j) +{ + MOZ_ASSERT(Imm16::IsInSignedRange(j)); + return writeInst(InstImm(op_addiu, rs, rd, Imm16(j)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_subu(Register rd, Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_subu).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_mult(Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, ff_mult).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_multu(Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, ff_multu).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_div(Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, ff_div).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_divu(Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, ff_divu).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_mul(Register rd, Register rs, Register rt) +{ + return writeInst(InstReg(op_special2, rs, rt, rd, ff_mul).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_lui(Register rd, int32_t j) +{ + MOZ_ASSERT(Imm16::IsInUnsignedRange(j)); + return writeInst(InstImm(op_lui, zero, rd, Imm16(j)).encode()); +} + +// Shift instructions +BufferOffset +AssemblerMIPSShared::as_sll(Register rd, Register rt, uint16_t sa) +{ + MOZ_ASSERT(sa < 32); + return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sll).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_sllv(Register rd, Register rt, Register rs) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_sllv).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_srl(Register rd, Register rt, uint16_t sa) +{ + MOZ_ASSERT(sa < 32); + return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_srl).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_srlv(Register rd, Register rt, Register rs) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_srlv).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_sra(Register rd, Register rt, uint16_t sa) +{ + MOZ_ASSERT(sa < 32); + return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sra).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_srav(Register rd, Register rt, Register rs) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_srav).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_rotr(Register rd, Register rt, uint16_t sa) +{ + MOZ_ASSERT(sa < 32); + return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_srl).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_rotrv(Register rd, Register rt, Register rs) +{ + return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_srlv).encode()); +} + +// Load and store instructions +BufferOffset +AssemblerMIPSShared::as_lb(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_lb, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_lbu(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_lbu, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_lh(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_lh, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_lhu(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_lhu, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_lw(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_lw, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_lwl(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_lwl, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_lwr(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_lwr, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_sb(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_sb, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_sh(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_sh, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_sw(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_sw, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_swl(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_swl, rs, rd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_swr(Register rd, Register rs, int16_t off) +{ + return writeInst(InstImm(op_swr, rs, rd, Imm16(off)).encode()); +} + +// Move from HI/LO register. +BufferOffset +AssemblerMIPSShared::as_mfhi(Register rd) +{ + return writeInst(InstReg(op_special, rd, ff_mfhi).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_mflo(Register rd) +{ + return writeInst(InstReg(op_special, rd, ff_mflo).encode()); +} + +// Set on less than. +BufferOffset +AssemblerMIPSShared::as_slt(Register rd, Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_slt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_sltu(Register rd, Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_sltu).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_slti(Register rd, Register rs, int32_t j) +{ + MOZ_ASSERT(Imm16::IsInSignedRange(j)); + return writeInst(InstImm(op_slti, rs, rd, Imm16(j)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_sltiu(Register rd, Register rs, uint32_t j) +{ + MOZ_ASSERT(Imm16::IsInUnsignedRange(j)); + return writeInst(InstImm(op_sltiu, rs, rd, Imm16(j)).encode()); +} + +// Conditional move. +BufferOffset +AssemblerMIPSShared::as_movz(Register rd, Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_movz).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_movn(Register rd, Register rs, Register rt) +{ + return writeInst(InstReg(op_special, rs, rt, rd, ff_movn).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_movt(Register rd, Register rs, uint16_t cc) +{ + Register rt; + rt = Register::FromCode((cc & 0x7) << 2 | 1); + return writeInst(InstReg(op_special, rs, rt, rd, ff_movci).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_movf(Register rd, Register rs, uint16_t cc) +{ + Register rt; + rt = Register::FromCode((cc & 0x7) << 2 | 0); + return writeInst(InstReg(op_special, rs, rt, rd, ff_movci).encode()); +} + +// Bit twiddling. +BufferOffset +AssemblerMIPSShared::as_clz(Register rd, Register rs) +{ + return writeInst(InstReg(op_special2, rs, rd, rd, ff_clz).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_ins(Register rt, Register rs, uint16_t pos, uint16_t size) +{ + MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 32); + Register rd; + rd = Register::FromCode(pos + size - 1); + return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ins).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_ext(Register rt, Register rs, uint16_t pos, uint16_t size) +{ + MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 32); + Register rd; + rd = Register::FromCode(size - 1); + return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ext).encode()); +} + +// FP instructions +BufferOffset +AssemblerMIPSShared::as_ld(FloatRegister fd, Register base, int32_t off) +{ + MOZ_ASSERT(Imm16::IsInSignedRange(off)); + return writeInst(InstImm(op_ldc1, base, fd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_sd(FloatRegister fd, Register base, int32_t off) +{ + MOZ_ASSERT(Imm16::IsInSignedRange(off)); + return writeInst(InstImm(op_sdc1, base, fd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_ls(FloatRegister fd, Register base, int32_t off) +{ + MOZ_ASSERT(Imm16::IsInSignedRange(off)); + return writeInst(InstImm(op_lwc1, base, fd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_ss(FloatRegister fd, Register base, int32_t off) +{ + MOZ_ASSERT(Imm16::IsInSignedRange(off)); + return writeInst(InstImm(op_swc1, base, fd, Imm16(off)).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_movs(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_mov_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_movd(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_mov_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_mtc1(Register rt, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_mtc1, rt, fs).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_mfc1(Register rt, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_mfc1, rt, fs).encode()); +} + +// FP convert instructions +BufferOffset +AssemblerMIPSShared::as_ceilws(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_ceil_w_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_floorws(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_floor_w_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_roundws(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_round_w_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_truncws(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_trunc_w_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_ceilwd(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_ceil_w_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_floorwd(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_floor_w_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_roundwd(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_round_w_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_truncwd(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_trunc_w_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_cvtds(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_d_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_cvtdw(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_w, zero, fs, fd, ff_cvt_d_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_cvtsd(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_cvt_s_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_cvtsw(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_w, zero, fs, fd, ff_cvt_s_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_cvtwd(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_cvt_w_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_cvtws(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_w_fmt).encode()); +} + +// FP arithmetic instructions +BufferOffset +AssemblerMIPSShared::as_adds(FloatRegister fd, FloatRegister fs, FloatRegister ft) +{ + return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_add_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_addd(FloatRegister fd, FloatRegister fs, FloatRegister ft) +{ + return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_add_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_subs(FloatRegister fd, FloatRegister fs, FloatRegister ft) +{ + return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_sub_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_subd(FloatRegister fd, FloatRegister fs, FloatRegister ft) +{ + return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_sub_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_abss(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_abs_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_absd(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_abs_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_negs(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_neg_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_negd(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_neg_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_muls(FloatRegister fd, FloatRegister fs, FloatRegister ft) +{ + return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_mul_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_muld(FloatRegister fd, FloatRegister fs, FloatRegister ft) +{ + return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_mul_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_divs(FloatRegister fd, FloatRegister fs, FloatRegister ft) +{ + return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_div_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_divd(FloatRegister fd, FloatRegister fs, FloatRegister ft) +{ + return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_div_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_sqrts(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_sqrt_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_sqrtd(FloatRegister fd, FloatRegister fs) +{ + return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_sqrt_fmt).encode()); +} + +// FP compare instructions +BufferOffset +AssemblerMIPSShared::as_cf(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) +{ + RSField rs = fmt == DoubleFloat ? rs_d : rs_s; + return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_f_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_cun(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) +{ + RSField rs = fmt == DoubleFloat ? rs_d : rs_s; + return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_un_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_ceq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) +{ + RSField rs = fmt == DoubleFloat ? rs_d : rs_s; + return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_eq_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_cueq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) +{ + RSField rs = fmt == DoubleFloat ? rs_d : rs_s; + return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ueq_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_colt(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) +{ + RSField rs = fmt == DoubleFloat ? rs_d : rs_s; + return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_olt_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_cult(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) +{ + RSField rs = fmt == DoubleFloat ? rs_d : rs_s; + return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ult_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_cole(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) +{ + RSField rs = fmt == DoubleFloat ? rs_d : rs_s; + return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ole_fmt).encode()); +} + +BufferOffset +AssemblerMIPSShared::as_cule(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) +{ + RSField rs = fmt == DoubleFloat ? rs_d : rs_s; + return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ule_fmt).encode()); +} + + +void +AssemblerMIPSShared::bind(Label* label, BufferOffset boff) +{ + // If our caller didn't give us an explicit target to bind to + // then we want to bind to the location of the next instruction + BufferOffset dest = boff.assigned() ? boff : nextOffset(); + if (label->used()) { + int32_t next; + + // A used label holds a link to branch that uses it. + BufferOffset b(label); + do { + Instruction* inst = editSrc(b); + + // Second word holds a pointer to the next branch in label's chain. + next = inst[1].encode(); + asAsm().bind(reinterpret_cast(inst), b.getOffset(), dest.getOffset()); + + b = BufferOffset(next); + } while (next != LabelBase::INVALID_OFFSET); + } + label->bind(dest.getOffset()); +} + +void +AssemblerMIPSShared::retarget(Label* label, Label* target) +{ + if (label->used()) { + if (target->bound()) { + bind(label, BufferOffset(target)); + } else if (target->used()) { + // The target is not bound but used. Prepend label's branch list + // onto target's. + int32_t next; + BufferOffset labelBranchOffset(label); + + // Find the head of the use chain for label. + do { + Instruction* inst = editSrc(labelBranchOffset); + + // Second word holds a pointer to the next branch in chain. + next = inst[1].encode(); + labelBranchOffset = BufferOffset(next); + } while (next != LabelBase::INVALID_OFFSET); + + // Then patch the head of label's use chain to the tail of + // target's use chain, prepending the entire use chain of target. + Instruction* inst = editSrc(labelBranchOffset); + int32_t prev = target->use(label->offset()); + inst[1].setData(prev); + } else { + // The target is unbound and unused. We can just take the head of + // the list hanging off of label, and dump that into target. + DebugOnly prev = target->use(label->offset()); + MOZ_ASSERT((int32_t)prev == Label::INVALID_OFFSET); + } + } + label->reset(); +} + +void dbg_break() {} +void +AssemblerMIPSShared::as_break(uint32_t code) +{ + MOZ_ASSERT(code <= MAX_BREAK_CODE); + writeInst(op_special | code << FunctionBits | ff_break); +} + +void +AssemblerMIPSShared::PatchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue, ImmPtr expectedValue) +{ + Assembler::PatchDataWithValueCheck(label, PatchedImmPtr(newValue.value), + PatchedImmPtr(expectedValue.value)); +} + +// This just stomps over memory with 32 bits of raw data. Its purpose is to +// overwrite the call of JITed code with 32 bits worth of an offset. This will +// is only meant to function on code that has been invalidated, so it should +// be totally safe. Since that instruction will never be executed again, a +// ICache flush should not be necessary +void +AssemblerMIPSShared::PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm) +{ + // Raw is going to be the return address. + uint32_t* raw = (uint32_t*)label.raw(); + // Overwrite the 4 bytes before the return address, which will + // end up being the call instruction. + *(raw - 1) = imm.value; +} + +uint8_t* +AssemblerMIPSShared::NextInstruction(uint8_t* inst_, uint32_t* count) +{ + Instruction* inst = reinterpret_cast(inst_); + if (count != nullptr) + *count += sizeof(Instruction); + return reinterpret_cast(inst->next()); +} + +// Since there are no pools in MIPS implementation, this should be simple. +Instruction* +Instruction::next() +{ + return this + 1; +} + +InstImm AssemblerMIPSShared::invertBranch(InstImm branch, BOffImm16 skipOffset) +{ + uint32_t rt = 0; + Opcode op = (Opcode) (branch.extractOpcode() << OpcodeShift); + switch(op) { + case op_beq: + branch.setBOffImm16(skipOffset); + branch.setOpcode(op_bne); + return branch; + case op_bne: + branch.setBOffImm16(skipOffset); + branch.setOpcode(op_beq); + return branch; + case op_bgtz: + branch.setBOffImm16(skipOffset); + branch.setOpcode(op_blez); + return branch; + case op_blez: + branch.setBOffImm16(skipOffset); + branch.setOpcode(op_bgtz); + return branch; + case op_regimm: + branch.setBOffImm16(skipOffset); + rt = branch.extractRT(); + if (rt == (rt_bltz >> RTShift)) { + branch.setRT(rt_bgez); + return branch; + } + if (rt == (rt_bgez >> RTShift)) { + branch.setRT(rt_bltz); + return branch; + } + + MOZ_CRASH("Error creating long branch."); + + case op_cop1: + MOZ_ASSERT(branch.extractRS() == rs_bc1 >> RSShift); + + branch.setBOffImm16(skipOffset); + rt = branch.extractRT(); + if (rt & 0x1) + branch.setRT((RTField) ((rt & ~0x1) << RTShift)); + else + branch.setRT((RTField) ((rt | 0x1) << RTShift)); + return branch; + default: + MOZ_CRASH("Error creating long branch."); + } +} + +void +AssemblerMIPSShared::ToggleToJmp(CodeLocationLabel inst_) +{ + InstImm * inst = (InstImm*)inst_.raw(); + + MOZ_ASSERT(inst->extractOpcode() == ((uint32_t)op_andi >> OpcodeShift)); + // We converted beq to andi, so now we restore it. + inst->setOpcode(op_beq); + + AutoFlushICache::flush(uintptr_t(inst), 4); +} + +void +AssemblerMIPSShared::ToggleToCmp(CodeLocationLabel inst_) +{ + InstImm * inst = (InstImm*)inst_.raw(); + + // toggledJump is allways used for short jumps. + MOZ_ASSERT(inst->extractOpcode() == ((uint32_t)op_beq >> OpcodeShift)); + // Replace "beq $zero, $zero, offset" with "andi $zero, $zero, offset" + inst->setOpcode(op_andi); + + AutoFlushICache::flush(uintptr_t(inst), 4); +} + diff --git a/js/src/jit/mips-shared/Assembler-mips-shared.h b/js/src/jit/mips-shared/Assembler-mips-shared.h new file mode 100644 index 000000000000..17b7c8de0c38 --- /dev/null +++ b/js/src/jit/mips-shared/Assembler-mips-shared.h @@ -0,0 +1,1276 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_mips_shared_Assembler_mips_shared_h +#define jit_mips_shared_Assembler_mips_shared_h + +#include "mozilla/ArrayUtils.h" +#include "mozilla/Attributes.h" +#include "mozilla/MathAlgorithms.h" + +#include "jit/CompactBuffer.h" +#include "jit/IonCode.h" +#include "jit/JitCompartment.h" +#include "jit/JitSpewer.h" +#include "jit/mips-shared/Architecture-mips-shared.h" +#include "jit/shared/Assembler-shared.h" +#include "jit/shared/IonAssemblerBuffer.h" + +namespace js { +namespace jit { + +static MOZ_CONSTEXPR_VAR Register zero = { Registers::zero }; +static MOZ_CONSTEXPR_VAR Register at = { Registers::at }; +static MOZ_CONSTEXPR_VAR Register v0 = { Registers::v0 }; +static MOZ_CONSTEXPR_VAR Register v1 = { Registers::v1 }; +static MOZ_CONSTEXPR_VAR Register a0 = { Registers::a0 }; +static MOZ_CONSTEXPR_VAR Register a1 = { Registers::a1 }; +static MOZ_CONSTEXPR_VAR Register a2 = { Registers::a2 }; +static MOZ_CONSTEXPR_VAR Register a3 = { Registers::a3 }; +static MOZ_CONSTEXPR_VAR Register t0 = { Registers::t0 }; +static MOZ_CONSTEXPR_VAR Register t1 = { Registers::t1 }; +static MOZ_CONSTEXPR_VAR Register t2 = { Registers::t2 }; +static MOZ_CONSTEXPR_VAR Register t3 = { Registers::t3 }; +static MOZ_CONSTEXPR_VAR Register t4 = { Registers::t4 }; +static MOZ_CONSTEXPR_VAR Register t5 = { Registers::t5 }; +static MOZ_CONSTEXPR_VAR Register t6 = { Registers::t6 }; +static MOZ_CONSTEXPR_VAR Register t7 = { Registers::t7 }; +static MOZ_CONSTEXPR_VAR Register s0 = { Registers::s0 }; +static MOZ_CONSTEXPR_VAR Register s1 = { Registers::s1 }; +static MOZ_CONSTEXPR_VAR Register s2 = { Registers::s2 }; +static MOZ_CONSTEXPR_VAR Register s3 = { Registers::s3 }; +static MOZ_CONSTEXPR_VAR Register s4 = { Registers::s4 }; +static MOZ_CONSTEXPR_VAR Register s5 = { Registers::s5 }; +static MOZ_CONSTEXPR_VAR Register s6 = { Registers::s6 }; +static MOZ_CONSTEXPR_VAR Register s7 = { Registers::s7 }; +static MOZ_CONSTEXPR_VAR Register t8 = { Registers::t8 }; +static MOZ_CONSTEXPR_VAR Register t9 = { Registers::t9 }; +static MOZ_CONSTEXPR_VAR Register k0 = { Registers::k0 }; +static MOZ_CONSTEXPR_VAR Register k1 = { Registers::k1 }; +static MOZ_CONSTEXPR_VAR Register gp = { Registers::gp }; +static MOZ_CONSTEXPR_VAR Register sp = { Registers::sp }; +static MOZ_CONSTEXPR_VAR Register fp = { Registers::fp }; +static MOZ_CONSTEXPR_VAR Register ra = { Registers::ra }; + +static MOZ_CONSTEXPR_VAR Register ScratchRegister = at; +static MOZ_CONSTEXPR_VAR Register SecondScratchReg = t8; + +// Helper classes for ScratchRegister usage. Asserts that only one piece +// of code thinks it has exclusive ownership of each scratch register. +struct ScratchRegisterScope : public AutoRegisterScope +{ + explicit ScratchRegisterScope(MacroAssembler& masm) + : AutoRegisterScope(masm, ScratchRegister) + { } +}; +struct SecondScratchRegisterScope : public AutoRegisterScope +{ + explicit SecondScratchRegisterScope(MacroAssembler& masm) + : AutoRegisterScope(masm, SecondScratchReg) + { } +}; + +// Use arg reg from EnterJIT function as OsrFrameReg. +static MOZ_CONSTEXPR_VAR Register OsrFrameReg = a3; +static MOZ_CONSTEXPR_VAR Register ArgumentsRectifierReg = s3; +static MOZ_CONSTEXPR_VAR Register CallTempReg0 = t0; +static MOZ_CONSTEXPR_VAR Register CallTempReg1 = t1; +static MOZ_CONSTEXPR_VAR Register CallTempReg2 = t2; +static MOZ_CONSTEXPR_VAR Register CallTempReg3 = t3; + +static MOZ_CONSTEXPR_VAR Register IntArgReg0 = a0; +static MOZ_CONSTEXPR_VAR Register IntArgReg1 = a1; +static MOZ_CONSTEXPR_VAR Register IntArgReg2 = a2; +static MOZ_CONSTEXPR_VAR Register IntArgReg3 = a3; +static MOZ_CONSTEXPR_VAR Register GlobalReg = s6; // used by Odin +static MOZ_CONSTEXPR_VAR Register HeapReg = s7; // used by Odin +static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = CALL_TEMP_NON_ARG_REGS; +static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); + +static MOZ_CONSTEXPR_VAR Register PreBarrierReg = a1; + +static MOZ_CONSTEXPR_VAR Register InvalidReg = { Registers::invalid_reg }; +static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg; + +static MOZ_CONSTEXPR_VAR Register StackPointer = sp; +static MOZ_CONSTEXPR_VAR Register FramePointer = InvalidReg; +static MOZ_CONSTEXPR_VAR Register ReturnReg = v0; +static MOZ_CONSTEXPR_VAR FloatRegister ReturnInt32x4Reg = InvalidFloatReg; +static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32x4Reg = InvalidFloatReg; +static MOZ_CONSTEXPR_VAR FloatRegister ScratchSimdReg = InvalidFloatReg; + +// A bias applied to the GlobalReg to allow the use of instructions with small +// negative immediate offsets which doubles the range of global data that can be +// accessed with a single instruction. +static const int32_t AsmJSGlobalRegBias = 32768; + +// Registers used in the GenerateFFIIonExit Enable Activation block. +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = t0; +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = a0; +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE1 = a1; +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE2 = a2; +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE3 = a3; + +// Registers used in the GenerateFFIIonExit Disable Activation block. +// None of these may be the second scratch register (t8). +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = a0; +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = a1; +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = t0; + +static MOZ_CONSTEXPR_VAR uint32_t CodeAlignment = 4; + +// This boolean indicates whether we support SIMD instructions flavoured for +// this architecture or not. Rather than a method in the LIRGenerator, it is +// here such that it is accessible from the entire codebase. Once full support +// for SIMD is reached on all tier-1 platforms, this constant can be deleted. +static MOZ_CONSTEXPR_VAR bool SupportsSimd = false; + +// MIPS instruction types +// +---------------------------------------------------------------+ +// | 6 | 5 | 5 | 5 | 5 | 6 | +// +---------------------------------------------------------------+ +// Register type | Opcode | Rs | Rt | Rd | Sa | Function | +// +---------------------------------------------------------------+ +// | 6 | 5 | 5 | 16 | +// +---------------------------------------------------------------+ +// Immediate type | Opcode | Rs | Rt | 2's complement constant | +// +---------------------------------------------------------------+ +// | 6 | 26 | +// +---------------------------------------------------------------+ +// Jump type | Opcode | jump_target | +// +---------------------------------------------------------------+ +// 31 bit bit 0 + +// MIPS instruction encoding constants. +static const uint32_t OpcodeShift = 26; +static const uint32_t OpcodeBits = 6; +static const uint32_t RSShift = 21; +static const uint32_t RSBits = 5; +static const uint32_t RTShift = 16; +static const uint32_t RTBits = 5; +static const uint32_t RDShift = 11; +static const uint32_t RDBits = 5; +static const uint32_t SAShift = 6; +static const uint32_t SABits = 5; +static const uint32_t FunctionShift = 0; +static const uint32_t FunctionBits = 6; +static const uint32_t Imm16Shift = 0; +static const uint32_t Imm16Bits = 16; +static const uint32_t Imm26Shift = 0; +static const uint32_t Imm26Bits = 26; +static const uint32_t Imm28Shift = 0; +static const uint32_t Imm28Bits = 28; +static const uint32_t ImmFieldShift = 2; +static const uint32_t FRBits = 5; +static const uint32_t FRShift = 21; +static const uint32_t FSShift = 11; +static const uint32_t FSBits = 5; +static const uint32_t FTShift = 16; +static const uint32_t FTBits = 5; +static const uint32_t FDShift = 6; +static const uint32_t FDBits = 5; +static const uint32_t FCccShift = 8; +static const uint32_t FCccBits = 3; +static const uint32_t FBccShift = 18; +static const uint32_t FBccBits = 3; +static const uint32_t FBtrueShift = 16; +static const uint32_t FBtrueBits = 1; +static const uint32_t FccMask = 0x7; +static const uint32_t FccShift = 2; + + +// MIPS instruction field bit masks. +static const uint32_t OpcodeMask = ((1 << OpcodeBits) - 1) << OpcodeShift; +static const uint32_t Imm16Mask = ((1 << Imm16Bits) - 1) << Imm16Shift; +static const uint32_t Imm26Mask = ((1 << Imm26Bits) - 1) << Imm26Shift; +static const uint32_t Imm28Mask = ((1 << Imm28Bits) - 1) << Imm28Shift; +static const uint32_t RSMask = ((1 << RSBits) - 1) << RSShift; +static const uint32_t RTMask = ((1 << RTBits) - 1) << RTShift; +static const uint32_t RDMask = ((1 << RDBits) - 1) << RDShift; +static const uint32_t SAMask = ((1 << SABits) - 1) << SAShift; +static const uint32_t FunctionMask = ((1 << FunctionBits) - 1) << FunctionShift; +static const uint32_t RegMask = Registers::Total - 1; + +static const uint32_t BREAK_STACK_UNALIGNED = 1; +static const uint32_t MAX_BREAK_CODE = 1024 - 1; + +class Instruction; +class InstReg; +class InstImm; +class InstJump; + +uint32_t RS(Register r); +uint32_t RT(Register r); +uint32_t RT(uint32_t regCode); +uint32_t RT(FloatRegister r); +uint32_t RD(Register r); +uint32_t RD(FloatRegister r); +uint32_t RD(uint32_t regCode); +uint32_t SA(uint32_t value); +uint32_t SA(FloatRegister r); + +Register toRS (Instruction& i); +Register toRT (Instruction& i); +Register toRD (Instruction& i); +Register toR (Instruction& i); + +// MIPS enums for instruction fields +enum Opcode { + op_special = 0 << OpcodeShift, + op_regimm = 1 << OpcodeShift, + + op_j = 2 << OpcodeShift, + op_jal = 3 << OpcodeShift, + op_beq = 4 << OpcodeShift, + op_bne = 5 << OpcodeShift, + op_blez = 6 << OpcodeShift, + op_bgtz = 7 << OpcodeShift, + + op_addi = 8 << OpcodeShift, + op_addiu = 9 << OpcodeShift, + op_slti = 10 << OpcodeShift, + op_sltiu = 11 << OpcodeShift, + op_andi = 12 << OpcodeShift, + op_ori = 13 << OpcodeShift, + op_xori = 14 << OpcodeShift, + op_lui = 15 << OpcodeShift, + + op_cop1 = 17 << OpcodeShift, + op_cop1x = 19 << OpcodeShift, + + op_beql = 20 << OpcodeShift, + op_bnel = 21 << OpcodeShift, + op_blezl = 22 << OpcodeShift, + op_bgtzl = 23 << OpcodeShift, + + op_special2 = 28 << OpcodeShift, + op_special3 = 31 << OpcodeShift, + + op_lb = 32 << OpcodeShift, + op_lh = 33 << OpcodeShift, + op_lwl = 34 << OpcodeShift, + op_lw = 35 << OpcodeShift, + op_lbu = 36 << OpcodeShift, + op_lhu = 37 << OpcodeShift, + op_lwr = 38 << OpcodeShift, + op_sb = 40 << OpcodeShift, + op_sh = 41 << OpcodeShift, + op_swl = 42 << OpcodeShift, + op_sw = 43 << OpcodeShift, + op_swr = 46 << OpcodeShift, + + op_lwc1 = 49 << OpcodeShift, + op_ldc1 = 53 << OpcodeShift, + + op_swc1 = 57 << OpcodeShift, + op_sdc1 = 61 << OpcodeShift +}; + +enum RSField { + rs_zero = 0 << RSShift, + // cop1 encoding of RS field. + rs_mfc1 = 0 << RSShift, + rs_one = 1 << RSShift, + rs_cfc1 = 2 << RSShift, + rs_mfhc1 = 3 << RSShift, + rs_mtc1 = 4 << RSShift, + rs_ctc1 = 6 << RSShift, + rs_mthc1 = 7 << RSShift, + rs_bc1 = 8 << RSShift, + rs_s = 16 << RSShift, + rs_d = 17 << RSShift, + rs_w = 20 << RSShift, + rs_l = 21 << RSShift, + rs_ps = 22 << RSShift +}; + +enum RTField { + rt_zero = 0 << RTShift, + // regimm encoding of RT field. + rt_bltz = 0 << RTShift, + rt_bgez = 1 << RTShift, + rt_bltzal = 16 << RTShift, + rt_bgezal = 17 << RTShift +}; + +enum FunctionField { + // special encoding of function field. + ff_sll = 0, + ff_movci = 1, + ff_srl = 2, + ff_sra = 3, + ff_sllv = 4, + ff_srlv = 6, + ff_srav = 7, + + ff_jr = 8, + ff_jalr = 9, + ff_movz = 10, + ff_movn = 11, + ff_break = 13, + + ff_mfhi = 16, + ff_mflo = 18, + + ff_mult = 24, + ff_multu = 25, + ff_div = 26, + ff_divu = 27, + + ff_add = 32, + ff_addu = 33, + ff_sub = 34, + ff_subu = 35, + ff_and = 36, + ff_or = 37, + ff_xor = 38, + ff_nor = 39, + + ff_slt = 42, + ff_sltu = 43, + + ff_tge = 48, + ff_tgeu = 49, + ff_tlt = 50, + ff_tltu = 51, + ff_teq = 52, + ff_tne = 54, + + // special2 encoding of function field. + ff_mul = 2, + ff_clz = 32, + ff_clo = 33, + + // special3 encoding of function field. + ff_ext = 0, + ff_ins = 4, + + // cop1 encoding of function field. + ff_add_fmt = 0, + ff_sub_fmt = 1, + ff_mul_fmt = 2, + ff_div_fmt = 3, + ff_sqrt_fmt = 4, + ff_abs_fmt = 5, + ff_mov_fmt = 6, + ff_neg_fmt = 7, + + ff_round_l_fmt = 8, + ff_trunc_l_fmt = 9, + ff_ceil_l_fmt = 10, + ff_floor_l_fmt = 11, + + ff_round_w_fmt = 12, + ff_trunc_w_fmt = 13, + ff_ceil_w_fmt = 14, + ff_floor_w_fmt = 15, + + ff_cvt_s_fmt = 32, + ff_cvt_d_fmt = 33, + ff_cvt_w_fmt = 36, + ff_cvt_l_fmt = 37, + ff_cvt_ps_s = 38, + + ff_c_f_fmt = 48, + ff_c_un_fmt = 49, + ff_c_eq_fmt = 50, + ff_c_ueq_fmt = 51, + ff_c_olt_fmt = 52, + ff_c_ult_fmt = 53, + ff_c_ole_fmt = 54, + ff_c_ule_fmt = 55, + + ff_madd_s = 32, + ff_madd_d = 33, + + ff_null = 0 +}; + +class Operand; + +// A BOffImm16 is a 16 bit immediate that is used for branches. +class BOffImm16 +{ + uint32_t data; + + public: + uint32_t encode() { + MOZ_ASSERT(!isInvalid()); + return data; + } + int32_t decode() { + MOZ_ASSERT(!isInvalid()); + return (int32_t(data << 18) >> 16) + 4; + } + + explicit BOffImm16(int offset) + : data ((offset - 4) >> 2 & Imm16Mask) + { + MOZ_ASSERT((offset & 0x3) == 0); + MOZ_ASSERT(IsInRange(offset)); + } + static bool IsInRange(int offset) { + if ((offset - 4) < (INT16_MIN << 2)) + return false; + if ((offset - 4) > (INT16_MAX << 2)) + return false; + return true; + } + static const uint32_t INVALID = 0x00020000; + BOffImm16() + : data(INVALID) + { } + + bool isInvalid() { + return data == INVALID; + } + Instruction* getDest(Instruction* src); + + BOffImm16(InstImm inst); +}; + +// A JOffImm26 is a 26 bit immediate that is used for unconditional jumps. +class JOffImm26 +{ + uint32_t data; + + public: + uint32_t encode() { + MOZ_ASSERT(!isInvalid()); + return data; + } + int32_t decode() { + MOZ_ASSERT(!isInvalid()); + return (int32_t(data << 8) >> 6) + 4; + } + + explicit JOffImm26(int offset) + : data ((offset - 4) >> 2 & Imm26Mask) + { + MOZ_ASSERT((offset & 0x3) == 0); + MOZ_ASSERT(IsInRange(offset)); + } + static bool IsInRange(int offset) { + if ((offset - 4) < -536870912) + return false; + if ((offset - 4) > 536870908) + return false; + return true; + } + static const uint32_t INVALID = 0x20000000; + JOffImm26() + : data(INVALID) + { } + + bool isInvalid() { + return data == INVALID; + } + Instruction* getDest(Instruction* src); + +}; + +class Imm16 +{ + uint16_t value; + + public: + Imm16(); + Imm16(uint32_t imm) + : value(imm) + { } + uint32_t encode() { + return value; + } + int32_t decodeSigned() { + return value; + } + uint32_t decodeUnsigned() { + return value; + } + static bool IsInSignedRange(int32_t imm) { + return imm >= INT16_MIN && imm <= INT16_MAX; + } + static bool IsInUnsignedRange(uint32_t imm) { + return imm <= UINT16_MAX ; + } + static Imm16 Lower (Imm32 imm) { + return Imm16(imm.value & 0xffff); + } + static Imm16 Upper (Imm32 imm) { + return Imm16((imm.value >> 16) & 0xffff); + } +}; + +class Operand +{ + public: + enum Tag { + REG, + FREG, + MEM + }; + + private: + Tag tag : 3; + uint32_t reg : 5; + int32_t offset; + + public: + Operand (Register reg_) + : tag(REG), reg(reg_.code()) + { } + + Operand (FloatRegister freg) + : tag(FREG), reg(freg.code()) + { } + + Operand (Register base, Imm32 off) + : tag(MEM), reg(base.code()), offset(off.value) + { } + + Operand (Register base, int32_t off) + : tag(MEM), reg(base.code()), offset(off) + { } + + Operand (const Address& addr) + : tag(MEM), reg(addr.base.code()), offset(addr.offset) + { } + + Tag getTag() const { + return tag; + } + + Register toReg() const { + MOZ_ASSERT(tag == REG); + return Register::FromCode(reg); + } + + FloatRegister toFReg() const { + MOZ_ASSERT(tag == FREG); + return FloatRegister::FromCode(reg); + } + + void toAddr(Register* r, Imm32* dest) const { + MOZ_ASSERT(tag == MEM); + *r = Register::FromCode(reg); + *dest = Imm32(offset); + } + Address toAddress() const { + MOZ_ASSERT(tag == MEM); + return Address(Register::FromCode(reg), offset); + } + int32_t disp() const { + MOZ_ASSERT(tag == MEM); + return offset; + } + + int32_t base() const { + MOZ_ASSERT(tag == MEM); + return reg; + } + Register baseReg() const { + MOZ_ASSERT(tag == MEM); + return Register::FromCode(reg); + } +}; + +void +PatchJump(CodeLocationJump& jump_, CodeLocationLabel label, + ReprotectCode reprotect = DontReprotect); + +void +PatchBackedge(CodeLocationJump& jump_, CodeLocationLabel label, JitRuntime::BackedgeTarget target); + +typedef js::jit::AssemblerBuffer<1024, Instruction> MIPSBuffer; + +class MIPSBufferWithExecutableCopy : public MIPSBuffer +{ + public: + void executableCopy(uint8_t* buffer) { + if (this->oom()) + return; + + for (Slice* cur = head; cur != nullptr; cur = cur->getNext()) { + memcpy(buffer, &cur->instructions, cur->length()); + buffer += cur->length(); + } + } +}; + +class Assembler; + +class AssemblerMIPSShared : public AssemblerShared +{ + public: + + enum Condition { + Equal, + NotEqual, + Above, + AboveOrEqual, + Below, + BelowOrEqual, + GreaterThan, + GreaterThanOrEqual, + LessThan, + LessThanOrEqual, + Overflow, + Signed, + NotSigned, + Zero, + NonZero, + Always, + }; + + enum DoubleCondition { + // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. + DoubleOrdered, + DoubleEqual, + DoubleNotEqual, + DoubleGreaterThan, + DoubleGreaterThanOrEqual, + DoubleLessThan, + DoubleLessThanOrEqual, + // If either operand is NaN, these conditions always evaluate to true. + DoubleUnordered, + DoubleEqualOrUnordered, + DoubleNotEqualOrUnordered, + DoubleGreaterThanOrUnordered, + DoubleGreaterThanOrEqualOrUnordered, + DoubleLessThanOrUnordered, + DoubleLessThanOrEqualOrUnordered + }; + + enum FPConditionBit { + FCC0 = 0, + FCC1, + FCC2, + FCC3, + FCC4, + FCC5, + FCC6, + FCC7 + }; + + enum FloatFormat { + SingleFloat, + DoubleFloat + }; + + enum JumpOrCall { + BranchIsJump, + BranchIsCall + }; + + enum FloatTestKind { + TestForTrue, + TestForFalse + }; + + // :( this should be protected, but since CodeGenerator + // wants to use it, It needs to go out here :( + + BufferOffset nextOffset() { + return m_buffer.nextOffset(); + } + + protected: + Instruction * editSrc (BufferOffset bo) { + return m_buffer.getInst(bo); + } + public: + uint32_t actualOffset(uint32_t) const; + uint32_t actualIndex(uint32_t) const; + static uint8_t* PatchableJumpAddress(JitCode* code, uint32_t index); + protected: + Assembler& asAsm(); + + // structure for fixing up pc-relative loads/jumps when a the machine code + // gets moved (executable copy, gc, etc.) + struct RelativePatch + { + // the offset within the code buffer where the value is loaded that + // we want to fix-up + BufferOffset offset; + void* target; + Relocation::Kind kind; + + RelativePatch(BufferOffset offset, void* target, Relocation::Kind kind) + : offset(offset), + target(target), + kind(kind) + { } + }; + + js::Vector codeLabels_; + js::Vector jumps_; + js::Vector longJumps_; + + CompactBufferWriter jumpRelocations_; + CompactBufferWriter dataRelocations_; + CompactBufferWriter preBarriers_; + + MIPSBufferWithExecutableCopy m_buffer; + + public: + AssemblerMIPSShared() + : m_buffer(), + isFinished(false) + { } + + static Condition InvertCondition(Condition cond); + static DoubleCondition InvertCondition(DoubleCondition cond); + + void writeRelocation(BufferOffset src) { + jumpRelocations_.writeUnsigned(src.getOffset()); + } + + // As opposed to x86/x64 version, the data relocation has to be executed + // before to recover the pointer, and not after. + void writeDataRelocation(ImmGCPtr ptr) { + if (ptr.value) { + if (gc::IsInsideNursery(ptr.value)) + embedsNurseryPointers_ = true; + dataRelocations_.writeUnsigned(nextOffset().getOffset()); + } + } + void writePrebarrierOffset(CodeOffsetLabel label) { + preBarriers_.writeUnsigned(label.offset()); + } + + public: + bool oom() const; + + void setPrinter(Sprinter* sp) { + } + + static const Register getStackPointer() { + return StackPointer; + } + + protected: + bool isFinished; + public: + void finish(); + void executableCopy(void* buffer); + void copyJumpRelocationTable(uint8_t* dest); + void copyDataRelocationTable(uint8_t* dest); + void copyPreBarrierTable(uint8_t* dest); + + void addCodeLabel(CodeLabel label); + size_t numCodeLabels() const { + return codeLabels_.length(); + } + CodeLabel codeLabel(size_t i) { + return codeLabels_[i]; + } + + // Size of the instruction stream, in bytes. + size_t size() const; + // Size of the jump relocation table, in bytes. + size_t jumpRelocationTableBytes() const; + size_t dataRelocationTableBytes() const; + size_t preBarrierTableBytes() const; + + // Size of the data table, in bytes. + size_t bytesNeeded() const; + + // Write a blob of binary into the instruction stream *OR* + // into a destination address. If dest is nullptr (the default), then the + // instruction gets written into the instruction stream. If dest is not null + // it is interpreted as a pointer to the location that we want the + // instruction to be written. + BufferOffset writeInst(uint32_t x, uint32_t* dest = nullptr); + // A static variant for the cases where we don't want to have an assembler + // object at all. Normally, you would use the dummy (nullptr) object. + static void WriteInstStatic(uint32_t x, uint32_t* dest); + + public: + BufferOffset haltingAlign(int alignment); + BufferOffset nopAlign(int alignment); + BufferOffset as_nop(); + + // Branch and jump instructions + BufferOffset as_bal(BOffImm16 off); + BufferOffset as_b(BOffImm16 off); + + InstImm getBranchCode(JumpOrCall jumpOrCall); + InstImm getBranchCode(Register s, Register t, Condition c); + InstImm getBranchCode(Register s, Condition c); + InstImm getBranchCode(FloatTestKind testKind, FPConditionBit fcc); + + BufferOffset as_j(JOffImm26 off); + BufferOffset as_jal(JOffImm26 off); + + BufferOffset as_jr(Register rs); + BufferOffset as_jalr(Register rs); + + // Arithmetic instructions + BufferOffset as_addu(Register rd, Register rs, Register rt); + BufferOffset as_addiu(Register rd, Register rs, int32_t j); + BufferOffset as_subu(Register rd, Register rs, Register rt); + BufferOffset as_mult(Register rs, Register rt); + BufferOffset as_multu(Register rs, Register rt); + BufferOffset as_div(Register rs, Register rt); + BufferOffset as_divu(Register rs, Register rt); + BufferOffset as_mul(Register rd, Register rs, Register rt); + + // Logical instructions + BufferOffset as_and(Register rd, Register rs, Register rt); + BufferOffset as_or(Register rd, Register rs, Register rt); + BufferOffset as_xor(Register rd, Register rs, Register rt); + BufferOffset as_nor(Register rd, Register rs, Register rt); + + BufferOffset as_andi(Register rd, Register rs, int32_t j); + BufferOffset as_ori(Register rd, Register rs, int32_t j); + BufferOffset as_xori(Register rd, Register rs, int32_t j); + BufferOffset as_lui(Register rd, int32_t j); + + // Shift instructions + // as_sll(zero, zero, x) instructions are reserved as nop + BufferOffset as_sll(Register rd, Register rt, uint16_t sa); + BufferOffset as_sllv(Register rd, Register rt, Register rs); + BufferOffset as_srl(Register rd, Register rt, uint16_t sa); + BufferOffset as_srlv(Register rd, Register rt, Register rs); + BufferOffset as_sra(Register rd, Register rt, uint16_t sa); + BufferOffset as_srav(Register rd, Register rt, Register rs); + BufferOffset as_rotr(Register rd, Register rt, uint16_t sa); + BufferOffset as_rotrv(Register rd, Register rt, Register rs); + + // Load and store instructions + BufferOffset as_lb(Register rd, Register rs, int16_t off); + BufferOffset as_lbu(Register rd, Register rs, int16_t off); + BufferOffset as_lh(Register rd, Register rs, int16_t off); + BufferOffset as_lhu(Register rd, Register rs, int16_t off); + BufferOffset as_lw(Register rd, Register rs, int16_t off); + BufferOffset as_lwl(Register rd, Register rs, int16_t off); + BufferOffset as_lwr(Register rd, Register rs, int16_t off); + BufferOffset as_sb(Register rd, Register rs, int16_t off); + BufferOffset as_sh(Register rd, Register rs, int16_t off); + BufferOffset as_sw(Register rd, Register rs, int16_t off); + BufferOffset as_swl(Register rd, Register rs, int16_t off); + BufferOffset as_swr(Register rd, Register rs, int16_t off); + + // Move from HI/LO register. + BufferOffset as_mfhi(Register rd); + BufferOffset as_mflo(Register rd); + + // Set on less than. + BufferOffset as_slt(Register rd, Register rs, Register rt); + BufferOffset as_sltu(Register rd, Register rs, Register rt); + BufferOffset as_slti(Register rd, Register rs, int32_t j); + BufferOffset as_sltiu(Register rd, Register rs, uint32_t j); + + // Conditional move. + BufferOffset as_movz(Register rd, Register rs, Register rt); + BufferOffset as_movn(Register rd, Register rs, Register rt); + BufferOffset as_movt(Register rd, Register rs, uint16_t cc = 0); + BufferOffset as_movf(Register rd, Register rs, uint16_t cc = 0); + + // Bit twiddling. + BufferOffset as_clz(Register rd, Register rs); + BufferOffset as_ins(Register rt, Register rs, uint16_t pos, uint16_t size); + BufferOffset as_ext(Register rt, Register rs, uint16_t pos, uint16_t size); + + // FP instructions + + // Use these two functions only when you are sure address is aligned. + // Otherwise, use ma_ld and ma_sd. + BufferOffset as_ld(FloatRegister fd, Register base, int32_t off); + BufferOffset as_sd(FloatRegister fd, Register base, int32_t off); + + BufferOffset as_ls(FloatRegister fd, Register base, int32_t off); + BufferOffset as_ss(FloatRegister fd, Register base, int32_t off); + + BufferOffset as_movs(FloatRegister fd, FloatRegister fs); + BufferOffset as_movd(FloatRegister fd, FloatRegister fs); + + BufferOffset as_mtc1(Register rt, FloatRegister fs); + BufferOffset as_mfc1(Register rt, FloatRegister fs); + + + public: + // FP convert instructions + BufferOffset as_ceilws(FloatRegister fd, FloatRegister fs); + BufferOffset as_floorws(FloatRegister fd, FloatRegister fs); + BufferOffset as_roundws(FloatRegister fd, FloatRegister fs); + BufferOffset as_truncws(FloatRegister fd, FloatRegister fs); + + BufferOffset as_ceilwd(FloatRegister fd, FloatRegister fs); + BufferOffset as_floorwd(FloatRegister fd, FloatRegister fs); + BufferOffset as_roundwd(FloatRegister fd, FloatRegister fs); + BufferOffset as_truncwd(FloatRegister fd, FloatRegister fs); + + BufferOffset as_cvtdl(FloatRegister fd, FloatRegister fs); + BufferOffset as_cvtds(FloatRegister fd, FloatRegister fs); + BufferOffset as_cvtdw(FloatRegister fd, FloatRegister fs); + BufferOffset as_cvtld(FloatRegister fd, FloatRegister fs); + BufferOffset as_cvtls(FloatRegister fd, FloatRegister fs); + BufferOffset as_cvtsd(FloatRegister fd, FloatRegister fs); + BufferOffset as_cvtsl(FloatRegister fd, FloatRegister fs); + BufferOffset as_cvtsw(FloatRegister fd, FloatRegister fs); + BufferOffset as_cvtwd(FloatRegister fd, FloatRegister fs); + BufferOffset as_cvtws(FloatRegister fd, FloatRegister fs); + + // FP arithmetic instructions + BufferOffset as_adds(FloatRegister fd, FloatRegister fs, FloatRegister ft); + BufferOffset as_addd(FloatRegister fd, FloatRegister fs, FloatRegister ft); + BufferOffset as_subs(FloatRegister fd, FloatRegister fs, FloatRegister ft); + BufferOffset as_subd(FloatRegister fd, FloatRegister fs, FloatRegister ft); + + BufferOffset as_abss(FloatRegister fd, FloatRegister fs); + BufferOffset as_absd(FloatRegister fd, FloatRegister fs); + BufferOffset as_negs(FloatRegister fd, FloatRegister fs); + BufferOffset as_negd(FloatRegister fd, FloatRegister fs); + + BufferOffset as_muls(FloatRegister fd, FloatRegister fs, FloatRegister ft); + BufferOffset as_muld(FloatRegister fd, FloatRegister fs, FloatRegister ft); + BufferOffset as_divs(FloatRegister fd, FloatRegister fs, FloatRegister ft); + BufferOffset as_divd(FloatRegister fd, FloatRegister fs, FloatRegister ft); + BufferOffset as_sqrts(FloatRegister fd, FloatRegister fs); + BufferOffset as_sqrtd(FloatRegister fd, FloatRegister fs); + + // FP compare instructions + BufferOffset as_cf(FloatFormat fmt, FloatRegister fs, FloatRegister ft, + FPConditionBit fcc = FCC0); + BufferOffset as_cun(FloatFormat fmt, FloatRegister fs, FloatRegister ft, + FPConditionBit fcc = FCC0); + BufferOffset as_ceq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, + FPConditionBit fcc = FCC0); + BufferOffset as_cueq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, + FPConditionBit fcc = FCC0); + BufferOffset as_colt(FloatFormat fmt, FloatRegister fs, FloatRegister ft, + FPConditionBit fcc = FCC0); + BufferOffset as_cult(FloatFormat fmt, FloatRegister fs, FloatRegister ft, + FPConditionBit fcc = FCC0); + BufferOffset as_cole(FloatFormat fmt, FloatRegister fs, FloatRegister ft, + FPConditionBit fcc = FCC0); + BufferOffset as_cule(FloatFormat fmt, FloatRegister fs, FloatRegister ft, + FPConditionBit fcc = FCC0); + + // label operations + void bind(Label* label, BufferOffset boff = BufferOffset()); + uint32_t currentOffset() { + return nextOffset().getOffset(); + } + void retarget(Label* label, Label* target); + + // See Bind + size_t labelOffsetToPatchOffset(size_t offset) { + return actualOffset(offset); + } + + void call(Label* label); + void call(void* target); + + void as_break(uint32_t code); + + public: + static bool SupportsFloatingPoint() { +#if (defined(__mips_hard_float) && !defined(__mips_single_float)) || defined(JS_SIMULATOR_MIPS32) + return true; +#else + return false; +#endif + } + static bool SupportsSimd() { + return js::jit::SupportsSimd; + } + + protected: + InstImm invertBranch(InstImm branch, BOffImm16 skipOffset); + void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) { + enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind)); + if (kind == Relocation::JITCODE) + writeRelocation(src); + } + + void addLongJump(BufferOffset src) { + enoughMemory_ &= longJumps_.append(src.getOffset()); + } + + public: + size_t numLongJumps() const { + return longJumps_.length(); + } + uint32_t longJump(size_t i) { + return longJumps_[i]; + } + + void flushBuffer() { + } + + static uint32_t NopSize() { return 4; } + + static void PatchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue, + ImmPtr expectedValue); + static void PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm); + + static uint32_t AlignDoubleArg(uint32_t offset) { + return (offset + 1U) &~ 1U; + } + + static uint8_t* NextInstruction(uint8_t* instruction, uint32_t* count = nullptr); + + static void ToggleToJmp(CodeLocationLabel inst_); + static void ToggleToCmp(CodeLocationLabel inst_); + + void processCodeLabels(uint8_t* rawCode); + + bool bailed() { + return m_buffer.bail(); + } + + void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end, + const Disassembler::HeapAccess& heapAccess) + { + // Implement this if we implement a disassembler. + } +}; // AssemblerMIPSShared + +// sll zero, zero, 0 +const uint32_t NopInst = 0x00000000; + +// An Instruction is a structure for both encoding and decoding any and all +// MIPS instructions. +class Instruction +{ + protected: + uint32_t data; + + // Standard constructor + Instruction (uint32_t data_) : data(data_) { } + + // You should never create an instruction directly. You should create a + // more specific instruction which will eventually call one of these + // constructors for you. + public: + uint32_t encode() const { + return data; + } + + void makeNop() { + data = NopInst; + } + + void setData(uint32_t data) { + this->data = data; + } + + const Instruction & operator=(const Instruction& src) { + data = src.data; + return *this; + } + + // Extract the one particular bit. + uint32_t extractBit(uint32_t bit) { + return (encode() >> bit) & 1; + } + // Extract a bit field out of the instruction + uint32_t extractBitField(uint32_t hi, uint32_t lo) { + return (encode() >> lo) & ((2 << (hi - lo)) - 1); + } + // Since all MIPS instructions have opcode, the opcode + // extractor resides in the base class. + uint32_t extractOpcode() { + return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift); + } + // Return the fields at their original place in the instruction encoding. + Opcode OpcodeFieldRaw() const { + return static_cast(encode() & OpcodeMask); + } + + // Get the next instruction in the instruction stream. + // This does neat things like ignoreconstant pools and their guards. + Instruction* next(); + + // Sometimes, an api wants a uint32_t (or a pointer to it) rather than + // an instruction. raw() just coerces this into a pointer to a uint32_t + const uint32_t* raw() const { return &data; } + uint32_t size() const { return 4; } +}; // Instruction + +// make sure that it is the right size +static_assert(sizeof(Instruction) == 4, "Size of Instruction class has to be 4 bytes."); + +class InstNOP : public Instruction +{ + public: + InstNOP() + : Instruction(NopInst) + { } + +}; + +// Class for register type instructions. +class InstReg : public Instruction +{ + public: + InstReg(Opcode op, Register rd, FunctionField ff) + : Instruction(op | RD(rd) | ff) + { } + InstReg(Opcode op, Register rs, Register rt, FunctionField ff) + : Instruction(op | RS(rs) | RT(rt) | ff) + { } + InstReg(Opcode op, Register rs, Register rt, Register rd, FunctionField ff) + : Instruction(op | RS(rs) | RT(rt) | RD(rd) | ff) + { } + InstReg(Opcode op, Register rs, Register rt, Register rd, uint32_t sa, FunctionField ff) + : Instruction(op | RS(rs) | RT(rt) | RD(rd) | SA(sa) | ff) + { } + InstReg(Opcode op, RSField rs, Register rt, Register rd, uint32_t sa, FunctionField ff) + : Instruction(op | rs | RT(rt) | RD(rd) | SA(sa) | ff) + { } + InstReg(Opcode op, Register rs, RTField rt, Register rd, uint32_t sa, FunctionField ff) + : Instruction(op | RS(rs) | rt | RD(rd) | SA(sa) | ff) + { } + InstReg(Opcode op, Register rs, uint32_t cc, Register rd, uint32_t sa, FunctionField ff) + : Instruction(op | RS(rs) | cc | RD(rd) | SA(sa) | ff) + { } + InstReg(Opcode op, uint32_t code, FunctionField ff) + : Instruction(op | code | ff) + { } + // for float point + InstReg(Opcode op, RSField rs, Register rt, FloatRegister rd) + : Instruction(op | rs | RT(rt) | RD(rd)) + { } + InstReg(Opcode op, RSField rs, Register rt, FloatRegister rd, uint32_t sa, FunctionField ff) + : Instruction(op | rs | RT(rt) | RD(rd) | SA(sa) | ff) + { } + InstReg(Opcode op, RSField rs, Register rt, FloatRegister fs, FloatRegister fd, FunctionField ff) + : Instruction(op | rs | RT(rt) | RD(fs) | SA(fd) | ff) + { } + InstReg(Opcode op, RSField rs, FloatRegister ft, FloatRegister fs, FloatRegister fd, FunctionField ff) + : Instruction(op | rs | RT(ft) | RD(fs) | SA(fd) | ff) + { } + InstReg(Opcode op, RSField rs, FloatRegister ft, FloatRegister fd, uint32_t sa, FunctionField ff) + : Instruction(op | rs | RT(ft) | RD(fd) | SA(sa) | ff) + { } + + uint32_t extractRS () { + return extractBitField(RSShift + RSBits - 1, RSShift); + } + uint32_t extractRT () { + return extractBitField(RTShift + RTBits - 1, RTShift); + } + uint32_t extractRD () { + return extractBitField(RDShift + RDBits - 1, RDShift); + } + uint32_t extractSA () { + return extractBitField(SAShift + SABits - 1, SAShift); + } + uint32_t extractFunctionField () { + return extractBitField(FunctionShift + FunctionBits - 1, FunctionShift); + } +}; + +// Class for branch, load and store instructions with immediate offset. +class InstImm : public Instruction +{ + public: + void extractImm16(BOffImm16* dest); + + InstImm(Opcode op, Register rs, Register rt, BOffImm16 off) + : Instruction(op | RS(rs) | RT(rt) | off.encode()) + { } + InstImm(Opcode op, Register rs, RTField rt, BOffImm16 off) + : Instruction(op | RS(rs) | rt | off.encode()) + { } + InstImm(Opcode op, RSField rs, uint32_t cc, BOffImm16 off) + : Instruction(op | rs | cc | off.encode()) + { } + InstImm(Opcode op, Register rs, Register rt, Imm16 off) + : Instruction(op | RS(rs) | RT(rt) | off.encode()) + { } + InstImm(uint32_t raw) + : Instruction(raw) + { } + // For floating-point loads and stores. + InstImm(Opcode op, Register rs, FloatRegister rt, Imm16 off) + : Instruction(op | RS(rs) | RT(rt) | off.encode()) + { } + + uint32_t extractOpcode() { + return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift); + } + void setOpcode(Opcode op) { + data = (data & ~OpcodeMask) | op; + } + uint32_t extractRS() { + return extractBitField(RSShift + RSBits - 1, RSShift); + } + uint32_t extractRT() { + return extractBitField(RTShift + RTBits - 1, RTShift); + } + void setRT(RTField rt) { + data = (data & ~RTMask) | rt; + } + uint32_t extractImm16Value() { + return extractBitField(Imm16Shift + Imm16Bits - 1, Imm16Shift); + } + void setBOffImm16(BOffImm16 off) { + // Reset immediate field and replace it + data = (data & ~Imm16Mask) | off.encode(); + } + void setImm16(Imm16 off) { + // Reset immediate field and replace it + data = (data & ~Imm16Mask) | off.encode(); + } +}; + +// Class for Jump type instructions. +class InstJump : public Instruction +{ + public: + InstJump(Opcode op, JOffImm26 off) + : Instruction(op | off.encode()) + { } + + uint32_t extractImm26Value() { + return extractBitField(Imm26Shift + Imm26Bits - 1, Imm26Shift); + } +}; + +static const uint32_t NumIntArgRegs = NUM_INT_ARG_REGS; + +static inline bool +GetIntArgReg(uint32_t usedArgSlots, Register* out) +{ + if (usedArgSlots < NumIntArgRegs) { + *out = Register::FromCode(a0.code() + usedArgSlots); + return true; + } + return false; +} + +// Get a register in which we plan to put a quantity that will be used as an +// integer argument. This differs from GetIntArgReg in that if we have no more +// actual argument registers to use we will fall back on using whatever +// CallTempReg* don't overlap the argument registers, and only fail once those +// run out too. +static inline bool +GetTempRegForIntArg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register* out) +{ + // NOTE: We can't properly determine which regs are used if there are + // float arguments. If this is needed, we will have to guess. + MOZ_ASSERT(usedFloatArgs == 0); + + if (GetIntArgReg(usedIntArgs, out)) + return true; + // Unfortunately, we have to assume things about the point at which + // GetIntArgReg returns false, because we need to know how many registers it + // can allocate. + usedIntArgs -= NumIntArgRegs; + if (usedIntArgs >= NumCallTempNonArgRegs) + return false; + *out = CallTempNonArgRegs[usedIntArgs]; + return true; +} + +} // namespace jit +} // namespace js + +#endif /* jit_mips_shared_Assembler_mips_shared_h */ diff --git a/js/src/jit/mips32/Assembler-mips32.cpp b/js/src/jit/mips32/Assembler-mips32.cpp index 797784d47a19..e5031c66d935 100644 --- a/js/src/jit/mips32/Assembler-mips32.cpp +++ b/js/src/jit/mips32/Assembler-mips32.cpp @@ -6,18 +6,6 @@ #include "jit/mips32/Assembler-mips32.h" -#include "mozilla/DebugOnly.h" -#include "mozilla/MathAlgorithms.h" - -#include "jscompartment.h" -#include "jsutil.h" - -#include "gc/Marking.h" -#include "jit/ExecutableAllocator.h" -#include "jit/JitCompartment.h" - -using mozilla::DebugOnly; - using namespace js; using namespace js::jit; @@ -87,22 +75,6 @@ const Register ABIArgGenerator::NonArg_VolatileReg = v0; const Register ABIArgGenerator::NonReturn_VolatileReg0 = a0; const Register ABIArgGenerator::NonReturn_VolatileReg1 = a1; -// Encode a standard register when it is being used as rd, the rs, and -// an extra register(rt). These should never be called with an InvalidReg. -uint32_t -js::jit::RS(Register r) -{ - MOZ_ASSERT((r.code() & ~RegMask) == 0); - return r.code() << RSShift; -} - -uint32_t -js::jit::RT(Register r) -{ - MOZ_ASSERT((r.code() & ~RegMask) == 0); - return r.code() << RTShift; -} - uint32_t js::jit::RT(FloatRegister r) { @@ -110,13 +82,6 @@ js::jit::RT(FloatRegister r) return r.id() << RTShift; } -uint32_t -js::jit::RD(Register r) -{ - MOZ_ASSERT((r.code() & ~RegMask) == 0); - return r.code() << RDShift; -} - uint32_t js::jit::RD(FloatRegister r) { @@ -124,13 +89,6 @@ js::jit::RD(FloatRegister r) return r.id() << RDShift; } -uint32_t -js::jit::SA(uint32_t value) -{ - MOZ_ASSERT(value < 32); - return value << SAShift; -} - uint32_t js::jit::SA(FloatRegister r) { @@ -138,36 +96,6 @@ js::jit::SA(FloatRegister r) return r.id() << SAShift; } -Register -js::jit::toRS(Instruction& i) -{ - return Register::FromCode((i.encode() & RSMask ) >> RSShift); -} - -Register -js::jit::toRT(Instruction& i) -{ - return Register::FromCode((i.encode() & RTMask ) >> RTShift); -} - -Register -js::jit::toRD(Instruction& i) -{ - return Register::FromCode((i.encode() & RDMask ) >> RDShift); -} - -Register -js::jit::toR(Instruction& i) -{ - return Register::FromCode(i.encode() & RegMask); -} - -void -InstImm::extractImm16(BOffImm16* dest) -{ - *dest = BOffImm16(*this); -} - // Used to patch jumps created by MacroAssemblerMIPSCompat::jumpWithPatch. void jit::PatchJump(CodeLocationJump& jump_, CodeLocationLabel label, ReprotectCode reprotect) @@ -209,13 +137,6 @@ jit::PatchBackedge(CodeLocationJump& jump, CodeLocationLabel label, } } -void -Assembler::finish() -{ - MOZ_ASSERT(!isFinished); - isFinished = true; -} - void Assembler::executableCopy(uint8_t* buffer) { @@ -226,54 +147,13 @@ Assembler::executableCopy(uint8_t* buffer) for (size_t i = 0; i < longJumps_.length(); i++) { Instruction* inst1 = (Instruction*) ((uint32_t)buffer + longJumps_[i]); - uint32_t value = ExtractLuiOriValue(inst1, inst1->next()); - UpdateLuiOriValue(inst1, inst1->next(), (uint32_t)buffer + value); + uint32_t value = Assembler::ExtractLuiOriValue(inst1, inst1->next()); + Assembler::UpdateLuiOriValue(inst1, inst1->next(), (uint32_t)buffer + value); } AutoFlushICache::setRange(uintptr_t(buffer), m_buffer.size()); } -uint32_t -Assembler::actualOffset(uint32_t off_) const -{ - return off_; -} - -uint32_t -Assembler::actualIndex(uint32_t idx_) const -{ - return idx_; -} - -uint8_t* -Assembler::PatchableJumpAddress(JitCode* code, uint32_t pe_) -{ - return code->raw() + pe_; -} - -class RelocationIterator -{ - CompactBufferReader reader_; - // offset in bytes - uint32_t offset_; - - public: - RelocationIterator(CompactBufferReader& reader) - : reader_(reader) - { } - - bool read() { - if (!reader_.more()) - return false; - offset_ = reader_.readUnsigned(); - return true; - } - - uint32_t offset() const { - return offset_; - } -}; - uintptr_t Assembler::GetPointer(uint8_t* instPtr) { @@ -339,27 +219,6 @@ Assembler::TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReade ::TraceDataRelocations(trc, code->raw(), reader); } -void -Assembler::copyJumpRelocationTable(uint8_t* dest) -{ - if (jumpRelocations_.length()) - memcpy(dest, jumpRelocations_.buffer(), jumpRelocations_.length()); -} - -void -Assembler::copyDataRelocationTable(uint8_t* dest) -{ - if (dataRelocations_.length()) - memcpy(dest, dataRelocations_.buffer(), dataRelocations_.length()); -} - -void -Assembler::copyPreBarrierTable(uint8_t* dest) -{ - if (preBarriers_.length()) - memcpy(dest, preBarriers_.buffer(), preBarriers_.length()); -} - void Assembler::trace(JSTracer* trc) { @@ -377,15 +236,6 @@ Assembler::trace(JSTracer* trc) } } -void -Assembler::processCodeLabels(uint8_t* rawCode) -{ - for (size_t i = 0; i < codeLabels_.length(); i++) { - CodeLabel label = codeLabels_[i]; - Bind(rawCode, label.dest(), rawCode + actualOffset(label.src()->offset())); - } -} - int32_t Assembler::ExtractCodeLabelOffset(uint8_t* code) { InstImm* inst = (InstImm*)code; @@ -407,912 +257,6 @@ Assembler::Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address) label->bind(); } -Assembler::Condition -Assembler::InvertCondition(Condition cond) -{ - switch (cond) { - case Equal: - return NotEqual; - case NotEqual: - return Equal; - case Zero: - return NonZero; - case NonZero: - return Zero; - case LessThan: - return GreaterThanOrEqual; - case LessThanOrEqual: - return GreaterThan; - case GreaterThan: - return LessThanOrEqual; - case GreaterThanOrEqual: - return LessThan; - case Above: - return BelowOrEqual; - case AboveOrEqual: - return Below; - case Below: - return AboveOrEqual; - case BelowOrEqual: - return Above; - case Signed: - return NotSigned; - case NotSigned: - return Signed; - default: - MOZ_CRASH("unexpected condition"); - } -} - -Assembler::DoubleCondition -Assembler::InvertCondition(DoubleCondition cond) -{ - switch (cond) { - case DoubleOrdered: - return DoubleUnordered; - case DoubleEqual: - return DoubleNotEqualOrUnordered; - case DoubleNotEqual: - return DoubleEqualOrUnordered; - case DoubleGreaterThan: - return DoubleLessThanOrEqualOrUnordered; - case DoubleGreaterThanOrEqual: - return DoubleLessThanOrUnordered; - case DoubleLessThan: - return DoubleGreaterThanOrEqualOrUnordered; - case DoubleLessThanOrEqual: - return DoubleGreaterThanOrUnordered; - case DoubleUnordered: - return DoubleOrdered; - case DoubleEqualOrUnordered: - return DoubleNotEqual; - case DoubleNotEqualOrUnordered: - return DoubleEqual; - case DoubleGreaterThanOrUnordered: - return DoubleLessThanOrEqual; - case DoubleGreaterThanOrEqualOrUnordered: - return DoubleLessThan; - case DoubleLessThanOrUnordered: - return DoubleGreaterThanOrEqual; - case DoubleLessThanOrEqualOrUnordered: - return DoubleGreaterThan; - default: - MOZ_CRASH("unexpected condition"); - } -} - -BOffImm16::BOffImm16(InstImm inst) - : data(inst.encode() & Imm16Mask) -{ -} - -bool -Assembler::oom() const -{ - return AssemblerShared::oom() || - m_buffer.oom() || - jumpRelocations_.oom() || - dataRelocations_.oom() || - preBarriers_.oom(); -} - -void -Assembler::addCodeLabel(CodeLabel label) -{ - propagateOOM(codeLabels_.append(label)); -} - -// Size of the instruction stream, in bytes. -size_t -Assembler::size() const -{ - return m_buffer.size(); -} - -// Size of the relocation table, in bytes. -size_t -Assembler::jumpRelocationTableBytes() const -{ - return jumpRelocations_.length(); -} - -size_t -Assembler::dataRelocationTableBytes() const -{ - return dataRelocations_.length(); -} - -size_t -Assembler::preBarrierTableBytes() const -{ - return preBarriers_.length(); -} - -// Size of the data table, in bytes. -size_t -Assembler::bytesNeeded() const -{ - return size() + - jumpRelocationTableBytes() + - dataRelocationTableBytes() + - preBarrierTableBytes(); -} - -// write a blob of binary into the instruction stream -BufferOffset -Assembler::writeInst(uint32_t x, uint32_t* dest) -{ - if (dest == nullptr) - return m_buffer.putInt(x); - - WriteInstStatic(x, dest); - return BufferOffset(); -} - -void -Assembler::WriteInstStatic(uint32_t x, uint32_t* dest) -{ - MOZ_ASSERT(dest != nullptr); - *dest = x; -} - -BufferOffset -Assembler::haltingAlign(int alignment) -{ - // TODO: Implement a proper halting align. - return nopAlign(alignment); -} - -BufferOffset -Assembler::nopAlign(int alignment) -{ - BufferOffset ret; - MOZ_ASSERT(m_buffer.isAligned(4)); - if (alignment == 8) { - if (!m_buffer.isAligned(alignment)) { - BufferOffset tmp = as_nop(); - if (!ret.assigned()) - ret = tmp; - } - } else { - MOZ_ASSERT((alignment & (alignment - 1)) == 0); - while (size() & (alignment - 1)) { - BufferOffset tmp = as_nop(); - if (!ret.assigned()) - ret = tmp; - } - } - return ret; -} - -BufferOffset -Assembler::as_nop() -{ - return writeInst(op_special | ff_sll); -} - -// Logical operations. -BufferOffset -Assembler::as_and(Register rd, Register rs, Register rt) -{ - return writeInst(InstReg(op_special, rs, rt, rd, ff_and).encode()); -} - -BufferOffset -Assembler::as_or(Register rd, Register rs, Register rt) -{ - return writeInst(InstReg(op_special, rs, rt, rd, ff_or).encode()); -} - -BufferOffset -Assembler::as_xor(Register rd, Register rs, Register rt) -{ - return writeInst(InstReg(op_special, rs, rt, rd, ff_xor).encode()); -} - -BufferOffset -Assembler::as_nor(Register rd, Register rs, Register rt) -{ - return writeInst(InstReg(op_special, rs, rt, rd, ff_nor).encode()); -} - -BufferOffset -Assembler::as_andi(Register rd, Register rs, int32_t j) -{ - MOZ_ASSERT(Imm16::IsInUnsignedRange(j)); - return writeInst(InstImm(op_andi, rs, rd, Imm16(j)).encode()); -} - -BufferOffset -Assembler::as_ori(Register rd, Register rs, int32_t j) -{ - MOZ_ASSERT(Imm16::IsInUnsignedRange(j)); - return writeInst(InstImm(op_ori, rs, rd, Imm16(j)).encode()); -} - -BufferOffset -Assembler::as_xori(Register rd, Register rs, int32_t j) -{ - MOZ_ASSERT(Imm16::IsInUnsignedRange(j)); - return writeInst(InstImm(op_xori, rs, rd, Imm16(j)).encode()); -} - -// Branch and jump instructions -BufferOffset -Assembler::as_bal(BOffImm16 off) -{ - BufferOffset bo = writeInst(InstImm(op_regimm, zero, rt_bgezal, off).encode()); - return bo; -} - -BufferOffset -Assembler::as_b(BOffImm16 off) -{ - BufferOffset bo = writeInst(InstImm(op_beq, zero, zero, off).encode()); - return bo; -} - -InstImm -Assembler::getBranchCode(JumpOrCall jumpOrCall) -{ - if (jumpOrCall == BranchIsCall) - return InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0)); - - return InstImm(op_beq, zero, zero, BOffImm16(0)); -} - -InstImm -Assembler::getBranchCode(Register s, Register t, Condition c) -{ - MOZ_ASSERT(c == Assembler::Equal || c == Assembler::NotEqual); - return InstImm(c == Assembler::Equal ? op_beq : op_bne, s, t, BOffImm16(0)); -} - -InstImm -Assembler::getBranchCode(Register s, Condition c) -{ - switch (c) { - case Assembler::Equal: - case Assembler::Zero: - case Assembler::BelowOrEqual: - return InstImm(op_beq, s, zero, BOffImm16(0)); - case Assembler::NotEqual: - case Assembler::NonZero: - case Assembler::Above: - return InstImm(op_bne, s, zero, BOffImm16(0)); - case Assembler::GreaterThan: - return InstImm(op_bgtz, s, zero, BOffImm16(0)); - case Assembler::GreaterThanOrEqual: - case Assembler::NotSigned: - return InstImm(op_regimm, s, rt_bgez, BOffImm16(0)); - case Assembler::LessThan: - case Assembler::Signed: - return InstImm(op_regimm, s, rt_bltz, BOffImm16(0)); - case Assembler::LessThanOrEqual: - return InstImm(op_blez, s, zero, BOffImm16(0)); - default: - MOZ_CRASH("Condition not supported."); - } -} - -InstImm -Assembler::getBranchCode(FloatTestKind testKind, FPConditionBit fcc) -{ - MOZ_ASSERT(!(fcc && FccMask)); - uint32_t rtField = ((testKind == TestForTrue ? 1 : 0) | (fcc << FccShift)) << RTShift; - - return InstImm(op_cop1, rs_bc1, rtField, BOffImm16(0)); -} - -BufferOffset -Assembler::as_j(JOffImm26 off) -{ - BufferOffset bo = writeInst(InstJump(op_j, off).encode()); - return bo; -} -BufferOffset -Assembler::as_jal(JOffImm26 off) -{ - BufferOffset bo = writeInst(InstJump(op_jal, off).encode()); - return bo; -} - -BufferOffset -Assembler::as_jr(Register rs) -{ - BufferOffset bo = writeInst(InstReg(op_special, rs, zero, zero, ff_jr).encode()); - return bo; -} -BufferOffset -Assembler::as_jalr(Register rs) -{ - BufferOffset bo = writeInst(InstReg(op_special, rs, zero, ra, ff_jalr).encode()); - return bo; -} - - -// Arithmetic instructions -BufferOffset -Assembler::as_addu(Register rd, Register rs, Register rt) -{ - return writeInst(InstReg(op_special, rs, rt, rd, ff_addu).encode()); -} - -BufferOffset -Assembler::as_addiu(Register rd, Register rs, int32_t j) -{ - MOZ_ASSERT(Imm16::IsInSignedRange(j)); - return writeInst(InstImm(op_addiu, rs, rd, Imm16(j)).encode()); -} - -BufferOffset -Assembler::as_subu(Register rd, Register rs, Register rt) -{ - return writeInst(InstReg(op_special, rs, rt, rd, ff_subu).encode()); -} - -BufferOffset -Assembler::as_mult(Register rs, Register rt) -{ - return writeInst(InstReg(op_special, rs, rt, ff_mult).encode()); -} - -BufferOffset -Assembler::as_multu(Register rs, Register rt) -{ - return writeInst(InstReg(op_special, rs, rt, ff_multu).encode()); -} - -BufferOffset -Assembler::as_div(Register rs, Register rt) -{ - return writeInst(InstReg(op_special, rs, rt, ff_div).encode()); -} - -BufferOffset -Assembler::as_divu(Register rs, Register rt) -{ - return writeInst(InstReg(op_special, rs, rt, ff_divu).encode()); -} - -BufferOffset -Assembler::as_mul(Register rd, Register rs, Register rt) -{ - return writeInst(InstReg(op_special2, rs, rt, rd, ff_mul).encode()); -} - -BufferOffset -Assembler::as_lui(Register rd, int32_t j) -{ - MOZ_ASSERT(Imm16::IsInUnsignedRange(j)); - return writeInst(InstImm(op_lui, zero, rd, Imm16(j)).encode()); -} - -// Shift instructions -BufferOffset -Assembler::as_sll(Register rd, Register rt, uint16_t sa) -{ - MOZ_ASSERT(sa < 32); - return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sll).encode()); -} - -BufferOffset -Assembler::as_sllv(Register rd, Register rt, Register rs) -{ - return writeInst(InstReg(op_special, rs, rt, rd, ff_sllv).encode()); -} - -BufferOffset -Assembler::as_srl(Register rd, Register rt, uint16_t sa) -{ - MOZ_ASSERT(sa < 32); - return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_srl).encode()); -} - -BufferOffset -Assembler::as_srlv(Register rd, Register rt, Register rs) -{ - return writeInst(InstReg(op_special, rs, rt, rd, ff_srlv).encode()); -} - -BufferOffset -Assembler::as_sra(Register rd, Register rt, uint16_t sa) -{ - MOZ_ASSERT(sa < 32); - return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sra).encode()); -} - -BufferOffset -Assembler::as_srav(Register rd, Register rt, Register rs) -{ - return writeInst(InstReg(op_special, rs, rt, rd, ff_srav).encode()); -} - -BufferOffset -Assembler::as_rotr(Register rd, Register rt, uint16_t sa) -{ - MOZ_ASSERT(sa < 32); - return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_srl).encode()); -} - -BufferOffset -Assembler::as_rotrv(Register rd, Register rt, Register rs) -{ - return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_srlv).encode()); -} - -// Load and store instructions -BufferOffset -Assembler::as_lb(Register rd, Register rs, int16_t off) -{ - return writeInst(InstImm(op_lb, rs, rd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_lbu(Register rd, Register rs, int16_t off) -{ - return writeInst(InstImm(op_lbu, rs, rd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_lh(Register rd, Register rs, int16_t off) -{ - return writeInst(InstImm(op_lh, rs, rd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_lhu(Register rd, Register rs, int16_t off) -{ - return writeInst(InstImm(op_lhu, rs, rd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_lw(Register rd, Register rs, int16_t off) -{ - return writeInst(InstImm(op_lw, rs, rd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_lwl(Register rd, Register rs, int16_t off) -{ - return writeInst(InstImm(op_lwl, rs, rd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_lwr(Register rd, Register rs, int16_t off) -{ - return writeInst(InstImm(op_lwr, rs, rd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_sb(Register rd, Register rs, int16_t off) -{ - return writeInst(InstImm(op_sb, rs, rd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_sh(Register rd, Register rs, int16_t off) -{ - return writeInst(InstImm(op_sh, rs, rd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_sw(Register rd, Register rs, int16_t off) -{ - return writeInst(InstImm(op_sw, rs, rd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_swl(Register rd, Register rs, int16_t off) -{ - return writeInst(InstImm(op_swl, rs, rd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_swr(Register rd, Register rs, int16_t off) -{ - return writeInst(InstImm(op_swr, rs, rd, Imm16(off)).encode()); -} - -// Move from HI/LO register. -BufferOffset -Assembler::as_mfhi(Register rd) -{ - return writeInst(InstReg(op_special, rd, ff_mfhi).encode()); -} - -BufferOffset -Assembler::as_mflo(Register rd) -{ - return writeInst(InstReg(op_special, rd, ff_mflo).encode()); -} - -// Set on less than. -BufferOffset -Assembler::as_slt(Register rd, Register rs, Register rt) -{ - return writeInst(InstReg(op_special, rs, rt, rd, ff_slt).encode()); -} - -BufferOffset -Assembler::as_sltu(Register rd, Register rs, Register rt) -{ - return writeInst(InstReg(op_special, rs, rt, rd, ff_sltu).encode()); -} - -BufferOffset -Assembler::as_slti(Register rd, Register rs, int32_t j) -{ - MOZ_ASSERT(Imm16::IsInSignedRange(j)); - return writeInst(InstImm(op_slti, rs, rd, Imm16(j)).encode()); -} - -BufferOffset -Assembler::as_sltiu(Register rd, Register rs, uint32_t j) -{ - MOZ_ASSERT(Imm16::IsInUnsignedRange(j)); - return writeInst(InstImm(op_sltiu, rs, rd, Imm16(j)).encode()); -} - -// Conditional move. -BufferOffset -Assembler::as_movz(Register rd, Register rs, Register rt) -{ - return writeInst(InstReg(op_special, rs, rt, rd, ff_movz).encode()); -} - -BufferOffset -Assembler::as_movn(Register rd, Register rs, Register rt) -{ - return writeInst(InstReg(op_special, rs, rt, rd, ff_movn).encode()); -} - -BufferOffset -Assembler::as_movt(Register rd, Register rs, uint16_t cc) -{ - Register rt; - rt = Register::FromCode((cc & 0x7) << 2 | 1); - return writeInst(InstReg(op_special, rs, rt, rd, ff_movci).encode()); -} - -BufferOffset -Assembler::as_movf(Register rd, Register rs, uint16_t cc) -{ - Register rt; - rt = Register::FromCode((cc & 0x7) << 2 | 0); - return writeInst(InstReg(op_special, rs, rt, rd, ff_movci).encode()); -} - -// Bit twiddling. -BufferOffset -Assembler::as_clz(Register rd, Register rs) -{ - return writeInst(InstReg(op_special2, rs, rd, rd, ff_clz).encode()); -} - -BufferOffset -Assembler::as_ins(Register rt, Register rs, uint16_t pos, uint16_t size) -{ - MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 32); - Register rd; - rd = Register::FromCode(pos + size - 1); - return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ins).encode()); -} - -BufferOffset -Assembler::as_ext(Register rt, Register rs, uint16_t pos, uint16_t size) -{ - MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 32); - Register rd; - rd = Register::FromCode(size - 1); - return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ext).encode()); -} - -// FP instructions -BufferOffset -Assembler::as_ld(FloatRegister fd, Register base, int32_t off) -{ - MOZ_ASSERT(Imm16::IsInSignedRange(off)); - return writeInst(InstImm(op_ldc1, base, fd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_sd(FloatRegister fd, Register base, int32_t off) -{ - MOZ_ASSERT(Imm16::IsInSignedRange(off)); - return writeInst(InstImm(op_sdc1, base, fd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_ls(FloatRegister fd, Register base, int32_t off) -{ - MOZ_ASSERT(Imm16::IsInSignedRange(off)); - return writeInst(InstImm(op_lwc1, base, fd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_ss(FloatRegister fd, Register base, int32_t off) -{ - MOZ_ASSERT(Imm16::IsInSignedRange(off)); - return writeInst(InstImm(op_swc1, base, fd, Imm16(off)).encode()); -} - -BufferOffset -Assembler::as_movs(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_mov_fmt).encode()); -} - -BufferOffset -Assembler::as_movd(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_mov_fmt).encode()); -} - -BufferOffset -Assembler::as_mtc1(Register rt, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_mtc1, rt, fs).encode()); -} - -BufferOffset -Assembler::as_mfc1(Register rt, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_mfc1, rt, fs).encode()); -} - -// FP convert instructions -BufferOffset -Assembler::as_ceilws(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_ceil_w_fmt).encode()); -} - -BufferOffset -Assembler::as_floorws(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_floor_w_fmt).encode()); -} - -BufferOffset -Assembler::as_roundws(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_round_w_fmt).encode()); -} - -BufferOffset -Assembler::as_truncws(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_trunc_w_fmt).encode()); -} - -BufferOffset -Assembler::as_ceilwd(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_ceil_w_fmt).encode()); -} - -BufferOffset -Assembler::as_floorwd(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_floor_w_fmt).encode()); -} - -BufferOffset -Assembler::as_roundwd(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_round_w_fmt).encode()); -} - -BufferOffset -Assembler::as_truncwd(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_trunc_w_fmt).encode()); -} - -BufferOffset -Assembler::as_cvtds(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_d_fmt).encode()); -} - -BufferOffset -Assembler::as_cvtdw(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_w, zero, fs, fd, ff_cvt_d_fmt).encode()); -} - -BufferOffset -Assembler::as_cvtsd(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_cvt_s_fmt).encode()); -} - -BufferOffset -Assembler::as_cvtsw(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_w, zero, fs, fd, ff_cvt_s_fmt).encode()); -} - -BufferOffset -Assembler::as_cvtwd(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_cvt_w_fmt).encode()); -} - -BufferOffset -Assembler::as_cvtws(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_w_fmt).encode()); -} - -// FP arithmetic instructions -BufferOffset -Assembler::as_adds(FloatRegister fd, FloatRegister fs, FloatRegister ft) -{ - return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_add_fmt).encode()); -} - -BufferOffset -Assembler::as_addd(FloatRegister fd, FloatRegister fs, FloatRegister ft) -{ - return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_add_fmt).encode()); -} - -BufferOffset -Assembler::as_subs(FloatRegister fd, FloatRegister fs, FloatRegister ft) -{ - return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_sub_fmt).encode()); -} - -BufferOffset -Assembler::as_subd(FloatRegister fd, FloatRegister fs, FloatRegister ft) -{ - return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_sub_fmt).encode()); -} - -BufferOffset -Assembler::as_abss(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_abs_fmt).encode()); -} - -BufferOffset -Assembler::as_absd(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_abs_fmt).encode()); -} - -BufferOffset -Assembler::as_negs(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_neg_fmt).encode()); -} - -BufferOffset -Assembler::as_negd(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_neg_fmt).encode()); -} - -BufferOffset -Assembler::as_muls(FloatRegister fd, FloatRegister fs, FloatRegister ft) -{ - return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_mul_fmt).encode()); -} - -BufferOffset -Assembler::as_muld(FloatRegister fd, FloatRegister fs, FloatRegister ft) -{ - return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_mul_fmt).encode()); -} - -BufferOffset -Assembler::as_divs(FloatRegister fd, FloatRegister fs, FloatRegister ft) -{ - return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_div_fmt).encode()); -} - -BufferOffset -Assembler::as_divd(FloatRegister fd, FloatRegister fs, FloatRegister ft) -{ - return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_div_fmt).encode()); -} - -BufferOffset -Assembler::as_sqrts(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_sqrt_fmt).encode()); -} - -BufferOffset -Assembler::as_sqrtd(FloatRegister fd, FloatRegister fs) -{ - return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_sqrt_fmt).encode()); -} - -// FP compare instructions -BufferOffset -Assembler::as_cf(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) -{ - RSField rs = fmt == DoubleFloat ? rs_d : rs_s; - return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_f_fmt).encode()); -} - -BufferOffset -Assembler::as_cun(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) -{ - RSField rs = fmt == DoubleFloat ? rs_d : rs_s; - return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_un_fmt).encode()); -} - -BufferOffset -Assembler::as_ceq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) -{ - RSField rs = fmt == DoubleFloat ? rs_d : rs_s; - return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_eq_fmt).encode()); -} - -BufferOffset -Assembler::as_cueq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) -{ - RSField rs = fmt == DoubleFloat ? rs_d : rs_s; - return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ueq_fmt).encode()); -} - -BufferOffset -Assembler::as_colt(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) -{ - RSField rs = fmt == DoubleFloat ? rs_d : rs_s; - return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_olt_fmt).encode()); -} - -BufferOffset -Assembler::as_cult(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) -{ - RSField rs = fmt == DoubleFloat ? rs_d : rs_s; - return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ult_fmt).encode()); -} - -BufferOffset -Assembler::as_cole(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) -{ - RSField rs = fmt == DoubleFloat ? rs_d : rs_s; - return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ole_fmt).encode()); -} - -BufferOffset -Assembler::as_cule(FloatFormat fmt, FloatRegister fs, FloatRegister ft, FPConditionBit fcc) -{ - RSField rs = fmt == DoubleFloat ? rs_d : rs_s; - return writeInst(InstReg(op_cop1, rs, ft, fs, fcc << FccShift, ff_c_ule_fmt).encode()); -} - - -void -Assembler::bind(Label* label, BufferOffset boff) -{ - // If our caller didn't give us an explicit target to bind to - // then we want to bind to the location of the next instruction - BufferOffset dest = boff.assigned() ? boff : nextOffset(); - if (label->used()) { - int32_t next; - - // A used label holds a link to branch that uses it. - BufferOffset b(label); - do { - Instruction* inst = editSrc(b); - - // Second word holds a pointer to the next branch in label's chain. - next = inst[1].encode(); - bind(reinterpret_cast(inst), b.getOffset(), dest.getOffset()); - - b = BufferOffset(next); - } while (next != LabelBase::INVALID_OFFSET); - } - label->bind(dest.getOffset()); -} - void Assembler::bind(InstImm* inst, uint32_t branch, uint32_t target) { @@ -1332,7 +276,7 @@ Assembler::bind(InstImm* inst, uint32_t branch, uint32_t target) // address after the reserved block. if (inst[0].encode() == inst_bgezal.encode()) { addLongJump(BufferOffset(branch)); - WriteLuiOriInstructions(inst, &inst[1], ScratchRegister, target); + Assembler::WriteLuiOriInstructions(inst, &inst[1], ScratchRegister, target); inst[2] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr).encode(); // There is 1 nop after this. return; @@ -1356,7 +300,7 @@ Assembler::bind(InstImm* inst, uint32_t branch, uint32_t target) if (inst[0].encode() == inst_beq.encode()) { // Handle long unconditional jump. addLongJump(BufferOffset(branch)); - WriteLuiOriInstructions(inst, &inst[1], ScratchRegister, target); + Assembler::WriteLuiOriInstructions(inst, &inst[1], ScratchRegister, target); inst[2] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode(); // There is 1 nop after this. } else { @@ -1364,7 +308,7 @@ Assembler::bind(InstImm* inst, uint32_t branch, uint32_t target) inst[0] = invertBranch(inst[0], BOffImm16(5 * sizeof(void*))); // No need for a "nop" here because we can clobber scratch. addLongJump(BufferOffset(branch + sizeof(void*))); - WriteLuiOriInstructions(&inst[1], &inst[2], ScratchRegister, target); + Assembler::WriteLuiOriInstructions(&inst[1], &inst[2], ScratchRegister, target); inst[3] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode(); // There is 1 nop after this. } @@ -1388,57 +332,13 @@ Assembler::bind(RepatchLabel* label) MOZ_ASSERT(BOffImm16::IsInRange(offset)); inst1->setBOffImm16(BOffImm16(offset)); } else { - UpdateLuiOriValue(inst1, inst1->next(), dest.getOffset()); + Assembler::UpdateLuiOriValue(inst1, inst1->next(), dest.getOffset()); } } label->bind(dest.getOffset()); } -void -Assembler::retarget(Label* label, Label* target) -{ - if (label->used()) { - if (target->bound()) { - bind(label, BufferOffset(target)); - } else if (target->used()) { - // The target is not bound but used. Prepend label's branch list - // onto target's. - int32_t next; - BufferOffset labelBranchOffset(label); - - // Find the head of the use chain for label. - do { - Instruction* inst = editSrc(labelBranchOffset); - - // Second word holds a pointer to the next branch in chain. - next = inst[1].encode(); - labelBranchOffset = BufferOffset(next); - } while (next != LabelBase::INVALID_OFFSET); - - // Then patch the head of label's use chain to the tail of - // target's use chain, prepending the entire use chain of target. - Instruction* inst = editSrc(labelBranchOffset); - int32_t prev = target->use(label->offset()); - inst[1].setData(prev); - } else { - // The target is unbound and unused. We can just take the head of - // the list hanging off of label, and dump that into target. - DebugOnly prev = target->use(label->offset()); - MOZ_ASSERT((int32_t)prev == Label::INVALID_OFFSET); - } - } - label->reset(); -} - -void dbg_break() {} -void -Assembler::as_break(uint32_t code) -{ - MOZ_ASSERT(code <= MAX_BREAK_CODE); - writeInst(op_special | code << FunctionBits | ff_break); -} - uint32_t Assembler::PatchWrite_NearCallSize() { @@ -1456,7 +356,7 @@ Assembler::PatchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall // - Jump has to be the same size because of PatchWrite_NearCallSize. // - Return address has to be at the end of replaced block. // Short jump wouldn't be more efficient. - WriteLuiOriInstructions(inst, &inst[1], ScratchRegister, (uint32_t)dest); + Assembler::WriteLuiOriInstructions(inst, &inst[1], ScratchRegister, (uint32_t)dest); inst[2] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr); inst[3] = InstNOP(); @@ -1511,28 +411,6 @@ Assembler::PatchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newVal AutoFlushICache::flush(uintptr_t(inst), 8); } -void -Assembler::PatchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue, ImmPtr expectedValue) -{ - PatchDataWithValueCheck(label, PatchedImmPtr(newValue.value), - PatchedImmPtr(expectedValue.value)); -} - -// This just stomps over memory with 32 bits of raw data. Its purpose is to -// overwrite the call of JITed code with 32 bits worth of an offset. This will -// is only meant to function on code that has been invalidated, so it should -// be totally safe. Since that instruction will never be executed again, a -// ICache flush should not be necessary -void -Assembler::PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm) -{ - // Raw is going to be the return address. - uint32_t* raw = (uint32_t*)label.raw(); - // Overwrite the 4 bytes before the return address, which will - // end up being the call instruction. - *(raw - 1) = imm.value; -} - void Assembler::PatchInstructionImmediate(uint8_t* code, PatchedImmPtr imm) { @@ -1540,97 +418,6 @@ Assembler::PatchInstructionImmediate(uint8_t* code, PatchedImmPtr imm) Assembler::UpdateLuiOriValue(inst, inst->next(), (uint32_t)imm.value); } -uint8_t* -Assembler::NextInstruction(uint8_t* inst_, uint32_t* count) -{ - Instruction* inst = reinterpret_cast(inst_); - if (count != nullptr) - *count += sizeof(Instruction); - return reinterpret_cast(inst->next()); -} - -// Since there are no pools in MIPS implementation, this should be simple. -Instruction* -Instruction::next() -{ - return this + 1; -} - -InstImm Assembler::invertBranch(InstImm branch, BOffImm16 skipOffset) -{ - uint32_t rt = 0; - Opcode op = (Opcode) (branch.extractOpcode() << OpcodeShift); - switch(op) { - case op_beq: - branch.setBOffImm16(skipOffset); - branch.setOpcode(op_bne); - return branch; - case op_bne: - branch.setBOffImm16(skipOffset); - branch.setOpcode(op_beq); - return branch; - case op_bgtz: - branch.setBOffImm16(skipOffset); - branch.setOpcode(op_blez); - return branch; - case op_blez: - branch.setBOffImm16(skipOffset); - branch.setOpcode(op_bgtz); - return branch; - case op_regimm: - branch.setBOffImm16(skipOffset); - rt = branch.extractRT(); - if (rt == (rt_bltz >> RTShift)) { - branch.setRT(rt_bgez); - return branch; - } - if (rt == (rt_bgez >> RTShift)) { - branch.setRT(rt_bltz); - return branch; - } - - MOZ_CRASH("Error creating long branch."); - - case op_cop1: - MOZ_ASSERT(branch.extractRS() == rs_bc1 >> RSShift); - - branch.setBOffImm16(skipOffset); - rt = branch.extractRT(); - if (rt & 0x1) - branch.setRT((RTField) ((rt & ~0x1) << RTShift)); - else - branch.setRT((RTField) ((rt | 0x1) << RTShift)); - return branch; - default: - MOZ_CRASH("Error creating long branch."); - } -} - -void -Assembler::ToggleToJmp(CodeLocationLabel inst_) -{ - InstImm * inst = (InstImm*)inst_.raw(); - - MOZ_ASSERT(inst->extractOpcode() == ((uint32_t)op_andi >> OpcodeShift)); - // We converted beq to andi, so now we restore it. - inst->setOpcode(op_beq); - - AutoFlushICache::flush(uintptr_t(inst), 4); -} - -void -Assembler::ToggleToCmp(CodeLocationLabel inst_) -{ - InstImm * inst = (InstImm*)inst_.raw(); - - // toggledJump is allways used for short jumps. - MOZ_ASSERT(inst->extractOpcode() == ((uint32_t)op_beq >> OpcodeShift)); - // Replace "beq $zero, $zero, offset" with "andi $zero, $zero, offset" - inst->setOpcode(op_andi); - - AutoFlushICache::flush(uintptr_t(inst), 4); -} - void Assembler::ToggleCall(CodeLocationLabel inst_, bool enabled) { @@ -1653,7 +440,8 @@ Assembler::ToggleCall(CodeLocationLabel inst_, bool enabled) AutoFlushICache::flush(uintptr_t(i2), 4); } -void Assembler::UpdateBoundsCheck(uint32_t heapSize, Instruction* inst) +void +Assembler::UpdateBoundsCheck(uint32_t heapSize, Instruction* inst) { InstImm* i0 = (InstImm*) inst; InstImm* i1 = (InstImm*) i0->next(); diff --git a/js/src/jit/mips32/Assembler-mips32.h b/js/src/jit/mips32/Assembler-mips32.h index 814c40ec0c3d..e1d88937c4a3 100644 --- a/js/src/jit/mips32/Assembler-mips32.h +++ b/js/src/jit/mips32/Assembler-mips32.h @@ -7,91 +7,23 @@ #ifndef jit_mips32_Assembler_mips32_h #define jit_mips32_Assembler_mips32_h -#include "mozilla/ArrayUtils.h" -#include "mozilla/Attributes.h" -#include "mozilla/MathAlgorithms.h" +// NOTE: Don't use these macros directly +// CallTempNonArgRegs +#define CALL_TEMP_NON_ARG_REGS \ + { t0, t1, t2, t3, t4 }; +// NumIntArgRegs +#define NUM_INT_ARG_REGS 4; + +#include "jit/mips-shared/Assembler-mips-shared.h" -#include "jit/CompactBuffer.h" -#include "jit/IonCode.h" -#include "jit/JitCompartment.h" -#include "jit/JitSpewer.h" #include "jit/mips32/Architecture-mips32.h" -#include "jit/shared/Assembler-shared.h" -#include "jit/shared/IonAssemblerBuffer.h" namespace js { namespace jit { -static MOZ_CONSTEXPR_VAR Register zero = { Registers::zero }; -static MOZ_CONSTEXPR_VAR Register at = { Registers::at }; -static MOZ_CONSTEXPR_VAR Register v0 = { Registers::v0 }; -static MOZ_CONSTEXPR_VAR Register v1 = { Registers::v1 }; -static MOZ_CONSTEXPR_VAR Register a0 = { Registers::a0 }; -static MOZ_CONSTEXPR_VAR Register a1 = { Registers::a1 }; -static MOZ_CONSTEXPR_VAR Register a2 = { Registers::a2 }; -static MOZ_CONSTEXPR_VAR Register a3 = { Registers::a3 }; -static MOZ_CONSTEXPR_VAR Register t0 = { Registers::t0 }; -static MOZ_CONSTEXPR_VAR Register t1 = { Registers::t1 }; -static MOZ_CONSTEXPR_VAR Register t2 = { Registers::t2 }; -static MOZ_CONSTEXPR_VAR Register t3 = { Registers::t3 }; -static MOZ_CONSTEXPR_VAR Register t4 = { Registers::t4 }; -static MOZ_CONSTEXPR_VAR Register t5 = { Registers::t5 }; -static MOZ_CONSTEXPR_VAR Register t6 = { Registers::t6 }; -static MOZ_CONSTEXPR_VAR Register t7 = { Registers::t7 }; -static MOZ_CONSTEXPR_VAR Register s0 = { Registers::s0 }; -static MOZ_CONSTEXPR_VAR Register s1 = { Registers::s1 }; -static MOZ_CONSTEXPR_VAR Register s2 = { Registers::s2 }; -static MOZ_CONSTEXPR_VAR Register s3 = { Registers::s3 }; -static MOZ_CONSTEXPR_VAR Register s4 = { Registers::s4 }; -static MOZ_CONSTEXPR_VAR Register s5 = { Registers::s5 }; -static MOZ_CONSTEXPR_VAR Register s6 = { Registers::s6 }; -static MOZ_CONSTEXPR_VAR Register s7 = { Registers::s7 }; -static MOZ_CONSTEXPR_VAR Register t8 = { Registers::t8 }; -static MOZ_CONSTEXPR_VAR Register t9 = { Registers::t9 }; -static MOZ_CONSTEXPR_VAR Register k0 = { Registers::k0 }; -static MOZ_CONSTEXPR_VAR Register k1 = { Registers::k1 }; -static MOZ_CONSTEXPR_VAR Register gp = { Registers::gp }; -static MOZ_CONSTEXPR_VAR Register sp = { Registers::sp }; -static MOZ_CONSTEXPR_VAR Register fp = { Registers::fp }; -static MOZ_CONSTEXPR_VAR Register ra = { Registers::ra }; - -static MOZ_CONSTEXPR_VAR Register ScratchRegister = at; -static MOZ_CONSTEXPR_VAR Register SecondScratchReg = t8; - -// Helper classes for ScratchRegister usage. Asserts that only one piece -// of code thinks it has exclusive ownership of each scratch register. -struct ScratchRegisterScope : public AutoRegisterScope -{ - explicit ScratchRegisterScope(MacroAssembler& masm) - : AutoRegisterScope(masm, ScratchRegister) - { } -}; -struct SecondScratchRegisterScope : public AutoRegisterScope -{ - explicit SecondScratchRegisterScope(MacroAssembler& masm) - : AutoRegisterScope(masm, SecondScratchReg) - { } -}; - -// Use arg reg from EnterJIT function as OsrFrameReg. -static MOZ_CONSTEXPR_VAR Register OsrFrameReg = a3; -static MOZ_CONSTEXPR_VAR Register ArgumentsRectifierReg = s3; -static MOZ_CONSTEXPR_VAR Register CallTempReg0 = t0; -static MOZ_CONSTEXPR_VAR Register CallTempReg1 = t1; -static MOZ_CONSTEXPR_VAR Register CallTempReg2 = t2; -static MOZ_CONSTEXPR_VAR Register CallTempReg3 = t3; static MOZ_CONSTEXPR_VAR Register CallTempReg4 = t4; static MOZ_CONSTEXPR_VAR Register CallTempReg5 = t5; -static MOZ_CONSTEXPR_VAR Register IntArgReg0 = a0; -static MOZ_CONSTEXPR_VAR Register IntArgReg1 = a1; -static MOZ_CONSTEXPR_VAR Register IntArgReg2 = a2; -static MOZ_CONSTEXPR_VAR Register IntArgReg3 = a3; -static MOZ_CONSTEXPR_VAR Register GlobalReg = s6; // used by Odin -static MOZ_CONSTEXPR_VAR Register HeapReg = s7; // used by Odin -static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = { t0, t1, t2, t3, t4 }; -static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); - class ABIArgGenerator { unsigned usedArgSlots_; @@ -124,45 +56,19 @@ class ABIArgGenerator static const Register NonReturn_VolatileReg1; }; -static MOZ_CONSTEXPR_VAR Register PreBarrierReg = a1; - -static MOZ_CONSTEXPR_VAR Register InvalidReg = { Registers::invalid_reg }; -static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg; - static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = a3; static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = a2; -static MOZ_CONSTEXPR_VAR Register StackPointer = sp; -static MOZ_CONSTEXPR_VAR Register FramePointer = InvalidReg; -static MOZ_CONSTEXPR_VAR Register ReturnReg = v0; static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = { FloatRegisters::f0, FloatRegister::Single }; static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = { FloatRegisters::f0, FloatRegister::Double }; -static MOZ_CONSTEXPR_VAR FloatRegister ReturnInt32x4Reg = InvalidFloatReg; -static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32x4Reg = InvalidFloatReg; static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = { FloatRegisters::f18, FloatRegister::Single }; static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = { FloatRegisters::f18, FloatRegister::Double }; -static MOZ_CONSTEXPR_VAR FloatRegister ScratchSimdReg = InvalidFloatReg; static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchFloat32Reg = { FloatRegisters::f16, FloatRegister::Single }; static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchDoubleReg = { FloatRegisters::f16, FloatRegister::Double }; -// A bias applied to the GlobalReg to allow the use of instructions with small -// negative immediate offsets which doubles the range of global data that can be -// accessed with a single instruction. -static const int32_t AsmJSGlobalRegBias = 32768; - -// Registers used in the GenerateFFIIonExit Enable Activation block. -static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = t0; -static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = a0; -static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE1 = a1; -static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE2 = a2; -static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE3 = a3; - // Registers used in the GenerateFFIIonExit Disable Activation block. // None of these may be the second scratch register (t8). static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = JSReturnReg_Data; static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = JSReturnReg_Type; -static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = a0; -static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = a1; -static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = t0; static MOZ_CONSTEXPR_VAR FloatRegister f0 = { FloatRegisters::f0, FloatRegister::Double }; static MOZ_CONSTEXPR_VAR FloatRegister f2 = { FloatRegisters::f2, FloatRegister::Double }; @@ -184,792 +90,32 @@ static MOZ_CONSTEXPR_VAR FloatRegister f30 = { FloatRegisters::f30, FloatRegiste // MIPS CPUs can only load multibyte data that is "naturally" // four-byte-aligned, sp register should be eight-byte-aligned. static MOZ_CONSTEXPR_VAR uint32_t ABIStackAlignment = 8; -static MOZ_CONSTEXPR_VAR uint32_t CodeAlignment = 4; static MOZ_CONSTEXPR_VAR uint32_t JitStackAlignment = 8; static MOZ_CONSTEXPR_VAR uint32_t JitStackValueAlignment = JitStackAlignment / sizeof(Value); static_assert(JitStackAlignment % sizeof(Value) == 0 && JitStackValueAlignment >= 1, "Stack alignment should be a non-zero multiple of sizeof(Value)"); -// This boolean indicates whether we support SIMD instructions flavoured for -// this architecture or not. Rather than a method in the LIRGenerator, it is -// here such that it is accessible from the entire codebase. Once full support -// for SIMD is reached on all tier-1 platforms, this constant can be deleted. -static MOZ_CONSTEXPR_VAR bool SupportsSimd = false; // TODO this is just a filler to prevent a build failure. The MIPS SIMD // alignment requirements still need to be explored. // TODO Copy the static_asserts from x64/x86 assembler files. static MOZ_CONSTEXPR_VAR uint32_t SimdMemoryAlignment = 8; - static MOZ_CONSTEXPR_VAR uint32_t AsmJSStackAlignment = SimdMemoryAlignment; static MOZ_CONSTEXPR_VAR Scale ScalePointer = TimesFour; -// MIPS instruction types -// +---------------------------------------------------------------+ -// | 6 | 5 | 5 | 5 | 5 | 6 | -// +---------------------------------------------------------------+ -// Register type | Opcode | Rs | Rt | Rd | Sa | Function | -// +---------------------------------------------------------------+ -// | 6 | 5 | 5 | 16 | -// +---------------------------------------------------------------+ -// Immediate type | Opcode | Rs | Rt | 2's complement constant | -// +---------------------------------------------------------------+ -// | 6 | 26 | -// +---------------------------------------------------------------+ -// Jump type | Opcode | jump_target | -// +---------------------------------------------------------------+ -// 31 bit bit 0 - -// MIPS instruction encoding constants. -static const uint32_t OpcodeShift = 26; -static const uint32_t OpcodeBits = 6; -static const uint32_t RSShift = 21; -static const uint32_t RSBits = 5; -static const uint32_t RTShift = 16; -static const uint32_t RTBits = 5; -static const uint32_t RDShift = 11; -static const uint32_t RDBits = 5; -static const uint32_t SAShift = 6; -static const uint32_t SABits = 5; -static const uint32_t FunctionShift = 0; -static const uint32_t FunctionBits = 6; -static const uint32_t Imm16Shift = 0; -static const uint32_t Imm16Bits = 16; -static const uint32_t Imm26Shift = 0; -static const uint32_t Imm26Bits = 26; -static const uint32_t Imm28Shift = 0; -static const uint32_t Imm28Bits = 28; -static const uint32_t ImmFieldShift = 2; -static const uint32_t FRBits = 5; -static const uint32_t FRShift = 21; -static const uint32_t FSShift = 11; -static const uint32_t FSBits = 5; -static const uint32_t FTShift = 16; -static const uint32_t FTBits = 5; -static const uint32_t FDShift = 6; -static const uint32_t FDBits = 5; -static const uint32_t FCccShift = 8; -static const uint32_t FCccBits = 3; -static const uint32_t FBccShift = 18; -static const uint32_t FBccBits = 3; -static const uint32_t FBtrueShift = 16; -static const uint32_t FBtrueBits = 1; -static const uint32_t FccMask = 0x7; -static const uint32_t FccShift = 2; - - -// MIPS instruction field bit masks. -static const uint32_t OpcodeMask = ((1 << OpcodeBits) - 1) << OpcodeShift; -static const uint32_t Imm16Mask = ((1 << Imm16Bits) - 1) << Imm16Shift; -static const uint32_t Imm26Mask = ((1 << Imm26Bits) - 1) << Imm26Shift; -static const uint32_t Imm28Mask = ((1 << Imm28Bits) - 1) << Imm28Shift; -static const uint32_t RSMask = ((1 << RSBits) - 1) << RSShift; -static const uint32_t RTMask = ((1 << RTBits) - 1) << RTShift; -static const uint32_t RDMask = ((1 << RDBits) - 1) << RDShift; -static const uint32_t SAMask = ((1 << SABits) - 1) << SAShift; -static const uint32_t FunctionMask = ((1 << FunctionBits) - 1) << FunctionShift; -static const uint32_t RegMask = Registers::Total - 1; - -static const uint32_t BREAK_STACK_UNALIGNED = 1; -static const uint32_t MAX_BREAK_CODE = 1024 - 1; - -class Instruction; -class InstReg; -class InstImm; -class InstJump; - -uint32_t RS(Register r); -uint32_t RT(Register r); -uint32_t RT(uint32_t regCode); -uint32_t RT(FloatRegister r); -uint32_t RD(Register r); -uint32_t RD(FloatRegister r); -uint32_t RD(uint32_t regCode); -uint32_t SA(uint32_t value); -uint32_t SA(FloatRegister r); - -Register toRS (Instruction& i); -Register toRT (Instruction& i); -Register toRD (Instruction& i); -Register toR (Instruction& i); - -// MIPS enums for instruction fields -enum Opcode { - op_special = 0 << OpcodeShift, - op_regimm = 1 << OpcodeShift, - - op_j = 2 << OpcodeShift, - op_jal = 3 << OpcodeShift, - op_beq = 4 << OpcodeShift, - op_bne = 5 << OpcodeShift, - op_blez = 6 << OpcodeShift, - op_bgtz = 7 << OpcodeShift, - - op_addi = 8 << OpcodeShift, - op_addiu = 9 << OpcodeShift, - op_slti = 10 << OpcodeShift, - op_sltiu = 11 << OpcodeShift, - op_andi = 12 << OpcodeShift, - op_ori = 13 << OpcodeShift, - op_xori = 14 << OpcodeShift, - op_lui = 15 << OpcodeShift, - - op_cop1 = 17 << OpcodeShift, - op_cop1x = 19 << OpcodeShift, - - op_beql = 20 << OpcodeShift, - op_bnel = 21 << OpcodeShift, - op_blezl = 22 << OpcodeShift, - op_bgtzl = 23 << OpcodeShift, - - op_special2 = 28 << OpcodeShift, - op_special3 = 31 << OpcodeShift, - - op_lb = 32 << OpcodeShift, - op_lh = 33 << OpcodeShift, - op_lwl = 34 << OpcodeShift, - op_lw = 35 << OpcodeShift, - op_lbu = 36 << OpcodeShift, - op_lhu = 37 << OpcodeShift, - op_lwr = 38 << OpcodeShift, - op_sb = 40 << OpcodeShift, - op_sh = 41 << OpcodeShift, - op_swl = 42 << OpcodeShift, - op_sw = 43 << OpcodeShift, - op_swr = 46 << OpcodeShift, - - op_lwc1 = 49 << OpcodeShift, - op_ldc1 = 53 << OpcodeShift, - - op_swc1 = 57 << OpcodeShift, - op_sdc1 = 61 << OpcodeShift -}; - -enum RSField { - rs_zero = 0 << RSShift, - // cop1 encoding of RS field. - rs_mfc1 = 0 << RSShift, - rs_one = 1 << RSShift, - rs_cfc1 = 2 << RSShift, - rs_mfhc1 = 3 << RSShift, - rs_mtc1 = 4 << RSShift, - rs_ctc1 = 6 << RSShift, - rs_mthc1 = 7 << RSShift, - rs_bc1 = 8 << RSShift, - rs_s = 16 << RSShift, - rs_d = 17 << RSShift, - rs_w = 20 << RSShift, - rs_l = 21 << RSShift, - rs_ps = 22 << RSShift -}; - -enum RTField { - rt_zero = 0 << RTShift, - // regimm encoding of RT field. - rt_bltz = 0 << RTShift, - rt_bgez = 1 << RTShift, - rt_bltzal = 16 << RTShift, - rt_bgezal = 17 << RTShift -}; - -enum FunctionField { - // special encoding of function field. - ff_sll = 0, - ff_movci = 1, - ff_srl = 2, - ff_sra = 3, - ff_sllv = 4, - ff_srlv = 6, - ff_srav = 7, - - ff_jr = 8, - ff_jalr = 9, - ff_movz = 10, - ff_movn = 11, - ff_break = 13, - - ff_mfhi = 16, - ff_mflo = 18, - - ff_mult = 24, - ff_multu = 25, - ff_div = 26, - ff_divu = 27, - - ff_add = 32, - ff_addu = 33, - ff_sub = 34, - ff_subu = 35, - ff_and = 36, - ff_or = 37, - ff_xor = 38, - ff_nor = 39, - - ff_slt = 42, - ff_sltu = 43, - - ff_tge = 48, - ff_tgeu = 49, - ff_tlt = 50, - ff_tltu = 51, - ff_teq = 52, - ff_tne = 54, - - // special2 encoding of function field. - ff_mul = 2, - ff_clz = 32, - ff_clo = 33, - - // special3 encoding of function field. - ff_ext = 0, - ff_ins = 4, - - // cop1 encoding of function field. - ff_add_fmt = 0, - ff_sub_fmt = 1, - ff_mul_fmt = 2, - ff_div_fmt = 3, - ff_sqrt_fmt = 4, - ff_abs_fmt = 5, - ff_mov_fmt = 6, - ff_neg_fmt = 7, - - ff_round_l_fmt = 8, - ff_trunc_l_fmt = 9, - ff_ceil_l_fmt = 10, - ff_floor_l_fmt = 11, - - ff_round_w_fmt = 12, - ff_trunc_w_fmt = 13, - ff_ceil_w_fmt = 14, - ff_floor_w_fmt = 15, - - ff_cvt_s_fmt = 32, - ff_cvt_d_fmt = 33, - ff_cvt_w_fmt = 36, - ff_cvt_l_fmt = 37, - ff_cvt_ps_s = 38, - - ff_c_f_fmt = 48, - ff_c_un_fmt = 49, - ff_c_eq_fmt = 50, - ff_c_ueq_fmt = 51, - ff_c_olt_fmt = 52, - ff_c_ult_fmt = 53, - ff_c_ole_fmt = 54, - ff_c_ule_fmt = 55, - - ff_madd_s = 32, - ff_madd_d = 33, - - ff_null = 0 -}; - -class Operand; - -// A BOffImm16 is a 16 bit immediate that is used for branches. -class BOffImm16 +class Assembler : public AssemblerMIPSShared { - uint32_t data; - - public: - uint32_t encode() { - MOZ_ASSERT(!isInvalid()); - return data; - } - int32_t decode() { - MOZ_ASSERT(!isInvalid()); - return (int32_t(data << 18) >> 16) + 4; - } - - explicit BOffImm16(int offset) - : data ((offset - 4) >> 2 & Imm16Mask) - { - MOZ_ASSERT((offset & 0x3) == 0); - MOZ_ASSERT(IsInRange(offset)); - } - static bool IsInRange(int offset) { - if ((offset - 4) < (INT16_MIN << 2)) - return false; - if ((offset - 4) > (INT16_MAX << 2)) - return false; - return true; - } - static const uint32_t INVALID = 0x00020000; - BOffImm16() - : data(INVALID) - { } - - bool isInvalid() { - return data == INVALID; - } - Instruction* getDest(Instruction* src); - - BOffImm16(InstImm inst); -}; - -// A JOffImm26 is a 26 bit immediate that is used for unconditional jumps. -class JOffImm26 -{ - uint32_t data; - - public: - uint32_t encode() { - MOZ_ASSERT(!isInvalid()); - return data; - } - int32_t decode() { - MOZ_ASSERT(!isInvalid()); - return (int32_t(data << 8) >> 6) + 4; - } - - explicit JOffImm26(int offset) - : data ((offset - 4) >> 2 & Imm26Mask) - { - MOZ_ASSERT((offset & 0x3) == 0); - MOZ_ASSERT(IsInRange(offset)); - } - static bool IsInRange(int offset) { - if ((offset - 4) < -536870912) - return false; - if ((offset - 4) > 536870908) - return false; - return true; - } - static const uint32_t INVALID = 0x20000000; - JOffImm26() - : data(INVALID) - { } - - bool isInvalid() { - return data == INVALID; - } - Instruction* getDest(Instruction* src); - -}; - -class Imm16 -{ - uint16_t value; - - public: - Imm16(); - Imm16(uint32_t imm) - : value(imm) - { } - uint32_t encode() { - return value; - } - int32_t decodeSigned() { - return value; - } - uint32_t decodeUnsigned() { - return value; - } - static bool IsInSignedRange(int32_t imm) { - return imm >= INT16_MIN && imm <= INT16_MAX; - } - static bool IsInUnsignedRange(uint32_t imm) { - return imm <= UINT16_MAX ; - } - static Imm16 Lower (Imm32 imm) { - return Imm16(imm.value & 0xffff); - } - static Imm16 Upper (Imm32 imm) { - return Imm16((imm.value >> 16) & 0xffff); - } -}; - -class Operand -{ - public: - enum Tag { - REG, - FREG, - MEM - }; - - private: - Tag tag : 3; - uint32_t reg : 5; - int32_t offset; - - public: - Operand (Register reg_) - : tag(REG), reg(reg_.code()) - { } - - Operand (FloatRegister freg) - : tag(FREG), reg(freg.code()) - { } - - Operand (Register base, Imm32 off) - : tag(MEM), reg(base.code()), offset(off.value) - { } - - Operand (Register base, int32_t off) - : tag(MEM), reg(base.code()), offset(off) - { } - - Operand (const Address& addr) - : tag(MEM), reg(addr.base.code()), offset(addr.offset) - { } - - Tag getTag() const { - return tag; - } - - Register toReg() const { - MOZ_ASSERT(tag == REG); - return Register::FromCode(reg); - } - - FloatRegister toFReg() const { - MOZ_ASSERT(tag == FREG); - return FloatRegister::FromCode(reg); - } - - void toAddr(Register* r, Imm32* dest) const { - MOZ_ASSERT(tag == MEM); - *r = Register::FromCode(reg); - *dest = Imm32(offset); - } - Address toAddress() const { - MOZ_ASSERT(tag == MEM); - return Address(Register::FromCode(reg), offset); - } - int32_t disp() const { - MOZ_ASSERT(tag == MEM); - return offset; - } - - int32_t base() const { - MOZ_ASSERT(tag == MEM); - return reg; - } - Register baseReg() const { - MOZ_ASSERT(tag == MEM); - return Register::FromCode(reg); - } -}; - -void -PatchJump(CodeLocationJump& jump_, CodeLocationLabel label, - ReprotectCode reprotect = DontReprotect); - -void -PatchBackedge(CodeLocationJump& jump_, CodeLocationLabel label, JitRuntime::BackedgeTarget target); - -class Assembler; -typedef js::jit::AssemblerBuffer<1024, Instruction> MIPSBuffer; - -class MIPSBufferWithExecutableCopy : public MIPSBuffer -{ - public: - void executableCopy(uint8_t* buffer) { - if (this->oom()) - return; - - for (Slice* cur = head; cur != nullptr; cur = cur->getNext()) { - memcpy(buffer, &cur->instructions, cur->length()); - buffer += cur->length(); - } - } -}; - -class Assembler : public AssemblerShared -{ - public: - - enum Condition { - Equal, - NotEqual, - Above, - AboveOrEqual, - Below, - BelowOrEqual, - GreaterThan, - GreaterThanOrEqual, - LessThan, - LessThanOrEqual, - Overflow, - Signed, - NotSigned, - Zero, - NonZero, - Always, - }; - - enum DoubleCondition { - // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. - DoubleOrdered, - DoubleEqual, - DoubleNotEqual, - DoubleGreaterThan, - DoubleGreaterThanOrEqual, - DoubleLessThan, - DoubleLessThanOrEqual, - // If either operand is NaN, these conditions always evaluate to true. - DoubleUnordered, - DoubleEqualOrUnordered, - DoubleNotEqualOrUnordered, - DoubleGreaterThanOrUnordered, - DoubleGreaterThanOrEqualOrUnordered, - DoubleLessThanOrUnordered, - DoubleLessThanOrEqualOrUnordered - }; - - enum FPConditionBit { - FCC0 = 0, - FCC1, - FCC2, - FCC3, - FCC4, - FCC5, - FCC6, - FCC7 - }; - - enum FloatFormat { - SingleFloat, - DoubleFloat - }; - - enum JumpOrCall { - BranchIsJump, - BranchIsCall - }; - - enum FloatTestKind { - TestForTrue, - TestForFalse - }; - - // :( this should be protected, but since CodeGenerator - // wants to use it, It needs to go out here :( - - BufferOffset nextOffset() { - return m_buffer.nextOffset(); - } - - protected: - Instruction * editSrc (BufferOffset bo) { - return m_buffer.getInst(bo); - } - public: - uint32_t actualOffset(uint32_t) const; - uint32_t actualIndex(uint32_t) const; - static uint8_t* PatchableJumpAddress(JitCode* code, uint32_t index); - protected: - - // structure for fixing up pc-relative loads/jumps when a the machine code - // gets moved (executable copy, gc, etc.) - struct RelativePatch - { - // the offset within the code buffer where the value is loaded that - // we want to fix-up - BufferOffset offset; - void* target; - Relocation::Kind kind; - - RelativePatch(BufferOffset offset, void* target, Relocation::Kind kind) - : offset(offset), - target(target), - kind(kind) - { } - }; - - js::Vector codeLabels_; - js::Vector jumps_; - js::Vector longJumps_; - - CompactBufferWriter jumpRelocations_; - CompactBufferWriter dataRelocations_; - CompactBufferWriter preBarriers_; - - MIPSBufferWithExecutableCopy m_buffer; - public: Assembler() - : m_buffer(), - isFinished(false) + : AssemblerMIPSShared() { } - static Condition InvertCondition(Condition cond); - static DoubleCondition InvertCondition(DoubleCondition cond); - // MacroAssemblers hold onto gcthings, so they are traced by the GC. void trace(JSTracer* trc); - void writeRelocation(BufferOffset src) { - jumpRelocations_.writeUnsigned(src.getOffset()); - } - // As opposed to x86/x64 version, the data relocation has to be executed - // before to recover the pointer, and not after. - void writeDataRelocation(ImmGCPtr ptr) { - if (ptr.value) { - if (gc::IsInsideNursery(ptr.value)) - embedsNurseryPointers_ = true; - dataRelocations_.writeUnsigned(nextOffset().getOffset()); - } - } - void writePrebarrierOffset(CodeOffsetLabel label) { - preBarriers_.writeUnsigned(label.offset()); - } - - public: static uintptr_t GetPointer(uint8_t*); - bool oom() const; - - void setPrinter(Sprinter* sp) { - } - - static const Register getStackPointer() { - return StackPointer; - } - - private: - bool isFinished; - public: - void finish(); - void executableCopy(void* buffer); - void copyJumpRelocationTable(uint8_t* dest); - void copyDataRelocationTable(uint8_t* dest); - void copyPreBarrierTable(uint8_t* dest); - - void addCodeLabel(CodeLabel label); - size_t numCodeLabels() const { - return codeLabels_.length(); - } - CodeLabel codeLabel(size_t i) { - return codeLabels_[i]; - } - - // Size of the instruction stream, in bytes. - size_t size() const; - // Size of the jump relocation table, in bytes. - size_t jumpRelocationTableBytes() const; - size_t dataRelocationTableBytes() const; - size_t preBarrierTableBytes() const; - - // Size of the data table, in bytes. - size_t bytesNeeded() const; - - // Write a blob of binary into the instruction stream *OR* - // into a destination address. If dest is nullptr (the default), then the - // instruction gets written into the instruction stream. If dest is not null - // it is interpreted as a pointer to the location that we want the - // instruction to be written. - BufferOffset writeInst(uint32_t x, uint32_t* dest = nullptr); - // A static variant for the cases where we don't want to have an assembler - // object at all. Normally, you would use the dummy (nullptr) object. - static void WriteInstStatic(uint32_t x, uint32_t* dest); - - public: - BufferOffset haltingAlign(int alignment); - BufferOffset nopAlign(int alignment); - BufferOffset as_nop(); - - // Branch and jump instructions - BufferOffset as_bal(BOffImm16 off); - BufferOffset as_b(BOffImm16 off); - - InstImm getBranchCode(JumpOrCall jumpOrCall); - InstImm getBranchCode(Register s, Register t, Condition c); - InstImm getBranchCode(Register s, Condition c); - InstImm getBranchCode(FloatTestKind testKind, FPConditionBit fcc); - - BufferOffset as_j(JOffImm26 off); - BufferOffset as_jal(JOffImm26 off); - - BufferOffset as_jr(Register rs); - BufferOffset as_jalr(Register rs); - - // Arithmetic instructions - BufferOffset as_addu(Register rd, Register rs, Register rt); - BufferOffset as_addiu(Register rd, Register rs, int32_t j); - BufferOffset as_subu(Register rd, Register rs, Register rt); - BufferOffset as_mult(Register rs, Register rt); - BufferOffset as_multu(Register rs, Register rt); - BufferOffset as_div(Register rs, Register rt); - BufferOffset as_divu(Register rs, Register rt); - BufferOffset as_mul(Register rd, Register rs, Register rt); - - // Logical instructions - BufferOffset as_and(Register rd, Register rs, Register rt); - BufferOffset as_or(Register rd, Register rs, Register rt); - BufferOffset as_xor(Register rd, Register rs, Register rt); - BufferOffset as_nor(Register rd, Register rs, Register rt); - - BufferOffset as_andi(Register rd, Register rs, int32_t j); - BufferOffset as_ori(Register rd, Register rs, int32_t j); - BufferOffset as_xori(Register rd, Register rs, int32_t j); - BufferOffset as_lui(Register rd, int32_t j); - - // Shift instructions - // as_sll(zero, zero, x) instructions are reserved as nop - BufferOffset as_sll(Register rd, Register rt, uint16_t sa); - BufferOffset as_sllv(Register rd, Register rt, Register rs); - BufferOffset as_srl(Register rd, Register rt, uint16_t sa); - BufferOffset as_srlv(Register rd, Register rt, Register rs); - BufferOffset as_sra(Register rd, Register rt, uint16_t sa); - BufferOffset as_srav(Register rd, Register rt, Register rs); - BufferOffset as_rotr(Register rd, Register rt, uint16_t sa); - BufferOffset as_rotrv(Register rd, Register rt, Register rs); - - // Load and store instructions - BufferOffset as_lb(Register rd, Register rs, int16_t off); - BufferOffset as_lbu(Register rd, Register rs, int16_t off); - BufferOffset as_lh(Register rd, Register rs, int16_t off); - BufferOffset as_lhu(Register rd, Register rs, int16_t off); - BufferOffset as_lw(Register rd, Register rs, int16_t off); - BufferOffset as_lwl(Register rd, Register rs, int16_t off); - BufferOffset as_lwr(Register rd, Register rs, int16_t off); - BufferOffset as_sb(Register rd, Register rs, int16_t off); - BufferOffset as_sh(Register rd, Register rs, int16_t off); - BufferOffset as_sw(Register rd, Register rs, int16_t off); - BufferOffset as_swl(Register rd, Register rs, int16_t off); - BufferOffset as_swr(Register rd, Register rs, int16_t off); - - // Move from HI/LO register. - BufferOffset as_mfhi(Register rd); - BufferOffset as_mflo(Register rd); - - // Set on less than. - BufferOffset as_slt(Register rd, Register rs, Register rt); - BufferOffset as_sltu(Register rd, Register rs, Register rt); - BufferOffset as_slti(Register rd, Register rs, int32_t j); - BufferOffset as_sltiu(Register rd, Register rs, uint32_t j); - - // Conditional move. - BufferOffset as_movz(Register rd, Register rs, Register rt); - BufferOffset as_movn(Register rd, Register rs, Register rt); - BufferOffset as_movt(Register rd, Register rs, uint16_t cc = 0); - BufferOffset as_movf(Register rd, Register rs, uint16_t cc = 0); - - // Bit twiddling. - BufferOffset as_clz(Register rd, Register rs); - BufferOffset as_ins(Register rt, Register rs, uint16_t pos, uint16_t size); - BufferOffset as_ext(Register rt, Register rs, uint16_t pos, uint16_t size); - - // FP instructions - - // Use these two functions only when you are sure address is aligned. - // Otherwise, use ma_ld and ma_sd. - BufferOffset as_ld(FloatRegister fd, Register base, int32_t off); - BufferOffset as_sd(FloatRegister fd, Register base, int32_t off); - - BufferOffset as_ls(FloatRegister fd, Register base, int32_t off); - BufferOffset as_ss(FloatRegister fd, Register base, int32_t off); - - BufferOffset as_movs(FloatRegister fd, FloatRegister fs); - BufferOffset as_movd(FloatRegister fd, FloatRegister fs); - - BufferOffset as_mtc1(Register rt, FloatRegister fs); - BufferOffset as_mfc1(Register rt, FloatRegister fs); - protected: // This is used to access the odd register form the pair of single // precision registers that make one double register. @@ -979,128 +125,22 @@ class Assembler : public AssemblerShared } public: - // FP convert instructions - BufferOffset as_ceilws(FloatRegister fd, FloatRegister fs); - BufferOffset as_floorws(FloatRegister fd, FloatRegister fs); - BufferOffset as_roundws(FloatRegister fd, FloatRegister fs); - BufferOffset as_truncws(FloatRegister fd, FloatRegister fs); + using AssemblerMIPSShared::bind; + using AssemblerMIPSShared::PatchDataWithValueCheck; - BufferOffset as_ceilwd(FloatRegister fd, FloatRegister fs); - BufferOffset as_floorwd(FloatRegister fd, FloatRegister fs); - BufferOffset as_roundwd(FloatRegister fd, FloatRegister fs); - BufferOffset as_truncwd(FloatRegister fd, FloatRegister fs); - - BufferOffset as_cvtdl(FloatRegister fd, FloatRegister fs); - BufferOffset as_cvtds(FloatRegister fd, FloatRegister fs); - BufferOffset as_cvtdw(FloatRegister fd, FloatRegister fs); - BufferOffset as_cvtld(FloatRegister fd, FloatRegister fs); - BufferOffset as_cvtls(FloatRegister fd, FloatRegister fs); - BufferOffset as_cvtsd(FloatRegister fd, FloatRegister fs); - BufferOffset as_cvtsl(FloatRegister fd, FloatRegister fs); - BufferOffset as_cvtsw(FloatRegister fd, FloatRegister fs); - BufferOffset as_cvtwd(FloatRegister fd, FloatRegister fs); - BufferOffset as_cvtws(FloatRegister fd, FloatRegister fs); - - // FP arithmetic instructions - BufferOffset as_adds(FloatRegister fd, FloatRegister fs, FloatRegister ft); - BufferOffset as_addd(FloatRegister fd, FloatRegister fs, FloatRegister ft); - BufferOffset as_subs(FloatRegister fd, FloatRegister fs, FloatRegister ft); - BufferOffset as_subd(FloatRegister fd, FloatRegister fs, FloatRegister ft); - - BufferOffset as_abss(FloatRegister fd, FloatRegister fs); - BufferOffset as_absd(FloatRegister fd, FloatRegister fs); - BufferOffset as_negs(FloatRegister fd, FloatRegister fs); - BufferOffset as_negd(FloatRegister fd, FloatRegister fs); - - BufferOffset as_muls(FloatRegister fd, FloatRegister fs, FloatRegister ft); - BufferOffset as_muld(FloatRegister fd, FloatRegister fs, FloatRegister ft); - BufferOffset as_divs(FloatRegister fd, FloatRegister fs, FloatRegister ft); - BufferOffset as_divd(FloatRegister fd, FloatRegister fs, FloatRegister ft); - BufferOffset as_sqrts(FloatRegister fd, FloatRegister fs); - BufferOffset as_sqrtd(FloatRegister fd, FloatRegister fs); - - // FP compare instructions - BufferOffset as_cf(FloatFormat fmt, FloatRegister fs, FloatRegister ft, - FPConditionBit fcc = FCC0); - BufferOffset as_cun(FloatFormat fmt, FloatRegister fs, FloatRegister ft, - FPConditionBit fcc = FCC0); - BufferOffset as_ceq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, - FPConditionBit fcc = FCC0); - BufferOffset as_cueq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, - FPConditionBit fcc = FCC0); - BufferOffset as_colt(FloatFormat fmt, FloatRegister fs, FloatRegister ft, - FPConditionBit fcc = FCC0); - BufferOffset as_cult(FloatFormat fmt, FloatRegister fs, FloatRegister ft, - FPConditionBit fcc = FCC0); - BufferOffset as_cole(FloatFormat fmt, FloatRegister fs, FloatRegister ft, - FPConditionBit fcc = FCC0); - BufferOffset as_cule(FloatFormat fmt, FloatRegister fs, FloatRegister ft, - FPConditionBit fcc = FCC0); - - // label operations - void bind(Label* label, BufferOffset boff = BufferOffset()); void bind(RepatchLabel* label); - uint32_t currentOffset() { - return nextOffset().getOffset(); - } - void retarget(Label* label, Label* target); void Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address); - // See Bind - size_t labelOffsetToPatchOffset(size_t offset) { - return actualOffset(offset); - } - - void call(Label* label); - void call(void* target); - - void as_break(uint32_t code); - - public: static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader); static void TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader); - static bool SupportsFloatingPoint() { -#if (defined(__mips_hard_float) && !defined(__mips_single_float)) || defined(JS_SIMULATOR_MIPS32) - return true; -#else - return false; -#endif - } - static bool SupportsSimd() { - return js::jit::SupportsSimd; - } - - protected: - InstImm invertBranch(InstImm branch, BOffImm16 skipOffset); void bind(InstImm* inst, uint32_t branch, uint32_t target); - void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) { - enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind)); - if (kind == Relocation::JITCODE) - writeRelocation(src); - } - - void addLongJump(BufferOffset src) { - enoughMemory_ &= longJumps_.append(src.getOffset()); - } - - public: - size_t numLongJumps() const { - return longJumps_.length(); - } - uint32_t longJump(size_t i) { - return longJumps_[i]; - } // Copy the assembly code to the given buffer, and perform any pending // relocations relying on the target address. void executableCopy(uint8_t* buffer); - void flushBuffer() { - } - static uint32_t PatchWrite_NearCallSize(); - static uint32_t NopSize() { return 4; } static uint32_t ExtractLuiOriValue(Instruction* inst0, Instruction* inst1); static void UpdateLuiOriValue(Instruction* inst0, Instruction* inst1, uint32_t value); @@ -1110,277 +150,15 @@ class Assembler : public AssemblerShared static void PatchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall); static void PatchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue, PatchedImmPtr expectedValue); - static void PatchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue, - ImmPtr expectedValue); - static void PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm); static void PatchInstructionImmediate(uint8_t* code, PatchedImmPtr imm); - static uint32_t AlignDoubleArg(uint32_t offset) { - return (offset + 1U) &~ 1U; - } - - static uint8_t* NextInstruction(uint8_t* instruction, uint32_t* count = nullptr); - - static void ToggleToJmp(CodeLocationLabel inst_); - static void ToggleToCmp(CodeLocationLabel inst_); - static void ToggleCall(CodeLocationLabel inst_, bool enabled); static void UpdateBoundsCheck(uint32_t logHeapSize, Instruction* inst); - void processCodeLabels(uint8_t* rawCode); static int32_t ExtractCodeLabelOffset(uint8_t* code); - - bool bailed() { - return m_buffer.bail(); - } - - void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end, - const Disassembler::HeapAccess& heapAccess) - { - // Implement this if we implement a disassembler. - } }; // Assembler -// sll zero, zero, 0 -const uint32_t NopInst = 0x00000000; - -// An Instruction is a structure for both encoding and decoding any and all -// MIPS instructions. -class Instruction -{ - protected: - uint32_t data; - - // Standard constructor - Instruction (uint32_t data_) : data(data_) { } - - // You should never create an instruction directly. You should create a - // more specific instruction which will eventually call one of these - // constructors for you. - public: - uint32_t encode() const { - return data; - } - - void makeNop() { - data = NopInst; - } - - void setData(uint32_t data) { - this->data = data; - } - - const Instruction & operator=(const Instruction& src) { - data = src.data; - return *this; - } - - // Extract the one particular bit. - uint32_t extractBit(uint32_t bit) { - return (encode() >> bit) & 1; - } - // Extract a bit field out of the instruction - uint32_t extractBitField(uint32_t hi, uint32_t lo) { - return (encode() >> lo) & ((2 << (hi - lo)) - 1); - } - // Since all MIPS instructions have opcode, the opcode - // extractor resides in the base class. - uint32_t extractOpcode() { - return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift); - } - // Return the fields at their original place in the instruction encoding. - Opcode OpcodeFieldRaw() const { - return static_cast(encode() & OpcodeMask); - } - - // Get the next instruction in the instruction stream. - // This does neat things like ignoreconstant pools and their guards. - Instruction* next(); - - // Sometimes, an api wants a uint32_t (or a pointer to it) rather than - // an instruction. raw() just coerces this into a pointer to a uint32_t - const uint32_t* raw() const { return &data; } - uint32_t size() const { return 4; } -}; // Instruction - -// make sure that it is the right size -static_assert(sizeof(Instruction) == 4, "Size of Instruction class has to be 4 bytes."); - -class InstNOP : public Instruction -{ - public: - InstNOP() - : Instruction(NopInst) - { } - -}; - -// Class for register type instructions. -class InstReg : public Instruction -{ - public: - InstReg(Opcode op, Register rd, FunctionField ff) - : Instruction(op | RD(rd) | ff) - { } - InstReg(Opcode op, Register rs, Register rt, FunctionField ff) - : Instruction(op | RS(rs) | RT(rt) | ff) - { } - InstReg(Opcode op, Register rs, Register rt, Register rd, FunctionField ff) - : Instruction(op | RS(rs) | RT(rt) | RD(rd) | ff) - { } - InstReg(Opcode op, Register rs, Register rt, Register rd, uint32_t sa, FunctionField ff) - : Instruction(op | RS(rs) | RT(rt) | RD(rd) | SA(sa) | ff) - { } - InstReg(Opcode op, RSField rs, Register rt, Register rd, uint32_t sa, FunctionField ff) - : Instruction(op | rs | RT(rt) | RD(rd) | SA(sa) | ff) - { } - InstReg(Opcode op, Register rs, RTField rt, Register rd, uint32_t sa, FunctionField ff) - : Instruction(op | RS(rs) | rt | RD(rd) | SA(sa) | ff) - { } - InstReg(Opcode op, Register rs, uint32_t cc, Register rd, uint32_t sa, FunctionField ff) - : Instruction(op | RS(rs) | cc | RD(rd) | SA(sa) | ff) - { } - InstReg(Opcode op, uint32_t code, FunctionField ff) - : Instruction(op | code | ff) - { } - // for float point - InstReg(Opcode op, RSField rs, Register rt, FloatRegister rd) - : Instruction(op | rs | RT(rt) | RD(rd)) - { } - InstReg(Opcode op, RSField rs, Register rt, FloatRegister rd, uint32_t sa, FunctionField ff) - : Instruction(op | rs | RT(rt) | RD(rd) | SA(sa) | ff) - { } - InstReg(Opcode op, RSField rs, Register rt, FloatRegister fs, FloatRegister fd, FunctionField ff) - : Instruction(op | rs | RT(rt) | RD(fs) | SA(fd) | ff) - { } - InstReg(Opcode op, RSField rs, FloatRegister ft, FloatRegister fs, FloatRegister fd, FunctionField ff) - : Instruction(op | rs | RT(ft) | RD(fs) | SA(fd) | ff) - { } - InstReg(Opcode op, RSField rs, FloatRegister ft, FloatRegister fd, uint32_t sa, FunctionField ff) - : Instruction(op | rs | RT(ft) | RD(fd) | SA(sa) | ff) - { } - - uint32_t extractRS () { - return extractBitField(RSShift + RSBits - 1, RSShift); - } - uint32_t extractRT () { - return extractBitField(RTShift + RTBits - 1, RTShift); - } - uint32_t extractRD () { - return extractBitField(RDShift + RDBits - 1, RDShift); - } - uint32_t extractSA () { - return extractBitField(SAShift + SABits - 1, SAShift); - } - uint32_t extractFunctionField () { - return extractBitField(FunctionShift + FunctionBits - 1, FunctionShift); - } -}; - -// Class for branch, load and store instructions with immediate offset. -class InstImm : public Instruction -{ - public: - void extractImm16(BOffImm16* dest); - - InstImm(Opcode op, Register rs, Register rt, BOffImm16 off) - : Instruction(op | RS(rs) | RT(rt) | off.encode()) - { } - InstImm(Opcode op, Register rs, RTField rt, BOffImm16 off) - : Instruction(op | RS(rs) | rt | off.encode()) - { } - InstImm(Opcode op, RSField rs, uint32_t cc, BOffImm16 off) - : Instruction(op | rs | cc | off.encode()) - { } - InstImm(Opcode op, Register rs, Register rt, Imm16 off) - : Instruction(op | RS(rs) | RT(rt) | off.encode()) - { } - InstImm(uint32_t raw) - : Instruction(raw) - { } - // For floating-point loads and stores. - InstImm(Opcode op, Register rs, FloatRegister rt, Imm16 off) - : Instruction(op | RS(rs) | RT(rt) | off.encode()) - { } - - uint32_t extractOpcode() { - return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift); - } - void setOpcode(Opcode op) { - data = (data & ~OpcodeMask) | op; - } - uint32_t extractRS() { - return extractBitField(RSShift + RSBits - 1, RSShift); - } - uint32_t extractRT() { - return extractBitField(RTShift + RTBits - 1, RTShift); - } - void setRT(RTField rt) { - data = (data & ~RTMask) | rt; - } - uint32_t extractImm16Value() { - return extractBitField(Imm16Shift + Imm16Bits - 1, Imm16Shift); - } - void setBOffImm16(BOffImm16 off) { - // Reset immediate field and replace it - data = (data & ~Imm16Mask) | off.encode(); - } - void setImm16(Imm16 off) { - // Reset immediate field and replace it - data = (data & ~Imm16Mask) | off.encode(); - } -}; - -// Class for Jump type instructions. -class InstJump : public Instruction -{ - public: - InstJump(Opcode op, JOffImm26 off) - : Instruction(op | off.encode()) - { } - - uint32_t extractImm26Value() { - return extractBitField(Imm26Shift + Imm26Bits - 1, Imm26Shift); - } -}; - -static const uint32_t NumIntArgRegs = 4; - -static inline bool -GetIntArgReg(uint32_t usedArgSlots, Register* out) -{ - if (usedArgSlots < NumIntArgRegs) { - *out = Register::FromCode(a0.code() + usedArgSlots); - return true; - } - return false; -} - -// Get a register in which we plan to put a quantity that will be used as an -// integer argument. This differs from GetIntArgReg in that if we have no more -// actual argument registers to use we will fall back on using whatever -// CallTempReg* don't overlap the argument registers, and only fail once those -// run out too. -static inline bool -GetTempRegForIntArg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register* out) -{ - // NOTE: We can't properly determine which regs are used if there are - // float arguments. If this is needed, we will have to guess. - MOZ_ASSERT(usedFloatArgs == 0); - - if (GetIntArgReg(usedIntArgs, out)) - return true; - // Unfortunately, we have to assume things about the point at which - // GetIntArgReg returns false, because we need to know how many registers it - // can allocate. - usedIntArgs -= NumIntArgRegs; - if (usedIntArgs >= NumCallTempNonArgRegs) - return false; - *out = CallTempNonArgRegs[usedIntArgs]; - return true; -} - static inline uint32_t GetArgStackDisp(uint32_t usedArgSlots) { diff --git a/js/src/moz.build b/js/src/moz.build index 0a48aa9edf58..09ec6d54be22 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -467,6 +467,7 @@ elif CONFIG['JS_CODEGEN_ARM64']: elif CONFIG['JS_CODEGEN_MIPS32']: UNIFIED_SOURCES += [ 'jit/mips-shared/Architecture-mips-shared.cpp', + 'jit/mips-shared/Assembler-mips-shared.cpp', ] if CONFIG['JS_CODEGEN_MIPS32']: UNIFIED_SOURCES += [ From c62acea8691d19de9b9770531ff8326dab8af444 Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Fri, 11 Sep 2015 18:52:08 -0700 Subject: [PATCH 118/131] Bug 1199491 - Use channel->ascynOpen2 in netwerk/base (r=sicking) --- netwerk/base/nsIncrementalDownload.cpp | 4 ++-- netwerk/base/nsPACMan.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/netwerk/base/nsIncrementalDownload.cpp b/netwerk/base/nsIncrementalDownload.cpp index 8e9817c96036..e56d88982c7c 100644 --- a/netwerk/base/nsIncrementalDownload.cpp +++ b/netwerk/base/nsIncrementalDownload.cpp @@ -268,7 +268,7 @@ nsIncrementalDownload::ProcessTimeout() nsresult rv = NS_NewChannel(getter_AddRefs(channel), mFinalURI, nsContentUtils::GetSystemPrincipal(), - nsILoadInfo::SEC_NORMAL, + nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, nsIContentPolicy::TYPE_OTHER, nullptr, // loadGroup this, // aCallbacks @@ -310,7 +310,7 @@ nsIncrementalDownload::ProcessTimeout() } } - rv = channel->AsyncOpen(this, nullptr); + rv = channel->AsyncOpen2(this); if (NS_FAILED(rv)) return rv; diff --git a/netwerk/base/nsPACMan.cpp b/netwerk/base/nsPACMan.cpp index fe8edaaeb6ec..743bb3ef0252 100644 --- a/netwerk/base/nsPACMan.cpp +++ b/netwerk/base/nsPACMan.cpp @@ -453,7 +453,7 @@ nsPACMan::StartLoading() NS_NewChannel(getter_AddRefs(channel), pacURI, nsContentUtils::GetSystemPrincipal(), - nsILoadInfo::SEC_NORMAL, + nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, nsIContentPolicy::TYPE_OTHER, nullptr, // aLoadGroup nullptr, // aCallbacks @@ -468,7 +468,7 @@ nsPACMan::StartLoading() if (channel) { channel->SetLoadFlags(nsIRequest::LOAD_BYPASS_CACHE); channel->SetNotificationCallbacks(this); - if (NS_SUCCEEDED(channel->AsyncOpen(mLoader, nullptr))) + if (NS_SUCCEEDED(channel->AsyncOpen2(mLoader))) return; } } From 485f77a94cda4c778f7221e854c2a7a17f38078e Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Fri, 11 Sep 2015 18:54:00 -0700 Subject: [PATCH 119/131] Bug 1199491 - Use channel->ascynOpen2 in netwerk/base/nsURIChecker (r=sicking,jduell) --- netwerk/base/nsURIChecker.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/netwerk/base/nsURIChecker.cpp b/netwerk/base/nsURIChecker.cpp index 5a24b2041258..9299dff098eb 100644 --- a/netwerk/base/nsURIChecker.cpp +++ b/netwerk/base/nsURIChecker.cpp @@ -6,10 +6,10 @@ #include "nsURIChecker.h" #include "nsIAuthPrompt.h" #include "nsIHttpChannel.h" +#include "nsContentUtils.h" #include "nsNetUtil.h" #include "nsString.h" #include "nsIAsyncVerifyRedirectCallback.h" -#include "nsNullPrincipal.h" //----------------------------------------------------------------------------- @@ -137,12 +137,10 @@ NS_IMETHODIMP nsURIChecker::Init(nsIURI *aURI) { nsresult rv; - nsCOMPtr nullPrincipal = nsNullPrincipal::Create(); - NS_ENSURE_TRUE(nullPrincipal, NS_ERROR_FAILURE); rv = NS_NewChannel(getter_AddRefs(mChannel), aURI, - nullPrincipal, - nsILoadInfo::SEC_NORMAL, + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, nsIContentPolicy::TYPE_OTHER); NS_ENSURE_SUCCESS(rv, rv); @@ -180,9 +178,9 @@ nsURIChecker::AsyncCheck(nsIRequestObserver *aObserver, // Hook us up to listen to redirects and the like (this creates a reference // cycle!) mChannel->SetNotificationCallbacks(this); - + // and start the request: - nsresult rv = mChannel->AsyncOpen(this, nullptr); + nsresult rv = mChannel->AsyncOpen2(this); if (NS_FAILED(rv)) mChannel = nullptr; else { From 976c25b63cbe12147a06c8b2565c31a5d7fd64b2 Mon Sep 17 00:00:00 2001 From: Botond Ballo Date: Fri, 11 Sep 2015 12:27:49 -0400 Subject: [PATCH 120/131] Bug 1202312 - Use mozilla::Function for the SetAllowedTouchBehavior callback. r=kats --HG-- extra : source : 168244f8869806e0fb6b318a938e46b706972f94 --- dom/ipc/TabChild.cpp | 26 +++++++------------- dom/ipc/TabChild.h | 4 ++-- gfx/layers/apz/util/APZCCallbackHelper.cpp | 4 ++-- gfx/layers/apz/util/APZCCallbackHelper.h | 14 ++++------- widget/nsBaseWidget.cpp | 28 ++++++++-------------- widget/nsBaseWidget.h | 4 ++-- 6 files changed, 29 insertions(+), 51 deletions(-) diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index f25f4e2976c3..d667592148b8 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -599,22 +599,6 @@ TabChild::Create(nsIContentChild* aManager, return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr; } -class TabChildSetAllowedTouchBehaviorCallback : public SetAllowedTouchBehaviorCallback { -public: - explicit TabChildSetAllowedTouchBehaviorCallback(TabChild* aTabChild) - : mTabChild(do_GetWeakReference(static_cast(aTabChild))) - {} - - void Run(uint64_t aInputBlockId, const nsTArray& aFlags) const override { - if (nsCOMPtr tabChild = do_QueryReferent(mTabChild)) { - static_cast(tabChild.get())->SendSetAllowedTouchBehavior(aInputBlockId, aFlags); - } - } - -private: - nsWeakPtr mTabChild; -}; - class TabChildContentReceivedInputBlockCallback : public ContentReceivedInputBlockCallback { public: explicit TabChildContentReceivedInputBlockCallback(TabChild* aTabChild) @@ -649,7 +633,6 @@ TabChild::TabChild(nsIContentChild* aManager, , mOrientation(eScreenOrientation_PortraitPrimary) , mUpdateHitRegion(false) , mIgnoreKeyPressEvent(false) - , mSetAllowedTouchBehaviorCallback(new TabChildSetAllowedTouchBehaviorCallback(this)) , mHasValidInnerSize(false) , mDestroyed(false) , mUniqueId(aTabId) @@ -665,6 +648,15 @@ TabChild::TabChild(nsIContentChild* aManager, // check the other conditions necessary for enabling APZ. mAsyncPanZoomEnabled = gfxPlatform::AsyncPanZoomEnabled(); + nsWeakPtr weakPtrThis(do_GetWeakReference(static_cast(this))); // for capture by the lambda + mSetAllowedTouchBehaviorCallback = [weakPtrThis](uint64_t aInputBlockId, + const nsTArray& aFlags) + { + if (nsCOMPtr tabChild = do_QueryReferent(weakPtrThis)) { + static_cast(tabChild.get())->SendSetAllowedTouchBehavior(aInputBlockId, aFlags); + } + }; + // preloaded TabChild should not be added to child map if (mUniqueId) { MOZ_ASSERT(NestedTabChildMap().find(mUniqueId) == NestedTabChildMap().end()); diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index 88a08aa6d545..1bf190ae2771 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -32,6 +32,7 @@ #include "mozilla/EventDispatcher.h" #include "mozilla/EventForwards.h" #include "mozilla/layers/CompositorTypes.h" +#include "mozilla/layers/APZCCallbackHelper.h" #include "nsIWebBrowserChrome3.h" #include "mozilla/dom/ipc/IdType.h" #include "AudioChannelService.h" @@ -49,7 +50,6 @@ namespace layers { class APZEventState; class ImageCompositeNotification; struct SetTargetAPZCCallback; -struct SetAllowedTouchBehaviorCallback; } // namespace layers namespace widget { @@ -635,7 +635,7 @@ private: bool mIgnoreKeyPressEvent; nsRefPtr mAPZEventState; - nsRefPtr mSetAllowedTouchBehaviorCallback; + SetAllowedTouchBehaviorCallback mSetAllowedTouchBehaviorCallback; bool mHasValidInnerSize; bool mDestroyed; // Position of tab, relative to parent widget (typically the window) diff --git a/gfx/layers/apz/util/APZCCallbackHelper.cpp b/gfx/layers/apz/util/APZCCallbackHelper.cpp index d80e36a2b1ab..8c3fc431a380 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.cpp +++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp @@ -787,13 +787,13 @@ APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification( nsIWidget* aWidget, const WidgetTouchEvent& aEvent, uint64_t aInputBlockId, - const nsRefPtr& aCallback) + const SetAllowedTouchBehaviorCallback& aCallback) { nsTArray flags; for (uint32_t i = 0; i < aEvent.touches.Length(); i++) { flags.AppendElement(widget::ContentHelper::GetAllowedTouchBehavior(aWidget, aEvent.touches[i]->mRefPoint)); } - aCallback->Run(aInputBlockId, flags); + aCallback(aInputBlockId, flags); } void diff --git a/gfx/layers/apz/util/APZCCallbackHelper.h b/gfx/layers/apz/util/APZCCallbackHelper.h index b7854a4b4e23..be3a0b175c53 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.h +++ b/gfx/layers/apz/util/APZCCallbackHelper.h @@ -8,6 +8,7 @@ #include "FrameMetrics.h" #include "mozilla/EventForwards.h" +#include "mozilla/Function.h" #include "mozilla/layers/APZUtils.h" #include "nsIDOMWindowUtils.h" @@ -22,15 +23,8 @@ template class nsRefPtr; namespace mozilla { namespace layers { -/* A base class for callbacks to be passed to - * APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification. */ -struct SetAllowedTouchBehaviorCallback { -public: - NS_INLINE_DECL_REFCOUNTING(SetAllowedTouchBehaviorCallback) - virtual void Run(uint64_t aInputBlockId, const nsTArray& aFlags) const = 0; -protected: - virtual ~SetAllowedTouchBehaviorCallback() {} -}; +typedef Function&)> + SetAllowedTouchBehaviorCallback; /* This class contains some helper methods that facilitate implementing the GeckoContentController callback interface required by the AsyncPanZoomController. @@ -162,7 +156,7 @@ public: static void SendSetAllowedTouchBehaviorNotification(nsIWidget* aWidget, const WidgetTouchEvent& aEvent, uint64_t aInputBlockId, - const nsRefPtr& aCallback); + const SetAllowedTouchBehaviorCallback& aCallback); /* Notify content of a mouse scroll testing event. */ static void NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent); diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index 311d932376c7..856d75bca107 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -873,23 +873,6 @@ nsBaseWidget::CreateRootContentController() return controller.forget(); } -class ChromeProcessSetAllowedTouchBehaviorCallback : public SetAllowedTouchBehaviorCallback { -public: - explicit ChromeProcessSetAllowedTouchBehaviorCallback(APZCTreeManager* aTreeManager) - : mTreeManager(aTreeManager) - {} - - void Run(uint64_t aInputBlockId, const nsTArray& aFlags) const override { - MOZ_ASSERT(NS_IsMainThread()); - APZThreadUtils::RunOnControllerThread(NewRunnableMethod( - mTreeManager.get(), &APZCTreeManager::SetAllowedTouchBehavior, - aInputBlockId, aFlags)); - } - -private: - nsRefPtr mTreeManager; -}; - class ChromeProcessContentReceivedInputBlockCallback : public ContentReceivedInputBlockCallback { public: explicit ChromeProcessContentReceivedInputBlockCallback(APZCTreeManager* aTreeManager) @@ -916,7 +899,16 @@ void nsBaseWidget::ConfigureAPZCTreeManager() mAPZC->SetDPI(GetDPI()); mAPZEventState = new APZEventState(this, new ChromeProcessContentReceivedInputBlockCallback(mAPZC)); - mSetAllowedTouchBehaviorCallback = new ChromeProcessSetAllowedTouchBehaviorCallback(mAPZC); + + nsRefPtr treeManager = mAPZC; // for capture by the lambda + mSetAllowedTouchBehaviorCallback = [treeManager](uint64_t aInputBlockId, + const nsTArray& aFlags) + { + MOZ_ASSERT(NS_IsMainThread()); + APZThreadUtils::RunOnControllerThread(NewRunnableMethod( + treeManager.get(), &APZCTreeManager::SetAllowedTouchBehavior, + aInputBlockId, aFlags)); + }; nsRefPtr controller = CreateRootContentController(); if (controller) { diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h index 8262f1eb9f14..91f0c368cccb 100644 --- a/widget/nsBaseWidget.h +++ b/widget/nsBaseWidget.h @@ -7,6 +7,7 @@ #include "mozilla/EventForwards.h" #include "mozilla/WidgetUtils.h" +#include "mozilla/layers/APZCCallbackHelper.h" #include "nsRect.h" #include "nsIWidget.h" #include "nsWidgetsCID.h" @@ -39,7 +40,6 @@ class APZCTreeManager; class GeckoContentController; class APZEventState; struct ScrollableLayerGuid; -struct SetAllowedTouchBehaviorCallback; } // namespace layers class CompositorVsyncDispatcher; @@ -498,7 +498,7 @@ protected: nsRefPtr mCompositorVsyncDispatcher; nsRefPtr mAPZC; nsRefPtr mAPZEventState; - nsRefPtr mSetAllowedTouchBehaviorCallback; + SetAllowedTouchBehaviorCallback mSetAllowedTouchBehaviorCallback; nsRefPtr mShutdownObserver; nsRefPtr mTextEventDispatcher; nsCursor mCursor; From b979ad25d3ac0b1e878b878015f8fe23e0f79f14 Mon Sep 17 00:00:00 2001 From: Botond Ballo Date: Fri, 11 Sep 2015 12:52:43 -0400 Subject: [PATCH 121/131] Bug 1202312 - Use mozilla::Function for the ContentReceivedInputBlock callback. r=kats --HG-- extra : source : d0d8d51c89955d70c72591b424e18790973e8805 --- dom/ipc/TabChild.cpp | 29 +++++++++------------- gfx/layers/apz/util/APZEventState.cpp | 15 ++++++------ gfx/layers/apz/util/APZEventState.h | 20 ++++++--------- widget/nsBaseWidget.cpp | 35 ++++++++++++--------------- 4 files changed, 43 insertions(+), 56 deletions(-) diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index d667592148b8..473e05b313a3 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -37,6 +37,7 @@ #include "mozilla/layout/RenderFrameChild.h" #include "mozilla/LookAndFeel.h" #include "mozilla/MouseEvents.h" +#include "mozilla/Move.h" #include "mozilla/PWebBrowserPersistDocumentChild.h" #include "mozilla/Services.h" #include "mozilla/StaticPtr.h" @@ -599,21 +600,6 @@ TabChild::Create(nsIContentChild* aManager, return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr; } -class TabChildContentReceivedInputBlockCallback : public ContentReceivedInputBlockCallback { -public: - explicit TabChildContentReceivedInputBlockCallback(TabChild* aTabChild) - : mTabChild(do_GetWeakReference(static_cast(aTabChild))) - {} - - void Run(const ScrollableLayerGuid& aGuid, uint64_t aInputBlockId, bool aPreventDefault) const override { - if (nsCOMPtr tabChild = do_QueryReferent(mTabChild)) { - static_cast(tabChild.get())->SendContentReceivedInputBlock(aGuid, aInputBlockId, aPreventDefault); - } - } -private: - nsWeakPtr mTabChild; -}; - TabChild::TabChild(nsIContentChild* aManager, const TabId& aTabId, const TabContext& aContext, @@ -852,8 +838,17 @@ TabChild::Init() do_QueryInterface(window->GetChromeEventHandler()); docShell->SetChromeEventHandler(chromeHandler); - mAPZEventState = new APZEventState(mPuppetWidget, - new TabChildContentReceivedInputBlockCallback(this)); + nsWeakPtr weakPtrThis = do_GetWeakReference(static_cast(this)); // for capture by the lambda + ContentReceivedInputBlockCallback callback( + [weakPtrThis](const ScrollableLayerGuid& aGuid, + uint64_t aInputBlockId, + bool aPreventDefault) + { + if (nsCOMPtr tabChild = do_QueryReferent(weakPtrThis)) { + static_cast(tabChild.get())->SendContentReceivedInputBlock(aGuid, aInputBlockId, aPreventDefault); + } + }); + mAPZEventState = new APZEventState(mPuppetWidget, Move(callback)); return NS_OK; } diff --git a/gfx/layers/apz/util/APZEventState.cpp b/gfx/layers/apz/util/APZEventState.cpp index 3966792054ec..f954c7f746b4 100644 --- a/gfx/layers/apz/util/APZEventState.cpp +++ b/gfx/layers/apz/util/APZEventState.cpp @@ -9,6 +9,7 @@ #include "APZCCallbackHelper.h" #include "gfxPrefs.h" #include "mozilla/BasicEvents.h" +#include "mozilla/Move.h" #include "mozilla/Preferences.h" #include "mozilla/TouchEvents.h" #include "mozilla/layers/APZCCallbackHelper.h" @@ -91,10 +92,10 @@ static int32_t sActiveDurationMs = 10; static bool sActiveDurationMsSet = false; APZEventState::APZEventState(nsIWidget* aWidget, - const nsRefPtr& aCallback) + ContentReceivedInputBlockCallback&& aCallback) : mWidget(nullptr) // initialized in constructor body , mActiveElementManager(new ActiveElementManager()) - , mContentReceivedInputBlockCallback(aCallback) + , mContentReceivedInputBlockCallback(Move(aCallback)) , mPendingTouchPreventedResponse(false) , mPendingTouchPreventedBlockId(0) , mEndTouchIsClick(false) @@ -244,7 +245,7 @@ APZEventState::ProcessLongTap(const nsCOMPtr& aPresShell, APZES_LOG("MOZLONGTAP event handled: %d\n", eventHandled); } - mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, eventHandled); + mContentReceivedInputBlockCallback(aGuid, aInputBlockId, eventHandled); } void @@ -266,13 +267,13 @@ APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent, if (mPendingTouchPreventedResponse) { // We can enter here if we get two TOUCH_STARTs in a row and didn't // respond to the first one. Respond to it now. - mContentReceivedInputBlockCallback->Run(mPendingTouchPreventedGuid, + mContentReceivedInputBlockCallback(mPendingTouchPreventedGuid, mPendingTouchPreventedBlockId, false); sentContentResponse = true; mPendingTouchPreventedResponse = false; } if (isTouchPrevented) { - mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, isTouchPrevented); + mContentReceivedInputBlockCallback(aGuid, aInputBlockId, isTouchPrevented); sentContentResponse = true; } else { mPendingTouchPreventedResponse = true; @@ -328,7 +329,7 @@ APZEventState::ProcessWheelEvent(const WidgetWheelEvent& aEvent, // scroll by setting defaultPrevented to true. bool defaultPrevented = aEvent.mFlags.mDefaultPrevented || aEvent.TriggersSwipe(); - mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, defaultPrevented); + mContentReceivedInputBlockCallback(aGuid, aInputBlockId, defaultPrevented); } void @@ -408,7 +409,7 @@ bool APZEventState::SendPendingTouchPreventedResponse(bool aPreventDefault) { if (mPendingTouchPreventedResponse) { - mContentReceivedInputBlockCallback->Run(mPendingTouchPreventedGuid, + mContentReceivedInputBlockCallback(mPendingTouchPreventedGuid, mPendingTouchPreventedBlockId, aPreventDefault); mPendingTouchPreventedResponse = false; return true; diff --git a/gfx/layers/apz/util/APZEventState.h b/gfx/layers/apz/util/APZEventState.h index 43902817189a..95257b442216 100644 --- a/gfx/layers/apz/util/APZEventState.h +++ b/gfx/layers/apz/util/APZEventState.h @@ -11,11 +11,12 @@ #include "FrameMetrics.h" // for ScrollableLayerGuid #include "Units.h" #include "mozilla/EventForwards.h" +#include "mozilla/Function.h" #include "mozilla/layers/GeckoContentController.h" // for APZStateChange +#include "mozilla/nsRefPtr.h" #include "nsCOMPtr.h" #include "nsISupportsImpl.h" // for NS_INLINE_DECL_REFCOUNTING #include "nsIWeakReferenceUtils.h" // for nsWeakPtr -#include "mozilla/nsRefPtr.h" template class nsCOMPtr; class nsIDocument; @@ -27,15 +28,10 @@ namespace layers { class ActiveElementManager; -struct ContentReceivedInputBlockCallback { -public: - NS_INLINE_DECL_REFCOUNTING(ContentReceivedInputBlockCallback); - virtual void Run(const ScrollableLayerGuid& aGuid, - uint64_t aInputBlockId, - bool aPreventDefault) const = 0; -protected: - virtual ~ContentReceivedInputBlockCallback() {} -}; +typedef Function + ContentReceivedInputBlockCallback; /** * A content-side component that keeps track of state for handling APZ @@ -46,7 +42,7 @@ class APZEventState { typedef FrameMetrics::ViewID ViewID; public: APZEventState(nsIWidget* aWidget, - const nsRefPtr& aCallback); + ContentReceivedInputBlockCallback&& aCallback); NS_INLINE_DECL_REFCOUNTING(APZEventState); @@ -76,7 +72,7 @@ private: private: nsWeakPtr mWidget; nsRefPtr mActiveElementManager; - nsRefPtr mContentReceivedInputBlockCallback; + ContentReceivedInputBlockCallback mContentReceivedInputBlockCallback; bool mPendingTouchPreventedResponse; ScrollableLayerGuid mPendingTouchPreventedGuid; uint64_t mPendingTouchPreventedBlockId; diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index 856d75bca107..94953dbe2cea 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -52,6 +52,7 @@ #include "mozilla/layers/InputAPZContext.h" #include "mozilla/layers/APZCCallbackHelper.h" #include "mozilla/dom/TabParent.h" +#include "mozilla/Move.h" #include "mozilla/Services.h" #include "mozilla/Snprintf.h" #include "nsRefPtrHashtable.h" @@ -873,23 +874,6 @@ nsBaseWidget::CreateRootContentController() return controller.forget(); } -class ChromeProcessContentReceivedInputBlockCallback : public ContentReceivedInputBlockCallback { -public: - explicit ChromeProcessContentReceivedInputBlockCallback(APZCTreeManager* aTreeManager) - : mTreeManager(aTreeManager) - {} - - void Run(const ScrollableLayerGuid& aGuid, uint64_t aInputBlockId, bool aPreventDefault) const override { - MOZ_ASSERT(NS_IsMainThread()); - APZThreadUtils::RunOnControllerThread(NewRunnableMethod( - mTreeManager.get(), &APZCTreeManager::ContentReceivedInputBlock, - aInputBlockId, aPreventDefault)); - } - -private: - nsRefPtr mTreeManager; -}; - void nsBaseWidget::ConfigureAPZCTreeManager() { MOZ_ASSERT(mAPZC); @@ -897,10 +881,21 @@ void nsBaseWidget::ConfigureAPZCTreeManager() ConfigureAPZControllerThread(); mAPZC->SetDPI(GetDPI()); - mAPZEventState = new APZEventState(this, - new ChromeProcessContentReceivedInputBlockCallback(mAPZC)); - nsRefPtr treeManager = mAPZC; // for capture by the lambda + nsRefPtr treeManager = mAPZC; // for capture by the lambdas + + ContentReceivedInputBlockCallback callback( + [treeManager](const ScrollableLayerGuid& aGuid, + uint64_t aInputBlockId, + bool aPreventDefault) + { + MOZ_ASSERT(NS_IsMainThread()); + APZThreadUtils::RunOnControllerThread(NewRunnableMethod( + treeManager.get(), &APZCTreeManager::ContentReceivedInputBlock, + aInputBlockId, aPreventDefault)); + }); + mAPZEventState = new APZEventState(this, mozilla::Move(callback)); + mSetAllowedTouchBehaviorCallback = [treeManager](uint64_t aInputBlockId, const nsTArray& aFlags) { From 1462347083140ff073214134322f723ebed82398 Mon Sep 17 00:00:00 2001 From: Botond Ballo Date: Sun, 6 Sep 2015 23:29:15 -0400 Subject: [PATCH 122/131] Bug 1202312 - Remove an old forward declaration and typedef. r=kats --HG-- extra : source : 8c0ad47c7db2a004355d8074b6ab868ac5c0aeb6 --- dom/ipc/TabChild.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index 1bf190ae2771..1ec8aedfd65d 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -49,7 +49,6 @@ class RenderFrameChild; namespace layers { class APZEventState; class ImageCompositeNotification; -struct SetTargetAPZCCallback; } // namespace layers namespace widget { @@ -230,7 +229,6 @@ class TabChild final : public TabChildBase, typedef mozilla::dom::ClonedMessageData ClonedMessageData; typedef mozilla::layout::RenderFrameChild RenderFrameChild; typedef mozilla::layers::APZEventState APZEventState; - typedef mozilla::layers::SetTargetAPZCCallback SetTargetAPZCCallback; typedef mozilla::layers::SetAllowedTouchBehaviorCallback SetAllowedTouchBehaviorCallback; public: From 07af4dc59f7d104dacf13aa899055d527e165d08 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Fri, 11 Sep 2015 15:06:37 -0400 Subject: [PATCH 123/131] Bug 1204068 - Update the clang used for OSX cross compiles to the latest that we use on Linux64; r=ted --- .../tooltool-manifests/macosx64/cross-releng.manifest | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/browser/config/tooltool-manifests/macosx64/cross-releng.manifest b/browser/config/tooltool-manifests/macosx64/cross-releng.manifest index d8ffa2d0e7ef..c66e36ffe471 100644 --- a/browser/config/tooltool-manifests/macosx64/cross-releng.manifest +++ b/browser/config/tooltool-manifests/macosx64/cross-releng.manifest @@ -1,13 +1,13 @@ [ { -"clang_version": "r183744" +"clang_version": "r241406" }, { -"size": 70350828, -"digest": "6cd04e8ec44c6fef159349c22bd0476891e4a2d46479f9586283eaf3305e42f79c720d40dfec0e78d8899c1651189b12e285de60862ffd0612b0dac7a0c336c6", +"size": 100307285, +"digest": "4d147d0072a928945fc1e938f39a5d0a9d3c676399c09e092c8750b2f973cdbbebda8d94d4d05805fae74a5c49c54263dc22b8b443c23c9a0ae830a261d3cf30", "algorithm": "sha512", -"unpack": true, -"filename": "clang.tar.bz2" +"filename": "clang.tar.bz2", +"unpack": true }, { "size": 80458572, From be9cbbe31803cc93fa9f507b39c93157a7ed1359 Mon Sep 17 00:00:00 2001 From: Jon Droniak Date: Fri, 11 Sep 2015 11:26:33 -0700 Subject: [PATCH 124/131] Bug 1199796 - Refactor Request and XHR request method validation. r=nsm --HG-- extra : commitid : 264lZKhsGRV extra : rebase_source : ad9ff02f24f648b87da4d00b03dfdfd9e26d45e7 --- dom/base/nsXMLHttpRequest.cpp | 29 ++++----------------------- dom/fetch/FetchUtil.cpp | 37 +++++++++++++++++++++++++++++++++++ dom/fetch/FetchUtil.h | 28 ++++++++++++++++++++++++++ dom/fetch/Request.cpp | 24 ++++++----------------- dom/fetch/moz.build | 2 ++ 5 files changed, 77 insertions(+), 43 deletions(-) create mode 100644 dom/fetch/FetchUtil.cpp create mode 100644 dom/fetch/FetchUtil.h diff --git a/dom/base/nsXMLHttpRequest.cpp b/dom/base/nsXMLHttpRequest.cpp index dbd0d69c7d1c..33d0dfaa9fd0 100644 --- a/dom/base/nsXMLHttpRequest.cpp +++ b/dom/base/nsXMLHttpRequest.cpp @@ -13,6 +13,7 @@ #include "mozilla/CheckedInt.h" #include "mozilla/dom/BlobSet.h" #include "mozilla/dom/File.h" +#include "mozilla/dom/FetchUtil.h" #include "mozilla/dom/XMLHttpRequestUploadBinding.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventListenerManager.h" @@ -1617,31 +1618,10 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url, NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED); - // Disallow HTTP/1.1 TRACE method (see bug 302489) - // and MS IIS equivalent TRACK (see bug 381264) - // and CONNECT - if (inMethod.LowerCaseEqualsLiteral("trace") || - inMethod.LowerCaseEqualsLiteral("connect") || - inMethod.LowerCaseEqualsLiteral("track")) { - return NS_ERROR_DOM_SECURITY_ERR; - } - nsAutoCString method; - // GET, POST, DELETE, HEAD, OPTIONS, PUT methods normalized to upper case - if (inMethod.LowerCaseEqualsLiteral("get")) { - method.AssignLiteral("GET"); - } else if (inMethod.LowerCaseEqualsLiteral("post")) { - method.AssignLiteral("POST"); - } else if (inMethod.LowerCaseEqualsLiteral("delete")) { - method.AssignLiteral("DELETE"); - } else if (inMethod.LowerCaseEqualsLiteral("head")) { - method.AssignLiteral("HEAD"); - } else if (inMethod.LowerCaseEqualsLiteral("options")) { - method.AssignLiteral("OPTIONS"); - } else if (inMethod.LowerCaseEqualsLiteral("put")) { - method.AssignLiteral("PUT"); - } else { - method = inMethod; // other methods are not normalized + nsresult rv = FetchUtil::GetValidRequestMethod(inMethod, method); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; } // sync request is not allowed using withCredential or responseType @@ -1662,7 +1642,6 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url, return NS_ERROR_DOM_INVALID_ACCESS_ERR; } - nsresult rv; nsCOMPtr uri; if (mState & (XML_HTTP_REQUEST_OPENED | diff --git a/dom/fetch/FetchUtil.cpp b/dom/fetch/FetchUtil.cpp new file mode 100644 index 000000000000..3e198e352565 --- /dev/null +++ b/dom/fetch/FetchUtil.cpp @@ -0,0 +1,37 @@ +#include "FetchUtil.h" +#include "nsError.h" +#include "nsString.h" + +namespace mozilla { +namespace dom { + +// static +nsresult +FetchUtil::GetValidRequestMethod(const nsACString& aMethod, nsCString& outMethod) +{ + nsAutoCString upperCaseMethod(aMethod); + ToUpperCase(upperCaseMethod); + if (upperCaseMethod.EqualsLiteral("CONNECT") || + upperCaseMethod.EqualsLiteral("TRACE") || + upperCaseMethod.EqualsLiteral("TRACK") || + !NS_IsValidHTTPToken(aMethod)) { + outMethod.SetIsVoid(true); + return NS_ERROR_DOM_SECURITY_ERR; + } + + if (upperCaseMethod.EqualsLiteral("DELETE") || + upperCaseMethod.EqualsLiteral("GET") || + upperCaseMethod.EqualsLiteral("HEAD") || + upperCaseMethod.EqualsLiteral("OPTIONS") || + upperCaseMethod.EqualsLiteral("POST") || + upperCaseMethod.EqualsLiteral("PUT")) { + outMethod = upperCaseMethod; + } + else { + outMethod = aMethod; // Case unchanged for non-standard methods + } + return NS_OK; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/fetch/FetchUtil.h b/dom/fetch/FetchUtil.h new file mode 100644 index 000000000000..b60cbc07a976 --- /dev/null +++ b/dom/fetch/FetchUtil.h @@ -0,0 +1,28 @@ +#ifndef mozilla_dom_FetchUtil_h +#define mozilla_dom_FetchUtil_h + +#include "nsString.h" +#include "nsError.h" + +namespace mozilla { +namespace dom { + +class FetchUtil final +{ +private: + FetchUtil() = delete; + +public: + /** + * Sets outMethod to a valid HTTP request method string based on an input method. + * Implements checks and normalization as specified by the Fetch specification. + * Returns NS_ERROR_DOM_SECURITY_ERR if the method is invalid. + * Otherwise returns NS_OK and the normalized method via outMethod. + */ + static nsresult + GetValidRequestMethod(const nsACString& aMethod, nsCString& outMethod); +}; + +} // namespace dom +} // namespace mozilla +#endif diff --git a/dom/fetch/Request.cpp b/dom/fetch/Request.cpp index 9f0674676bc2..18572542bb2d 100644 --- a/dom/fetch/Request.cpp +++ b/dom/fetch/Request.cpp @@ -12,6 +12,7 @@ #include "mozilla/ErrorResult.h" #include "mozilla/dom/Headers.h" #include "mozilla/dom/Fetch.h" +#include "mozilla/dom/FetchUtil.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/URL.h" #include "mozilla/dom/WorkerPrivate.h" @@ -298,34 +299,21 @@ Request::Constructor(const GlobalObject& aGlobal, // Request constructor step 14. if (aInit.mMethod.WasPassed()) { nsAutoCString method(aInit.mMethod.Value()); - nsAutoCString upperCaseMethod = method; - ToUpperCase(upperCaseMethod); // Step 14.1. Disallow forbidden methods, and anything that is not a HTTP // token, since HTTP states that Method may be any of the defined values or // a token (extension method). - if (upperCaseMethod.EqualsLiteral("CONNECT") || - upperCaseMethod.EqualsLiteral("TRACE") || - upperCaseMethod.EqualsLiteral("TRACK") || - !NS_IsValidHTTPToken(method)) { + nsAutoCString outMethod; + nsresult rv = FetchUtil::GetValidRequestMethod(method, outMethod); + if (NS_FAILED(rv)) { NS_ConvertUTF8toUTF16 label(method); aRv.ThrowTypeError(MSG_INVALID_REQUEST_METHOD, &label); return nullptr; } // Step 14.2 - if (upperCaseMethod.EqualsLiteral("DELETE") || - upperCaseMethod.EqualsLiteral("GET") || - upperCaseMethod.EqualsLiteral("HEAD") || - upperCaseMethod.EqualsLiteral("POST") || - upperCaseMethod.EqualsLiteral("PUT") || - upperCaseMethod.EqualsLiteral("OPTIONS")) { - request->ClearCreatedByFetchEvent(); - request->SetMethod(upperCaseMethod); - } else { - request->ClearCreatedByFetchEvent(); - request->SetMethod(method); - } + request->ClearCreatedByFetchEvent(); + request->SetMethod(outMethod); } nsRefPtr requestHeaders = request->Headers(); diff --git a/dom/fetch/moz.build b/dom/fetch/moz.build index 102e0e18dc33..9b3e60ddcc54 100644 --- a/dom/fetch/moz.build +++ b/dom/fetch/moz.build @@ -8,6 +8,7 @@ EXPORTS.mozilla.dom += [ 'ChannelInfo.h', 'Fetch.h', 'FetchDriver.h', + 'FetchUtil.h', 'Headers.h', 'InternalHeaders.h', 'InternalRequest.h', @@ -20,6 +21,7 @@ UNIFIED_SOURCES += [ 'ChannelInfo.cpp', 'Fetch.cpp', 'FetchDriver.cpp', + 'FetchUtil.cpp', 'Headers.cpp', 'InternalHeaders.cpp', 'InternalRequest.cpp', From 2842b5f00268b9466401a3be83e8b032ba512025 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Sat, 12 Sep 2015 16:23:08 +1000 Subject: [PATCH 125/131] Bug 1185115: P2. replace all stagefright::Vector with nsTArray. r=kentuckyfriedtakahe --- .../media/libstagefright/MPEG4Extractor.cpp | 123 +++++++++--------- .../av/media/libstagefright/SampleTable.cpp | 48 ++++--- .../libstagefright/include/MPEG4Extractor.h | 8 +- .../libstagefright/include/SampleTable.h | 9 +- 4 files changed, 97 insertions(+), 91 deletions(-) diff --git a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp index b57072456605..dfc71a612120 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp @@ -38,7 +38,6 @@ #include #include #include -#include "nsTArray.h" static const uint32_t kMAX_ALLOCATION = (SIZE_MAX < INT32_MAX ? SIZE_MAX : INT32_MAX) - 128; @@ -52,7 +51,7 @@ public: const sp &dataSource, int32_t timeScale, const sp &sampleTable, - Vector &sidx, + nsTArray &sidx, MPEG4Extractor::TrackExtends &trackExtends); virtual status_t start(MetaData *params = NULL); @@ -76,7 +75,7 @@ private: sp mSampleTable; uint32_t mCurrentSampleIndex; uint32_t mCurrentFragmentIndex; - Vector &mSegments; + nsTArray &mSegments; bool mLookedForMoof; off64_t mFirstMoofOffset; off64_t mCurrentMoofOffset; @@ -149,12 +148,12 @@ private: int32_t ctsOffset; uint32_t flags; uint8_t iv[16]; - Vector clearsizes; - Vector encryptedsizes; + nsTArray clearsizes; + nsTArray encryptedsizes; bool isSync() const { return !(flags & 0x1010000); } }; - Vector mCurrentSamples; + nsTArray mCurrentSamples; MPEG4Extractor::TrackExtends mTrackExtends; // XXX hack -- demuxer expects a track's trun to be seen before saio or @@ -164,8 +163,8 @@ private: off64_t mStart; off64_t mSize; }; - Vector mDeferredSaiz; - Vector mDeferredSaio; + nsTArray mDeferredSaiz; + nsTArray mDeferredSaio; MPEG4Source(const MPEG4Source &); MPEG4Source &operator=(const MPEG4Source &); @@ -405,7 +404,7 @@ MPEG4Extractor::~MPEG4Extractor() { } mFirstSINF = NULL; - for (size_t i = 0; i < mPssh.size(); i++) { + for (size_t i = 0; i < mPssh.Length(); i++) { delete [] mPssh[i].data; } } @@ -509,13 +508,13 @@ status_t MPEG4Extractor::readMetaData() { // copy pssh data into file metadata int psshsize = 0; - for (size_t i = 0; i < mPssh.size(); i++) { + for (size_t i = 0; i < mPssh.Length(); i++) { psshsize += 20 + mPssh[i].datalen; } if (psshsize) { char *buf = (char*)malloc(psshsize); char *ptr = buf; - for (size_t i = 0; i < mPssh.size(); i++) { + for (size_t i = 0; i < mPssh.Length(); i++) { memcpy(ptr, mPssh[i].uuid, 20); // uuid + length memcpy(ptr + 20, mPssh[i].data, mPssh[i].datalen); ptr += (20 + mPssh[i].datalen); @@ -695,24 +694,24 @@ status_t MPEG4Extractor::parseDrmSINF(off64_t *offset, off64_t data_offset) { } struct PathAdder { - PathAdder(Vector *path, uint32_t chunkType) + PathAdder(nsTArray *path, uint32_t chunkType) : mPath(path) { - mPath->push(chunkType); + mPath->AppendElement(chunkType); } ~PathAdder() { - mPath->pop(); + mPath->RemoveElementAt(mPath->Length() - 1); } private: - Vector *mPath; + nsTArray *mPath; PathAdder(const PathAdder &); PathAdder &operator=(const PathAdder &); }; -static bool underMetaDataPath(const Vector &path) { - return path.size() >= 5 +static bool underMetaDataPath(const nsTArray &path) { + return path.Length() >= 5 && path[0] == FOURCC('m', 'o', 'o', 'v') && path[1] == FOURCC('u', 'd', 't', 'a') && path[2] == FOURCC('m', 'e', 't', 'a') @@ -807,7 +806,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { if (chunk_type != FOURCC('c', 'p', 'r', 't') && chunk_type != FOURCC('c', 'o', 'v', 'r') - && mPath.size() == 5 && underMetaDataPath(mPath)) { + && mPath.Length() == 5 && underMetaDataPath(mPath)) { off64_t stop_offset = *offset + chunk_size; *offset = data_offset; while (*offset < stop_offset) { @@ -1135,7 +1134,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { return ERROR_IO; } - mPssh.push_back(pssh); + mPssh.AppendElement(pssh); *offset += chunk_size; break; @@ -1691,9 +1690,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mLastTrack->meta->setData( kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4); - if (mPath.size() >= 2 - && (mPath[mPath.size() - 2] == FOURCC('m', 'p', '4', 'a') || - (mPath[mPath.size() - 2] == FOURCC('e', 'n', 'c', 'a')))) { + if (mPath.Length() >= 2 + && (mPath[mPath.Length() - 2] == FOURCC('m', 'p', '4', 'a') || + (mPath[mPath.Length() - 2] == FOURCC('e', 'n', 'c', 'a')))) { // Information from the ESDS must be relied on for proper // setup of sample rate and channel count for MPEG4 Audio. // The generic header appears to only contain generic @@ -1811,7 +1810,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('n', 'a', 'm', 'e'): case FOURCC('d', 'a', 't', 'a'): { - if (mPath.size() == 6 && underMetaDataPath(mPath)) { + if (mPath.Length() == 6 && underMetaDataPath(mPath)) { status_t err = parseMetaData(data_offset, chunk_data_size); if (err != OK) { @@ -2175,7 +2174,7 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) { SidxEntry se; se.mSize = d1 & 0x7fffffff; se.mDurationUs = 1000000LL * d2 / timeScale; - mSidxEntries.add(se); + mSidxEntries.AppendElement(se); } mSidxDuration = total_duration * 1000000 / timeScale; @@ -2688,7 +2687,7 @@ MPEG4Source::MPEG4Source( const sp &dataSource, int32_t timeScale, const sp &sampleTable, - Vector &sidx, + nsTArray &sidx, MPEG4Extractor::TrackExtends &trackExtends) : mFormat(format), mDataSource(dataSource), @@ -2925,14 +2924,14 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(off64_t offset, off64 ALOGV("parseSampleAuxiliaryInformationSizes"); // 14496-12 8.7.12 - if (mCurrentSamples.isEmpty()) { + if (mCurrentSamples.IsEmpty()) { // XXX hack -- we haven't seen trun yet; defer parsing this box until // after trun. ALOGW("deferring processing of saiz box"); AuxRange range; range.mStart = offset; range.mSize = size; - mDeferredSaiz.add(range); + mDeferredSaiz.AppendElement(range); return OK; } @@ -2999,14 +2998,14 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(off64_t offset, off ALOGV("parseSampleAuxiliaryInformationOffsets"); // 14496-12 8.7.13 - if (mCurrentSamples.isEmpty()) { + if (mCurrentSamples.IsEmpty()) { // XXX hack -- we haven't seen trun yet; defer parsing this box until // after trun. ALOGW("deferring processing of saio box"); AuxRange range; range.mStart = offset; range.mSize = size; - mDeferredSaio.add(range); + mDeferredSaio.AppendElement(range); return OK; } @@ -3067,7 +3066,7 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(off64_t offset, off // read CencSampleAuxiliaryDataFormats for (size_t i = 0; i < mCurrentSampleInfoCount; i++) { - Sample *smpl = &mCurrentSamples.editItemAt(i); + Sample *smpl = &mCurrentSamples[i]; memset(smpl->iv, 0, 16); if (mDataSource->readAt(drmoffset, smpl->iv, ivlength) != ivlength) { @@ -3097,12 +3096,12 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(off64_t offset, off return ERROR_IO; } drmoffset += 4; - smpl->clearsizes.add(numclear); - smpl->encryptedsizes.add(numencrypted); + smpl->clearsizes.AppendElement(numclear); + smpl->encryptedsizes.AppendElement(numencrypted); } } else { - smpl->clearsizes.add(0); - smpl->encryptedsizes.add(smpl->size); + smpl->clearsizes.AppendElement(0); + smpl->encryptedsizes.AppendElement(smpl->size); } } @@ -3401,14 +3400,14 @@ status_t MPEG4Source::parseTrackFragmentRun(off64_t offset, off64_t size) { tmp.size = sampleSize; tmp.duration = sampleDuration; tmp.ctsOffset = (int32_t)sampleCtsOffset; - mCurrentSamples.add(tmp); + mCurrentSamples.AppendElement(tmp); dataOffset += sampleSize; } mTrackFragmentHeaderInfo.mDataOffset = dataOffset; - for (size_t i = 0; i < mDeferredSaio.size() && i < mDeferredSaiz.size(); i++) { + for (size_t i = 0; i < mDeferredSaio.Length() && i < mDeferredSaiz.Length(); i++) { const auto& saio = mDeferredSaio[i]; const auto& saiz = mDeferredSaiz[i]; parseSampleAuxiliaryInformationSizes(saiz.mStart, saiz.mSize); @@ -3658,8 +3657,8 @@ status_t MPEG4Source::read( } if (mSampleTable->hasCencInfo()) { - Vector clearSizes; - Vector cipherSizes; + nsTArray clearSizes; + nsTArray cipherSizes; uint8_t iv[16]; status_t err = mSampleTable->getSampleCencInfo( mCurrentSampleIndex, clearSizes, cipherSizes, iv); @@ -3669,10 +3668,10 @@ status_t MPEG4Source::read( } const auto& meta = mBuffer->meta_data(); - meta->setData(kKeyPlainSizes, 0, clearSizes.array(), - clearSizes.size() * sizeof(uint16_t)); - meta->setData(kKeyEncryptedSizes, 0, cipherSizes.array(), - cipherSizes.size() * sizeof(uint32_t)); + meta->setData(kKeyPlainSizes, 0, clearSizes.Elements(), + clearSizes.Length() * sizeof(uint16_t)); + meta->setData(kKeyEncryptedSizes, 0, cipherSizes.Elements(), + cipherSizes.Length() * sizeof(uint32_t)); meta->setData(kKeyCryptoIV, 0, iv, sizeof(iv)); meta->setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize); meta->setInt32(kKeyCryptoMode, mCryptoMode); @@ -3824,8 +3823,8 @@ status_t MPEG4Source::read( } if (mSampleTable->hasCencInfo()) { - Vector clearSizes; - Vector cipherSizes; + nsTArray clearSizes; + nsTArray cipherSizes; uint8_t iv[16]; status_t err = mSampleTable->getSampleCencInfo( mCurrentSampleIndex, clearSizes, cipherSizes, iv); @@ -3835,10 +3834,10 @@ status_t MPEG4Source::read( } const auto& meta = mBuffer->meta_data(); - meta->setData(kKeyPlainSizes, 0, clearSizes.array(), - clearSizes.size() * sizeof(uint16_t)); - meta->setData(kKeyEncryptedSizes, 0, cipherSizes.array(), - cipherSizes.size() * sizeof(uint32_t)); + meta->setData(kKeyPlainSizes, 0, clearSizes.Elements(), + clearSizes.Length() * sizeof(uint16_t)); + meta->setData(kKeyEncryptedSizes, 0, cipherSizes.Elements(), + cipherSizes.Length() * sizeof(uint32_t)); meta->setData(kKeyCryptoIV, 0, iv, sizeof(iv)); meta->setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize); meta->setInt32(kKeyCryptoMode, mCryptoMode); @@ -3856,9 +3855,9 @@ status_t MPEG4Source::read( status_t MPEG4Source::moveToNextFragment() { off64_t nextMoof = mNextMoofOffset; - mCurrentSamples.clear(); - mDeferredSaio.clear(); - mDeferredSaiz.clear(); + mCurrentSamples.Clear(); + mDeferredSaio.Clear(); + mDeferredSaiz.Clear(); mCurrentSampleIndex = 0; uint32_t hdr[2]; do { @@ -3878,7 +3877,7 @@ status_t MPEG4Source::moveToNextFragment() { if (ret != OK) { return ret; } - } while (mCurrentSamples.size() == 0); + } while (mCurrentSamples.Length() == 0); return OK; } @@ -3897,7 +3896,7 @@ status_t MPEG4Source::fragmentedRead( ReadOptions::SeekMode mode; if (options && options->getSeekTo(&seekTimeUs, &mode)) { - int numSidxEntries = mSegments.size(); + int numSidxEntries = mSegments.Length(); if (numSidxEntries != 0) { int64_t totalTime = 0; off64_t totalOffset = mFirstMoofOffset; @@ -3919,9 +3918,9 @@ status_t MPEG4Source::fragmentedRead( totalOffset += se->mSize; } mCurrentMoofOffset = totalOffset; - mCurrentSamples.clear(); - mDeferredSaio.clear(); - mDeferredSaiz.clear(); + mCurrentSamples.Clear(); + mDeferredSaio.Clear(); + mDeferredSaiz.Clear(); mCurrentSampleIndex = 0; mCurrentTime = totalTime * mTimescale / 1000000ll; mNextMoofOffset = totalOffset; @@ -3936,7 +3935,7 @@ status_t MPEG4Source::fragmentedRead( } uint32_t time = mCurrentTime; int i; - for (i = 0; i < mCurrentSamples.size() && time <= seekTime; i++) { + for (i = 0; i < mCurrentSamples.Length() && time <= seekTime; i++) { const Sample *smpl = &mCurrentSamples[i]; if (smpl->isSync()) { mCurrentSampleIndex = i; @@ -3944,7 +3943,7 @@ status_t MPEG4Source::fragmentedRead( } time += smpl->duration; } - if (i != mCurrentSamples.size()) { + if (i != mCurrentSamples.Length()) { break; } } @@ -3970,7 +3969,7 @@ status_t MPEG4Source::fragmentedRead( if (mBuffer == NULL) { newBuffer = true; - if (mCurrentSampleIndex >= mCurrentSamples.size()) { + if (mCurrentSampleIndex >= mCurrentSamples.Length()) { status_t ret = moveToNextFragment(); if (ret != OK) { return ret; @@ -3994,12 +3993,12 @@ status_t MPEG4Source::fragmentedRead( const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex]; const sp bufmeta = mBuffer->meta_data(); bufmeta->clear(); - if (smpl->encryptedsizes.size()) { + if (smpl->encryptedsizes.Length()) { // store clear/encrypted lengths in metadata bufmeta->setData(kKeyPlainSizes, 0, - smpl->clearsizes.array(), smpl->clearsizes.size() * 2); + smpl->clearsizes.Elements(), smpl->clearsizes.Length() * 2); bufmeta->setData(kKeyEncryptedSizes, 0, - smpl->encryptedsizes.array(), smpl->encryptedsizes.size() * 4); + smpl->encryptedsizes.Elements(), smpl->encryptedsizes.Length() * 4); bufmeta->setData(kKeyCryptoIV, 0, smpl->iv, 16); // use 16 or the actual size? bufmeta->setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize); bufmeta->setInt32(kKeyCryptoMode, mCryptoMode); diff --git a/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp b/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp index cd2f73f22104..ab4d6ee2ed4a 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp @@ -514,7 +514,7 @@ SampleTable::setSampleAuxiliaryInformationSizeParams( return OK; } - if (!mCencSizes.isEmpty() || mCencDefaultSize) { + if (!mCencSizes.IsEmpty() || mCencDefaultSize) { ALOGE("duplicate cenc saiz box"); return ERROR_MALFORMED; } @@ -536,9 +536,11 @@ SampleTable::setSampleAuxiliaryInformationSizeParams( data_offset += 4; if (!mCencDefaultSize) { - mCencSizes.insertAt(0, 0, mCencInfoCount); + if (!mCencSizes.InsertElementsAt(0, mCencInfoCount, mozilla::fallible)) { + return ERROR_IO; + } if (mDataSource->readAt( - data_offset, mCencSizes.editArray(), mCencInfoCount) + data_offset, mCencSizes.Elements(), mCencInfoCount) < mCencInfoCount) { return ERROR_IO; } @@ -568,7 +570,7 @@ SampleTable::setSampleAuxiliaryInformationOffsetParams( return OK; } - if (!mCencOffsets.isEmpty()) { + if (!mCencOffsets.IsEmpty()) { ALOGE("duplicate cenc saio box"); return ERROR_MALFORMED; } @@ -580,22 +582,29 @@ SampleTable::setSampleAuxiliaryInformationOffsetParams( } data_offset += 4; - if (mCencOffsets.setCapacity(cencOffsetCount) < 0) { + if (cencOffsetCount >= kMAX_ALLOCATION) { return ERROR_MALFORMED; } if (!version) { + if (!mCencOffsets.SetCapacity(cencOffsetCount, mozilla::fallible)) { + return ERROR_MALFORMED; + } for (uint32_t i = 0; i < cencOffsetCount; i++) { uint32_t tmp; if (!mDataSource->getUInt32(data_offset, &tmp)) { ALOGE("error reading cenc aux info offsets"); return ERROR_IO; } - mCencOffsets.push(tmp); + // FIXME: Make this infallible after bug 968520 is done. + MOZ_ALWAYS_TRUE(mCencOffsets.AppendElement(tmp, mozilla::fallible)); data_offset += 4; } } else { + if (!mCencOffsets.SetLength(cencOffsetCount, mozilla::fallible)) { + return ERROR_MALFORMED; + } for (uint32_t i = 0; i < cencOffsetCount; i++) { - if (!mDataSource->getUInt64(data_offset, &mCencOffsets.editItemAt(i))) { + if (!mDataSource->getUInt64(data_offset, &mCencOffsets[i])) { ALOGE("error reading cenc aux info offsets"); return ERROR_IO; } @@ -610,15 +619,15 @@ SampleTable::setSampleAuxiliaryInformationOffsetParams( status_t SampleTable::parseSampleCencInfo() { - if ((!mCencDefaultSize && !mCencInfoCount) || mCencOffsets.isEmpty()) { + if ((!mCencDefaultSize && !mCencInfoCount) || mCencOffsets.IsEmpty()) { // We don't have all the cenc information we need yet. Quietly fail and // hope we get the data we need later in the track header. ALOGV("Got half of cenc saio/saiz pair. Deferring parse until we get the other half."); return OK; } - if (!mCencSizes.isEmpty() && mCencOffsets.size() > 1 && - mCencSizes.size() != mCencOffsets.size()) { + if (!mCencSizes.IsEmpty() && mCencOffsets.Length() > 1 && + mCencSizes.IsEmpty() != mCencOffsets.Length()) { return ERROR_MALFORMED; } @@ -635,7 +644,7 @@ SampleTable::parseSampleCencInfo() { uint64_t nextOffset = mCencOffsets[0]; for (uint32_t i = 0; i < mCencInfoCount; i++) { uint8_t size = mCencDefaultSize ? mCencDefaultSize : mCencSizes[i]; - uint64_t offset = mCencOffsets.size() == 1 ? nextOffset : mCencOffsets[i]; + uint64_t offset = mCencOffsets.Length() == 1 ? nextOffset : mCencOffsets[i]; nextOffset = offset + size; auto& info = mCencInfo[i]; @@ -1096,9 +1105,9 @@ uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) { status_t SampleTable::getSampleCencInfo( - uint32_t sample_index, Vector& clear_sizes, - Vector& cipher_sizes, uint8_t iv[]) { - CHECK(clear_sizes.isEmpty() && cipher_sizes.isEmpty()); + uint32_t sample_index, nsTArray& clear_sizes, + nsTArray& cipher_sizes, uint8_t iv[]) { + CHECK(clear_sizes.IsEmpty() && cipher_sizes.IsEmpty()); if (sample_index >= mCencInfoCount) { ALOGE("cenc info requested for out of range sample index"); @@ -1106,16 +1115,15 @@ SampleTable::getSampleCencInfo( } auto& info = mCencInfo[sample_index]; - if (clear_sizes.setCapacity(info.mSubsampleCount) < 0) { - return ERROR_MALFORMED; - } - if (cipher_sizes.setCapacity(info.mSubsampleCount) < 0) { + if (info.mSubsampleCount > kMAX_ALLOCATION) { return ERROR_MALFORMED; } + clear_sizes.SetCapacity(info.mSubsampleCount); + cipher_sizes.SetCapacity(info.mSubsampleCount); for (uint32_t i = 0; i < info.mSubsampleCount; i++) { - clear_sizes.push(info.mSubsamples[i].mClearBytes); - cipher_sizes.push(info.mSubsamples[i].mCipherBytes); + clear_sizes.AppendElement(info.mSubsamples[i].mClearBytes); + cipher_sizes.AppendElement(info.mSubsamples[i].mCipherBytes); } memcpy(iv, info.mIV, IV_BYTES); diff --git a/media/libstagefright/frameworks/av/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/frameworks/av/media/libstagefright/include/MPEG4Extractor.h index f70d028d6fe3..68030c0f4715 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/include/MPEG4Extractor.h +++ b/media/libstagefright/frameworks/av/media/libstagefright/include/MPEG4Extractor.h @@ -24,8 +24,8 @@ #include #include #include -#include #include +#include "nsTArray.h" namespace stagefright { @@ -97,10 +97,10 @@ private: bool skipTrack; }; - Vector mSidxEntries; + nsTArray mSidxEntries; uint64_t mSidxDuration; - Vector mPssh; + nsTArray mPssh; sp mDataSource; status_t mInitCheck; @@ -111,7 +111,7 @@ private: sp mFileMetaData; - Vector mPath; + nsTArray mPath; String8 mLastCommentMean; String8 mLastCommentName; String8 mLastCommentData; diff --git a/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h b/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h index db39a4247c88..a24aa01e4453 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h +++ b/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h @@ -24,7 +24,6 @@ #include #include #include -#include namespace stagefright { @@ -96,8 +95,8 @@ public: bool hasCencInfo() const { return !!mCencInfo; } status_t getSampleCencInfo(uint32_t aSampleIndex, - Vector& aClearSizes, - Vector& aCipherSizes, + nsTArray& aClearSizes, + nsTArray& aCipherSizes, uint8_t aIV[]); protected: @@ -166,8 +165,8 @@ private: uint32_t mCencInfoCount; uint8_t mCencDefaultSize; - Vector mCencSizes; - Vector mCencOffsets; + FallibleTArray mCencSizes; + FallibleTArray mCencOffsets; friend struct SampleIterator; From ccb0cb109c4b733ecc28d2d3fd0bcc8180904ad2 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Sat, 12 Sep 2015 16:57:43 +1000 Subject: [PATCH 126/131] Revert "Bug 1185115: P2. replace all stagefright::Vector with nsTArray. r=kentuckyfriedtakahe" This reverts commit 757c4bd76326 --- .../media/libstagefright/MPEG4Extractor.cpp | 123 +++++++++--------- .../av/media/libstagefright/SampleTable.cpp | 48 +++---- .../libstagefright/include/MPEG4Extractor.h | 8 +- .../libstagefright/include/SampleTable.h | 9 +- 4 files changed, 91 insertions(+), 97 deletions(-) diff --git a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp index dfc71a612120..b57072456605 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp @@ -38,6 +38,7 @@ #include #include #include +#include "nsTArray.h" static const uint32_t kMAX_ALLOCATION = (SIZE_MAX < INT32_MAX ? SIZE_MAX : INT32_MAX) - 128; @@ -51,7 +52,7 @@ public: const sp &dataSource, int32_t timeScale, const sp &sampleTable, - nsTArray &sidx, + Vector &sidx, MPEG4Extractor::TrackExtends &trackExtends); virtual status_t start(MetaData *params = NULL); @@ -75,7 +76,7 @@ private: sp mSampleTable; uint32_t mCurrentSampleIndex; uint32_t mCurrentFragmentIndex; - nsTArray &mSegments; + Vector &mSegments; bool mLookedForMoof; off64_t mFirstMoofOffset; off64_t mCurrentMoofOffset; @@ -148,12 +149,12 @@ private: int32_t ctsOffset; uint32_t flags; uint8_t iv[16]; - nsTArray clearsizes; - nsTArray encryptedsizes; + Vector clearsizes; + Vector encryptedsizes; bool isSync() const { return !(flags & 0x1010000); } }; - nsTArray mCurrentSamples; + Vector mCurrentSamples; MPEG4Extractor::TrackExtends mTrackExtends; // XXX hack -- demuxer expects a track's trun to be seen before saio or @@ -163,8 +164,8 @@ private: off64_t mStart; off64_t mSize; }; - nsTArray mDeferredSaiz; - nsTArray mDeferredSaio; + Vector mDeferredSaiz; + Vector mDeferredSaio; MPEG4Source(const MPEG4Source &); MPEG4Source &operator=(const MPEG4Source &); @@ -404,7 +405,7 @@ MPEG4Extractor::~MPEG4Extractor() { } mFirstSINF = NULL; - for (size_t i = 0; i < mPssh.Length(); i++) { + for (size_t i = 0; i < mPssh.size(); i++) { delete [] mPssh[i].data; } } @@ -508,13 +509,13 @@ status_t MPEG4Extractor::readMetaData() { // copy pssh data into file metadata int psshsize = 0; - for (size_t i = 0; i < mPssh.Length(); i++) { + for (size_t i = 0; i < mPssh.size(); i++) { psshsize += 20 + mPssh[i].datalen; } if (psshsize) { char *buf = (char*)malloc(psshsize); char *ptr = buf; - for (size_t i = 0; i < mPssh.Length(); i++) { + for (size_t i = 0; i < mPssh.size(); i++) { memcpy(ptr, mPssh[i].uuid, 20); // uuid + length memcpy(ptr + 20, mPssh[i].data, mPssh[i].datalen); ptr += (20 + mPssh[i].datalen); @@ -694,24 +695,24 @@ status_t MPEG4Extractor::parseDrmSINF(off64_t *offset, off64_t data_offset) { } struct PathAdder { - PathAdder(nsTArray *path, uint32_t chunkType) + PathAdder(Vector *path, uint32_t chunkType) : mPath(path) { - mPath->AppendElement(chunkType); + mPath->push(chunkType); } ~PathAdder() { - mPath->RemoveElementAt(mPath->Length() - 1); + mPath->pop(); } private: - nsTArray *mPath; + Vector *mPath; PathAdder(const PathAdder &); PathAdder &operator=(const PathAdder &); }; -static bool underMetaDataPath(const nsTArray &path) { - return path.Length() >= 5 +static bool underMetaDataPath(const Vector &path) { + return path.size() >= 5 && path[0] == FOURCC('m', 'o', 'o', 'v') && path[1] == FOURCC('u', 'd', 't', 'a') && path[2] == FOURCC('m', 'e', 't', 'a') @@ -806,7 +807,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { if (chunk_type != FOURCC('c', 'p', 'r', 't') && chunk_type != FOURCC('c', 'o', 'v', 'r') - && mPath.Length() == 5 && underMetaDataPath(mPath)) { + && mPath.size() == 5 && underMetaDataPath(mPath)) { off64_t stop_offset = *offset + chunk_size; *offset = data_offset; while (*offset < stop_offset) { @@ -1134,7 +1135,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { return ERROR_IO; } - mPssh.AppendElement(pssh); + mPssh.push_back(pssh); *offset += chunk_size; break; @@ -1690,9 +1691,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mLastTrack->meta->setData( kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4); - if (mPath.Length() >= 2 - && (mPath[mPath.Length() - 2] == FOURCC('m', 'p', '4', 'a') || - (mPath[mPath.Length() - 2] == FOURCC('e', 'n', 'c', 'a')))) { + if (mPath.size() >= 2 + && (mPath[mPath.size() - 2] == FOURCC('m', 'p', '4', 'a') || + (mPath[mPath.size() - 2] == FOURCC('e', 'n', 'c', 'a')))) { // Information from the ESDS must be relied on for proper // setup of sample rate and channel count for MPEG4 Audio. // The generic header appears to only contain generic @@ -1810,7 +1811,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('n', 'a', 'm', 'e'): case FOURCC('d', 'a', 't', 'a'): { - if (mPath.Length() == 6 && underMetaDataPath(mPath)) { + if (mPath.size() == 6 && underMetaDataPath(mPath)) { status_t err = parseMetaData(data_offset, chunk_data_size); if (err != OK) { @@ -2174,7 +2175,7 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) { SidxEntry se; se.mSize = d1 & 0x7fffffff; se.mDurationUs = 1000000LL * d2 / timeScale; - mSidxEntries.AppendElement(se); + mSidxEntries.add(se); } mSidxDuration = total_duration * 1000000 / timeScale; @@ -2687,7 +2688,7 @@ MPEG4Source::MPEG4Source( const sp &dataSource, int32_t timeScale, const sp &sampleTable, - nsTArray &sidx, + Vector &sidx, MPEG4Extractor::TrackExtends &trackExtends) : mFormat(format), mDataSource(dataSource), @@ -2924,14 +2925,14 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(off64_t offset, off64 ALOGV("parseSampleAuxiliaryInformationSizes"); // 14496-12 8.7.12 - if (mCurrentSamples.IsEmpty()) { + if (mCurrentSamples.isEmpty()) { // XXX hack -- we haven't seen trun yet; defer parsing this box until // after trun. ALOGW("deferring processing of saiz box"); AuxRange range; range.mStart = offset; range.mSize = size; - mDeferredSaiz.AppendElement(range); + mDeferredSaiz.add(range); return OK; } @@ -2998,14 +2999,14 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(off64_t offset, off ALOGV("parseSampleAuxiliaryInformationOffsets"); // 14496-12 8.7.13 - if (mCurrentSamples.IsEmpty()) { + if (mCurrentSamples.isEmpty()) { // XXX hack -- we haven't seen trun yet; defer parsing this box until // after trun. ALOGW("deferring processing of saio box"); AuxRange range; range.mStart = offset; range.mSize = size; - mDeferredSaio.AppendElement(range); + mDeferredSaio.add(range); return OK; } @@ -3066,7 +3067,7 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(off64_t offset, off // read CencSampleAuxiliaryDataFormats for (size_t i = 0; i < mCurrentSampleInfoCount; i++) { - Sample *smpl = &mCurrentSamples[i]; + Sample *smpl = &mCurrentSamples.editItemAt(i); memset(smpl->iv, 0, 16); if (mDataSource->readAt(drmoffset, smpl->iv, ivlength) != ivlength) { @@ -3096,12 +3097,12 @@ status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(off64_t offset, off return ERROR_IO; } drmoffset += 4; - smpl->clearsizes.AppendElement(numclear); - smpl->encryptedsizes.AppendElement(numencrypted); + smpl->clearsizes.add(numclear); + smpl->encryptedsizes.add(numencrypted); } } else { - smpl->clearsizes.AppendElement(0); - smpl->encryptedsizes.AppendElement(smpl->size); + smpl->clearsizes.add(0); + smpl->encryptedsizes.add(smpl->size); } } @@ -3400,14 +3401,14 @@ status_t MPEG4Source::parseTrackFragmentRun(off64_t offset, off64_t size) { tmp.size = sampleSize; tmp.duration = sampleDuration; tmp.ctsOffset = (int32_t)sampleCtsOffset; - mCurrentSamples.AppendElement(tmp); + mCurrentSamples.add(tmp); dataOffset += sampleSize; } mTrackFragmentHeaderInfo.mDataOffset = dataOffset; - for (size_t i = 0; i < mDeferredSaio.Length() && i < mDeferredSaiz.Length(); i++) { + for (size_t i = 0; i < mDeferredSaio.size() && i < mDeferredSaiz.size(); i++) { const auto& saio = mDeferredSaio[i]; const auto& saiz = mDeferredSaiz[i]; parseSampleAuxiliaryInformationSizes(saiz.mStart, saiz.mSize); @@ -3657,8 +3658,8 @@ status_t MPEG4Source::read( } if (mSampleTable->hasCencInfo()) { - nsTArray clearSizes; - nsTArray cipherSizes; + Vector clearSizes; + Vector cipherSizes; uint8_t iv[16]; status_t err = mSampleTable->getSampleCencInfo( mCurrentSampleIndex, clearSizes, cipherSizes, iv); @@ -3668,10 +3669,10 @@ status_t MPEG4Source::read( } const auto& meta = mBuffer->meta_data(); - meta->setData(kKeyPlainSizes, 0, clearSizes.Elements(), - clearSizes.Length() * sizeof(uint16_t)); - meta->setData(kKeyEncryptedSizes, 0, cipherSizes.Elements(), - cipherSizes.Length() * sizeof(uint32_t)); + meta->setData(kKeyPlainSizes, 0, clearSizes.array(), + clearSizes.size() * sizeof(uint16_t)); + meta->setData(kKeyEncryptedSizes, 0, cipherSizes.array(), + cipherSizes.size() * sizeof(uint32_t)); meta->setData(kKeyCryptoIV, 0, iv, sizeof(iv)); meta->setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize); meta->setInt32(kKeyCryptoMode, mCryptoMode); @@ -3823,8 +3824,8 @@ status_t MPEG4Source::read( } if (mSampleTable->hasCencInfo()) { - nsTArray clearSizes; - nsTArray cipherSizes; + Vector clearSizes; + Vector cipherSizes; uint8_t iv[16]; status_t err = mSampleTable->getSampleCencInfo( mCurrentSampleIndex, clearSizes, cipherSizes, iv); @@ -3834,10 +3835,10 @@ status_t MPEG4Source::read( } const auto& meta = mBuffer->meta_data(); - meta->setData(kKeyPlainSizes, 0, clearSizes.Elements(), - clearSizes.Length() * sizeof(uint16_t)); - meta->setData(kKeyEncryptedSizes, 0, cipherSizes.Elements(), - cipherSizes.Length() * sizeof(uint32_t)); + meta->setData(kKeyPlainSizes, 0, clearSizes.array(), + clearSizes.size() * sizeof(uint16_t)); + meta->setData(kKeyEncryptedSizes, 0, cipherSizes.array(), + cipherSizes.size() * sizeof(uint32_t)); meta->setData(kKeyCryptoIV, 0, iv, sizeof(iv)); meta->setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize); meta->setInt32(kKeyCryptoMode, mCryptoMode); @@ -3855,9 +3856,9 @@ status_t MPEG4Source::read( status_t MPEG4Source::moveToNextFragment() { off64_t nextMoof = mNextMoofOffset; - mCurrentSamples.Clear(); - mDeferredSaio.Clear(); - mDeferredSaiz.Clear(); + mCurrentSamples.clear(); + mDeferredSaio.clear(); + mDeferredSaiz.clear(); mCurrentSampleIndex = 0; uint32_t hdr[2]; do { @@ -3877,7 +3878,7 @@ status_t MPEG4Source::moveToNextFragment() { if (ret != OK) { return ret; } - } while (mCurrentSamples.Length() == 0); + } while (mCurrentSamples.size() == 0); return OK; } @@ -3896,7 +3897,7 @@ status_t MPEG4Source::fragmentedRead( ReadOptions::SeekMode mode; if (options && options->getSeekTo(&seekTimeUs, &mode)) { - int numSidxEntries = mSegments.Length(); + int numSidxEntries = mSegments.size(); if (numSidxEntries != 0) { int64_t totalTime = 0; off64_t totalOffset = mFirstMoofOffset; @@ -3918,9 +3919,9 @@ status_t MPEG4Source::fragmentedRead( totalOffset += se->mSize; } mCurrentMoofOffset = totalOffset; - mCurrentSamples.Clear(); - mDeferredSaio.Clear(); - mDeferredSaiz.Clear(); + mCurrentSamples.clear(); + mDeferredSaio.clear(); + mDeferredSaiz.clear(); mCurrentSampleIndex = 0; mCurrentTime = totalTime * mTimescale / 1000000ll; mNextMoofOffset = totalOffset; @@ -3935,7 +3936,7 @@ status_t MPEG4Source::fragmentedRead( } uint32_t time = mCurrentTime; int i; - for (i = 0; i < mCurrentSamples.Length() && time <= seekTime; i++) { + for (i = 0; i < mCurrentSamples.size() && time <= seekTime; i++) { const Sample *smpl = &mCurrentSamples[i]; if (smpl->isSync()) { mCurrentSampleIndex = i; @@ -3943,7 +3944,7 @@ status_t MPEG4Source::fragmentedRead( } time += smpl->duration; } - if (i != mCurrentSamples.Length()) { + if (i != mCurrentSamples.size()) { break; } } @@ -3969,7 +3970,7 @@ status_t MPEG4Source::fragmentedRead( if (mBuffer == NULL) { newBuffer = true; - if (mCurrentSampleIndex >= mCurrentSamples.Length()) { + if (mCurrentSampleIndex >= mCurrentSamples.size()) { status_t ret = moveToNextFragment(); if (ret != OK) { return ret; @@ -3993,12 +3994,12 @@ status_t MPEG4Source::fragmentedRead( const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex]; const sp bufmeta = mBuffer->meta_data(); bufmeta->clear(); - if (smpl->encryptedsizes.Length()) { + if (smpl->encryptedsizes.size()) { // store clear/encrypted lengths in metadata bufmeta->setData(kKeyPlainSizes, 0, - smpl->clearsizes.Elements(), smpl->clearsizes.Length() * 2); + smpl->clearsizes.array(), smpl->clearsizes.size() * 2); bufmeta->setData(kKeyEncryptedSizes, 0, - smpl->encryptedsizes.Elements(), smpl->encryptedsizes.Length() * 4); + smpl->encryptedsizes.array(), smpl->encryptedsizes.size() * 4); bufmeta->setData(kKeyCryptoIV, 0, smpl->iv, 16); // use 16 or the actual size? bufmeta->setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize); bufmeta->setInt32(kKeyCryptoMode, mCryptoMode); diff --git a/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp b/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp index ab4d6ee2ed4a..cd2f73f22104 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp @@ -514,7 +514,7 @@ SampleTable::setSampleAuxiliaryInformationSizeParams( return OK; } - if (!mCencSizes.IsEmpty() || mCencDefaultSize) { + if (!mCencSizes.isEmpty() || mCencDefaultSize) { ALOGE("duplicate cenc saiz box"); return ERROR_MALFORMED; } @@ -536,11 +536,9 @@ SampleTable::setSampleAuxiliaryInformationSizeParams( data_offset += 4; if (!mCencDefaultSize) { - if (!mCencSizes.InsertElementsAt(0, mCencInfoCount, mozilla::fallible)) { - return ERROR_IO; - } + mCencSizes.insertAt(0, 0, mCencInfoCount); if (mDataSource->readAt( - data_offset, mCencSizes.Elements(), mCencInfoCount) + data_offset, mCencSizes.editArray(), mCencInfoCount) < mCencInfoCount) { return ERROR_IO; } @@ -570,7 +568,7 @@ SampleTable::setSampleAuxiliaryInformationOffsetParams( return OK; } - if (!mCencOffsets.IsEmpty()) { + if (!mCencOffsets.isEmpty()) { ALOGE("duplicate cenc saio box"); return ERROR_MALFORMED; } @@ -582,29 +580,22 @@ SampleTable::setSampleAuxiliaryInformationOffsetParams( } data_offset += 4; - if (cencOffsetCount >= kMAX_ALLOCATION) { + if (mCencOffsets.setCapacity(cencOffsetCount) < 0) { return ERROR_MALFORMED; } if (!version) { - if (!mCencOffsets.SetCapacity(cencOffsetCount, mozilla::fallible)) { - return ERROR_MALFORMED; - } for (uint32_t i = 0; i < cencOffsetCount; i++) { uint32_t tmp; if (!mDataSource->getUInt32(data_offset, &tmp)) { ALOGE("error reading cenc aux info offsets"); return ERROR_IO; } - // FIXME: Make this infallible after bug 968520 is done. - MOZ_ALWAYS_TRUE(mCencOffsets.AppendElement(tmp, mozilla::fallible)); + mCencOffsets.push(tmp); data_offset += 4; } } else { - if (!mCencOffsets.SetLength(cencOffsetCount, mozilla::fallible)) { - return ERROR_MALFORMED; - } for (uint32_t i = 0; i < cencOffsetCount; i++) { - if (!mDataSource->getUInt64(data_offset, &mCencOffsets[i])) { + if (!mDataSource->getUInt64(data_offset, &mCencOffsets.editItemAt(i))) { ALOGE("error reading cenc aux info offsets"); return ERROR_IO; } @@ -619,15 +610,15 @@ SampleTable::setSampleAuxiliaryInformationOffsetParams( status_t SampleTable::parseSampleCencInfo() { - if ((!mCencDefaultSize && !mCencInfoCount) || mCencOffsets.IsEmpty()) { + if ((!mCencDefaultSize && !mCencInfoCount) || mCencOffsets.isEmpty()) { // We don't have all the cenc information we need yet. Quietly fail and // hope we get the data we need later in the track header. ALOGV("Got half of cenc saio/saiz pair. Deferring parse until we get the other half."); return OK; } - if (!mCencSizes.IsEmpty() && mCencOffsets.Length() > 1 && - mCencSizes.IsEmpty() != mCencOffsets.Length()) { + if (!mCencSizes.isEmpty() && mCencOffsets.size() > 1 && + mCencSizes.size() != mCencOffsets.size()) { return ERROR_MALFORMED; } @@ -644,7 +635,7 @@ SampleTable::parseSampleCencInfo() { uint64_t nextOffset = mCencOffsets[0]; for (uint32_t i = 0; i < mCencInfoCount; i++) { uint8_t size = mCencDefaultSize ? mCencDefaultSize : mCencSizes[i]; - uint64_t offset = mCencOffsets.Length() == 1 ? nextOffset : mCencOffsets[i]; + uint64_t offset = mCencOffsets.size() == 1 ? nextOffset : mCencOffsets[i]; nextOffset = offset + size; auto& info = mCencInfo[i]; @@ -1105,9 +1096,9 @@ uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) { status_t SampleTable::getSampleCencInfo( - uint32_t sample_index, nsTArray& clear_sizes, - nsTArray& cipher_sizes, uint8_t iv[]) { - CHECK(clear_sizes.IsEmpty() && cipher_sizes.IsEmpty()); + uint32_t sample_index, Vector& clear_sizes, + Vector& cipher_sizes, uint8_t iv[]) { + CHECK(clear_sizes.isEmpty() && cipher_sizes.isEmpty()); if (sample_index >= mCencInfoCount) { ALOGE("cenc info requested for out of range sample index"); @@ -1115,15 +1106,16 @@ SampleTable::getSampleCencInfo( } auto& info = mCencInfo[sample_index]; - if (info.mSubsampleCount > kMAX_ALLOCATION) { + if (clear_sizes.setCapacity(info.mSubsampleCount) < 0) { + return ERROR_MALFORMED; + } + if (cipher_sizes.setCapacity(info.mSubsampleCount) < 0) { return ERROR_MALFORMED; } - clear_sizes.SetCapacity(info.mSubsampleCount); - cipher_sizes.SetCapacity(info.mSubsampleCount); for (uint32_t i = 0; i < info.mSubsampleCount; i++) { - clear_sizes.AppendElement(info.mSubsamples[i].mClearBytes); - cipher_sizes.AppendElement(info.mSubsamples[i].mCipherBytes); + clear_sizes.push(info.mSubsamples[i].mClearBytes); + cipher_sizes.push(info.mSubsamples[i].mCipherBytes); } memcpy(iv, info.mIV, IV_BYTES); diff --git a/media/libstagefright/frameworks/av/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/frameworks/av/media/libstagefright/include/MPEG4Extractor.h index 68030c0f4715..f70d028d6fe3 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/include/MPEG4Extractor.h +++ b/media/libstagefright/frameworks/av/media/libstagefright/include/MPEG4Extractor.h @@ -24,8 +24,8 @@ #include #include #include +#include #include -#include "nsTArray.h" namespace stagefright { @@ -97,10 +97,10 @@ private: bool skipTrack; }; - nsTArray mSidxEntries; + Vector mSidxEntries; uint64_t mSidxDuration; - nsTArray mPssh; + Vector mPssh; sp mDataSource; status_t mInitCheck; @@ -111,7 +111,7 @@ private: sp mFileMetaData; - nsTArray mPath; + Vector mPath; String8 mLastCommentMean; String8 mLastCommentName; String8 mLastCommentData; diff --git a/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h b/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h index a24aa01e4453..db39a4247c88 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h +++ b/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h @@ -24,6 +24,7 @@ #include #include #include +#include namespace stagefright { @@ -95,8 +96,8 @@ public: bool hasCencInfo() const { return !!mCencInfo; } status_t getSampleCencInfo(uint32_t aSampleIndex, - nsTArray& aClearSizes, - nsTArray& aCipherSizes, + Vector& aClearSizes, + Vector& aCipherSizes, uint8_t aIV[]); protected: @@ -165,8 +166,8 @@ private: uint32_t mCencInfoCount; uint8_t mCencDefaultSize; - FallibleTArray mCencSizes; - FallibleTArray mCencOffsets; + Vector mCencSizes; + Vector mCencOffsets; friend struct SampleIterator; From bae5d8a74284864565bfd8e439fa218f51cddfd8 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 10 Sep 2015 14:47:31 +1200 Subject: [PATCH 127/131] bug 1203380 ClearDownstreamMark() before returning AsMutableChunk() r=padenot --HG-- extra : rebase_source : ddc5b3f2ec5238688bc13ed7d4c007fe91f42b85 --- dom/media/webaudio/AudioBlock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/media/webaudio/AudioBlock.h b/dom/media/webaudio/AudioBlock.h index 2748ff67b8a5..76c3c8972227 100644 --- a/dom/media/webaudio/AudioBlock.h +++ b/dom/media/webaudio/AudioBlock.h @@ -44,7 +44,7 @@ public: const AudioChunk& AsAudioChunk() const { return *this; } AudioChunk* AsMutableChunk() { - void ClearDownstreamMark(); + ClearDownstreamMark(); return this; } From 4935533d54ce238a00633d726c965dc6ed8f0d6d Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 10 Sep 2015 15:13:45 +1200 Subject: [PATCH 128/131] bug 1203380 destroy AudioBlocks on AudioNodeStream on graph thread r=padenot --HG-- extra : rebase_source : b2e560fa1c6da233de42667207946d2732727701 --- dom/media/webaudio/AudioNodeStream.cpp | 10 ++++++++++ dom/media/webaudio/AudioNodeStream.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/dom/media/webaudio/AudioNodeStream.cpp b/dom/media/webaudio/AudioNodeStream.cpp index 373c46f3d268..024e07da2f0b 100644 --- a/dom/media/webaudio/AudioNodeStream.cpp +++ b/dom/media/webaudio/AudioNodeStream.cpp @@ -53,6 +53,16 @@ AudioNodeStream::~AudioNodeStream() MOZ_COUNT_DTOR(AudioNodeStream); } +void +AudioNodeStream::DestroyImpl() +{ + // These are graph thread objects, so clean up on graph thread. + mInputChunks.Clear(); + mLastChunks.Clear(); + + ProcessedMediaStream::DestroyImpl(); +} + /* static */ already_AddRefed AudioNodeStream::Create(MediaStreamGraph* aGraph, AudioNodeEngine* aEngine, Flags aFlags) diff --git a/dom/media/webaudio/AudioNodeStream.h b/dom/media/webaudio/AudioNodeStream.h index c43109258535..5fd175b9da73 100644 --- a/dom/media/webaudio/AudioNodeStream.h +++ b/dom/media/webaudio/AudioNodeStream.h @@ -169,6 +169,8 @@ public: protected: + virtual void DestroyImpl() override; + void AdvanceOutputSegment(); void FinishOutput(); void AccumulateInputChunk(uint32_t aInputIndex, const AudioBlock& aChunk, From 99d66c32cbcefd94173d66d444270fbd6661b00e Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 10 Sep 2015 09:01:55 +1200 Subject: [PATCH 129/131] bug 1203380 tighten not-sharing assertion in ChannelFloatsForWrite() r=padenot --HG-- extra : rebase_source : 5206ae1ae59bade7f2b40400e0f851bf26df5d9c --- dom/media/webaudio/AudioBlock.cpp | 9 ++++++--- dom/media/webaudio/AudioBlock.h | 10 ++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/dom/media/webaudio/AudioBlock.cpp b/dom/media/webaudio/AudioBlock.cpp index c30fce63fcbe..e8dd4a6a0550 100644 --- a/dom/media/webaudio/AudioBlock.cpp +++ b/dom/media/webaudio/AudioBlock.cpp @@ -124,9 +124,12 @@ AudioBlock::ClearDownstreamMark() { } } -void -AudioBlock::AssertNoLastingShares() { - MOZ_ASSERT(!mBuffer->AsAudioBlockBuffer()->HasLastingShares()); +bool +AudioBlock::CanWrite() { + // If mBufferIsDownstreamRef is set then the buffer is not ours to use. + // It may be in use by another node which is not downstream. + return !mBufferIsDownstreamRef && + !mBuffer->AsAudioBlockBuffer()->HasLastingShares(); } void diff --git a/dom/media/webaudio/AudioBlock.h b/dom/media/webaudio/AudioBlock.h index 76c3c8972227..2a96a310af81 100644 --- a/dom/media/webaudio/AudioBlock.h +++ b/dom/media/webaudio/AudioBlock.h @@ -54,12 +54,14 @@ public: */ void AllocateChannels(uint32_t aChannelCount); + /** + * ChannelFloatsForWrite() should only be used when the buffers have been + * created with AllocateChannels(). + */ float* ChannelFloatsForWrite(size_t aChannel) { MOZ_ASSERT(mBufferFormat == AUDIO_FORMAT_FLOAT32); -#if DEBUG - AssertNoLastingShares(); -#endif + MOZ_ASSERT(CanWrite()); return static_cast(const_cast(mChannelData[aChannel])); } @@ -103,7 +105,7 @@ public: private: void ClearDownstreamMark(); - void AssertNoLastingShares(); + bool CanWrite(); // mBufferIsDownstreamRef is set only when mBuffer references an // AudioBlockBuffer created in a different AudioBlock. That can happen when From 965591c7132b1e4c8cbe4d2ce433dcb5791aa1d0 Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 10 Sep 2015 08:39:12 +1200 Subject: [PATCH 130/131] bug 1203380 add custom assignment operator to AudioBlock r=padenot --HG-- extra : rebase_source : 620bcfe8e7841ab1b19790abbf4df87a3e083c35 --- dom/media/webaudio/AudioBlock.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dom/media/webaudio/AudioBlock.h b/dom/media/webaudio/AudioBlock.h index 2a96a310af81..da3b2d2b9e8d 100644 --- a/dom/media/webaudio/AudioBlock.h +++ b/dom/media/webaudio/AudioBlock.h @@ -74,6 +74,12 @@ public: mBufferFormat = AUDIO_FORMAT_SILENCE; } + AudioBlock& operator=(const AudioBlock& aBlock) { + // Instead of just copying, mBufferIsDownstreamRef must be first cleared + // if set. It is set again for the new mBuffer if possible. This happens + // in SetBuffer(). + return *this = aBlock.AsAudioChunk(); + } AudioBlock& operator=(const AudioChunk& aChunk) { MOZ_ASSERT(aChunk.mDuration == WEBAUDIO_BLOCK_SIZE); SetBuffer(aChunk.mBuffer); From 99e730c642129758a22322b5d89a2edb803d9c3e Mon Sep 17 00:00:00 2001 From: Karl Tomlinson Date: Thu, 10 Sep 2015 09:29:34 +1200 Subject: [PATCH 131/131] bug 1203380 add custom AudioBlock copy constructor and make AudioChunk conversion constructor explicit r=padenot Making the conversion constructor explicit means that it will be obvious if a temporary is created to pass an AudioChunk as an AudioBlock parameter. --HG-- extra : rebase_source : 54bf8acdb42499a0e0d66cfc138ff6fb6f1ef4da --- dom/media/webaudio/AudioBlock.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/dom/media/webaudio/AudioBlock.h b/dom/media/webaudio/AudioBlock.h index da3b2d2b9e8d..5d0d9e17aad0 100644 --- a/dom/media/webaudio/AudioBlock.h +++ b/dom/media/webaudio/AudioBlock.h @@ -24,9 +24,16 @@ public: AudioBlock() { mDuration = WEBAUDIO_BLOCK_SIZE; } - MOZ_IMPLICIT AudioBlock(const AudioChunk& aChunk) { - mDuration = WEBAUDIO_BLOCK_SIZE; - operator=(aChunk); + // No effort is made in constructors to ensure that mBufferIsDownstreamRef + // is set because the block is expected to be a temporary and so the + // reference will be released before the next iteration. + // The custom copy constructor is required so as not to set + // mBufferIsDownstreamRef without notifying AudioBlockBuffer. + AudioBlock(const AudioBlock& aBlock) : AudioChunk(aBlock.AsAudioChunk()) {} + explicit AudioBlock(const AudioChunk& aChunk) + : AudioChunk(aChunk) + { + MOZ_ASSERT(aChunk.mDuration == WEBAUDIO_BLOCK_SIZE); } ~AudioBlock();