import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1202386: Add logging macros for HAL IPC, r=shuang (246eb96f38)
- Bug 1202386: Output clear HAL IPC errors, r=shuang (eaba0dc9a8)
- Bug 1202704: Move Bluetooth IPC pack functions to generic HAL IPC, r=shuang (4c745de79c)
- Bug 1202704: Move Bluetooth IPC unpack functions to generic HAL IPC, r=shuang (4f8600030b)
- Bug 1202704: Move Bluetooth's |UnpackPDUInitOp| to generic HAL IPC code, r=shuang (345f21c637)
- Bug 1209085: Add 6-argument operator () to |UnpackPDUInitOp|, r=joliu (f5f8cf2dd9)
- Bug 1123760 - make autocomplete dropmarker in the urlbar actually work when activated through a11y APIs, r=surkov (eee42195f4)
- Bug 1123760 - bustage follow-up: remove unused variable, rs=bustage on a CLOSED TREE (6de8519b23)
- Bug 1152836 - QR Decoder: Let everywhere, style nits: 580ms -> 400ms r=past (92a7fd6a15)
- Bug 1212430 - Remove CrashAtUnhandlableOOM() and replace with AutoEnterOOMUnsafeRegion r=jandem (f595b87951)
- Bug 1175755 - Only clear GC statistics aborted flag at the end of the outermost nested GC r=bbouvier (ca73f34c69)
- reapply  Bug 1221385 - Handle OOM during JitRuntime (e7def65b78)
- No bug: Clarify documentation for js::NewObjectMetadataState. DONTBUILD r=fitzgen (41022b4137)
- Bug 1211164 - Collect JS deprecated language extension telemetry for Add-ons. r=till,bsmedberg (eacd40ad66)
- Bug 1212296 - undo a state change on OOM. r=till (6e272353d0)
- Bug 1214006 - Take account of the fact that JSScript::atoms may be null while tracing r=terrence (19f61d7494)
- missing bits of Bug 1208665 (c31173b0d4)
- Bug 1221891 - "Fix a typo in TraceLoggingGraph.h". r=hv1989 (e1fc11f8df)
- Bug 1221460 - "TraceLogger: Enable several new optimizations in 'TLLOG=IonCompiler'". r=hv1989 (ab3398646e)
- Bug 1204365 - Repair external view source file name and extension. r=mconley (f033e55a0e)
- Bug 1163693 - Fix View Source external editor fallback. r=jryans. (9c8becc93b)
- Bug 1207629 - Don't assume that viewSourceUtils.js has Services in scope. r=jryans (07977953c0)
- add back some telemetry (1e3b5bde5b)
- Bug 1186785 - Replace nsBaseHashtable::EnumerateRead() calls in toolkit/ with iterators. r=froydnj. (e93e098dd8)
- add back some crashreporter (80e325b3be)
- Bug 1220035 - Fix -Wimplicit-fallthrough warnings in xpcom. r=mccr8 (2ef9ecad5f)
- Bug 1215629 - Remove nsDebug logger. r=froydnj (46784f05fd)
- Bug 1137963 - Use a spin lock for TraceRefCnt. r=waldo, r=froydnj (b2420c97c0)
- Bug 1196430 - part 1 - rename serialNumberRecord to SerialNumberRecord; r=mccr8 (933670070d)
- Bug 1196430 - part 2 - give SerialNumberRecord a proper constructor; r=mccr8 (3ddf3d5e69)
- Bug 1196430 - part 3 - remove unnecessary nsString.h include from nsTraceRefcnt.cpp; r=mccr8 (034954e692)
- Bug 1196430 - part 4 - record allocation stacks for classes in XPCOM_MEM_LOG_CLASSES; r=mccr8 (366b612807)
- Bug 1196430 - part 5 - dump allocation stacks for leaked objects in XPCOM_MEM_LOG_CLASSES; r=mccr8 (dce7b9cca2)
- Bug 1180745 - Fix logging test screenshotting errors. r=jgriffin (a589f0d322)
- Bug 1091285 - move dumpScreen in a new mozscreenshot package. r=jgriffin This also completely remove build/automationutils.py. (6e633359ef)
- some crashreporter stuff (2d0bc9c95d)
- Bug 1196430 - part 6 - move cut-and-paste stack fixer code into mozrunner; r=wlach (ffc7ccd521)
- Bug 1196430 - part 7 - teach process_leak_log how to symbolicate leaked object stacks; r=mccr8 (0b5a4ace7c)
- Bug 1196430 - part 8 - use less reinterpret_cast in nsTraceRefcnt.cpp; r=mccr8 (758cfca0aa)
- Bug 1196430 follow-up: Hide the usage of gCodeAddressService behind #ifdef MOZ_STACKWALKING (e8d62dd73e)
- Bug 487494 - Add an xpcshell selftest for readable stacks from assertions.;r=ted (ea15cf3cbb)
- Bug 1156977 - Assert when aClassName is empty in BloatEntry. r=froydnj Bug 1116550 - Part 1: Turn HaveLeaks and Clear into methods. r=froydnj (8d7f88f498)
- Bug 1116550 - Part 2: Print out negative values for leaks when there are more dtors than ctors. r=froydnj (7c9e3e7848)
- Bug 1190483 - Add a way to record a DMD log late in shutdown. r=erahm (df7c22e64d)
- Bug 1174344 - make error message for mismatched leak log entries more helpful; r=mccr8 (7f969e72c0)
- Bug 1190483 - Followup to address review comment. (d3873f76fd)
- Bug 1186025. Optimize the usage of regions. r=mstange (263080a66e)
- Bug 1211841 - Style off the main thread markers differently, r=jsantell (1a183c5d3e)
- Bug 1211839 - Don't allow off the main thread markers to nest under main thread markers, r=smaug, jsantell (f4d4b7ccf1)
- Bug 1207161 - fix run-by-dir leak in test_bug846906.xul; r=mccr8 (5511752103)
- Bug 1205348 - Always do shutdown CCs when NS_FREE_PERMANENT_DATA is defined. r=smaug (7fd7a7455c)
- Bug 1208157, part 1 - Add and use nsCycleCollector::IsIdle() predicate. r=smaug (a06c2bd1db)
- Bug 1208157, part 2 - Make the fields of nsCycleCollector private. r=smaug (494637fbef)
- Bug 1207368 - Use swap() instead of forget() to remove MessageElement::mMessage. r=froydnj (8c58d38a55)
- Bug 1181520 - Remove support for passing in reftest arguments via the command line, r=jmaher (75e9440e40)
- Bug 1196814 - Fail Android mochitest, robocop, reftests when Fennec is not installed; r=jmaher (6ec15636eb)
- Bug 1183717 - Increase default timeout for Android Debug reftests; r=jmaher (1b07fc1c9b)
- Bug 1181516 - Allow reftests to take paths to multiple directories containing tests on the command line, r=jmaher (1e27ef0d69)
- Bug 1198944 - remove vmware recording support from mochitest; r=khuey (06e79556fb)
- Bug 1162003 - Enable run-by-dir mode on Fx desktop opt builds. r=jmaher (0ef288a33c)
- Bug 1087629 - Add two new test cases for ICE connection states. r=ekr (374112f2d0)
- Bug 1186551 - [mozlog] add structured action process_start/process_exit. r=jgraham (13ce88dbf7)
- Bug 1154111 - Colorize SKIP in test logs. r=jgraham (85910e0f8b)
- Bug 1191267 - Fix mozlog log buffering command line option, r=chmanchester (2bd6592f9b)
- Bug 1185244 - Improve mach support for running mochitests on Valgrind. r=jgraham, njn. (7f5a830fa0)
- Bug 1219870 - [mozlog] ensure correct suite state when logging suite_start/suite_end via StructuredLogger.log_raw, r=chmanchester (21710387a4)
- Bug 1198257 - Better support for providing a directory name and discovering reftests under that directory, r=jmaher (f6255fc44c)
- Bug 1208220 - Remove test of manifest filename that breaks my workflow. r=jgraham (ae4e45946d)
- Bug 1186888 - [mozlog] Ability to use a pre-existing logger with commandline.setup_logging(), r=jgraham (80dfa2a8a8)
- Bug 1042998 - Use StructuredLog.jsm for mochitest logging, r=chmanchester (8851b1b6f9)
- Bug 1218010 - Shorten the polling interval when waiting for httpd.js startup in mochitest. r=ahal (a1f2c81a8e)
- Bug 1224305 - Add an option to the mochitest harness to provide a copy of the extra chrome manifest it writes. r=ahal (e617971f41)
- Bug 1170342 - Don't disable XInput2 for mochitests on GTK3, off by default now. r=karlt (05d53439da)
- Bug 1145375 - Don't kill the debugger if the user Ctrl-C's as running a mochitest; r=ted (6c310500b8)
- Bug 1199241 - Average runtime data across platforms instead of keeping it distinct, r=jgriffin (cd497f509c)
- Bug 1157852 - Mochitest DevTools test directories run multiple times. r=ahal (415ab41a3a)
- Bug 1186791 (part 1) - Replace nsBaseHashtable::EnumerateRead() calls in storage/ with iterators. r=mak. (84f6f1f566)
- Bug 1186791 (part 2) - Replace nsBaseHashtable::EnumerateRead() calls in storage/ with iterators. r=mak. (9c67504d0c)
- Bug 1186791 (part 3) - Replace nsBaseHashtable::EnumerateRead() calls in storage/ with iterators. r=mak. (02f472c197)
- Bug 1219238 - remove AutoArray from mozStorageSQLFunctions.cpp; r=mak (45e751d2b7)
- Bug 1166931 - JS Warning in MobileIdentityManager.jsm r=ferjm (2022d4cccd)
- var-const (b7800ec532)
- Trivial, no bug: add missing semicolon to nsBlocklistService.js to avoid a strict warning. (ee6b8a7593)
- Bug 1208242 - Part 1: hook up the blocklist service to b2g web extensions r=mossop,ferjm (d0ad653af4)
- Bug 1208242 - Part 3: don't ship things that should not ship r=me (cd75e88080)
- Bug 1009795 - Use toLocalString to format download size instead of the decimalSymbol hook; r=mak (a4b4442d2c)
- Bug 1009795 - Part 2: Revert to the old gDecimalSymbol hack if the Internationalization API is not available; r=mak (465e23f2c3)
- Bug 1116385. r=Mossop (f0a7b7d450)
- let-var (cb5d9d1d07)
- Bug 1210459: Add originAttributes for tests that implement nsILoadContext. r=bholley (ea6be1490a)
- var-let (d7d4533b53)
- Bug 1034724 - Fixed Unicode values of prefs in about:support. r=adw (1c8253ac5b)
- Bug 1153381. Add a D3D11 ANGLE blacklist. r=mstange (9008483ca5)
- add back some WIn XP and 2k3 stuff (896a4a7e9b)
- Bug 1141783 - Correct user message for mismatched drivers. Don't mismatch if the DLLs are missing. r=jrmuizelaar (872d0c3aff)
- missing members version (4771ff5f24)
- bug 1170987 - Fix gfx/2d to build on iOS. r=jrmuizel (1e555cb6b3)
- Bug 1201937 - push transform onto cairo context when evaluating path bounds. r=eihrul (6a4d8d98ec)
- Bug 1165900 - Make MaybeSnapToDevicePixels return a boolean to indicate whether snapping occurred. r=Bas (8f33f6cf7d)
- Bug 1190705 - Add crashtest for canvas 2d. r=Bas (bf3afb2acc)
- Bug 1161277 - verify SkPath is finite before doing ContainsPoint queries. r=jmuizelaar (c56f9ef322)
- Bug 1218900 - Make shell function startTimingMutator() fail with an error rather than asserting when called at the wrong time r=sfink (856e8678ce)
- small type fix (b36cfdf416)
- Bug 1214846 - Make SPSProfiler::enter() report OOM to the context r=terrence (6086f60d17)
- Bug 1218637 - IonMonkey: MIPS64: Add support into vm. r=arai (ae22538418)
- gfx: add back `AddCrashReportAnnotations()` prototype (c13f61cd8a)
This commit is contained in:
2022-12-29 09:22:12 +08:00
parent 83a04cbfb3
commit a51002fbca
241 changed files with 8266 additions and 3868 deletions
+14 -9
View File
@@ -224,22 +224,27 @@ XULDropmarkerAccessible::DropmarkerOpen(bool aToggleOpen) const
{
bool isOpen = false;
nsCOMPtr<nsIDOMXULButtonElement> parentButtonElement =
do_QueryInterface(mContent->GetFlattenedTreeParent());
nsIContent* parent = mContent->GetFlattenedTreeParent();
while (parent) {
nsCOMPtr<nsIDOMXULButtonElement> parentButtonElement =
do_QueryInterface(parent);
if (parentButtonElement) {
parentButtonElement->GetOpen(&isOpen);
if (aToggleOpen)
parentButtonElement->SetOpen(!isOpen);
return isOpen;
}
if (parentButtonElement) {
parentButtonElement->GetOpen(&isOpen);
if (aToggleOpen)
parentButtonElement->SetOpen(!isOpen);
}
else {
nsCOMPtr<nsIDOMXULMenuListElement> parentMenuListElement =
do_QueryInterface(parentButtonElement);
do_QueryInterface(parent);
if (parentMenuListElement) {
parentMenuListElement->GetOpen(&isOpen);
if (aToggleOpen)
parentMenuListElement->SetOpen(!isOpen);
return isOpen;
}
parent = parent->GetFlattenedTreeParent();
}
return isOpen;
+5
View File
@@ -1105,3 +1105,8 @@ pref("dom.performance.enable_notify_performance_timing", true);
pref("b2g.multiscreen.chrome_remote_url", "chrome://b2g/content/shell_remote.html");
pref("b2g.multiscreen.system_remote_url", "index_remote.html");
// Blocklist service
pref("extensions.blocklist.enabled", true);
pref("extensions.blocklist.interval", 86400);
pref("extensions.blocklist.url", "https://blocklist.addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/%TOTAL_PING_COUNT%/%DAYS_SINCE_LAST_PING%/");
pref("extensions.blocklist.detailsURL", "https://www.mozilla.com/%LOCALE%/blocklist/");
+3 -2
View File
@@ -545,15 +545,16 @@
#endif // MOZ_WIDGET_GONK && MOZ_B2G_RIL
#ifndef MOZ_WIDGET_GONK
@RESPATH@/components/extensions.manifest
@RESPATH@/components/addonManager.js
@RESPATH@/components/amContentHandler.js
@RESPATH@/components/amInstallTrigger.js
@RESPATH@/components/amWebInstallListener.js
@RESPATH@/components/nsBlocklistService.js
@RESPATH@/components/OopCommandLine.js
@RESPATH@/components/CommandLine.js
#endif
@RESPATH@/components/extensions.manifest
@RESPATH@/components/nsBlocklistService.js
@RESPATH@/components/BootstrapCommandLine.js
#ifdef MOZ_UPDATER
-3
View File
@@ -95,6 +95,3 @@ endif
libs:: automation.py
ifdef ENABLE_TESTS
GARBAGE += $(srcdir)/automationutils.pyc
endif # ENABLE_TESTS
+30 -5
View File
@@ -16,7 +16,6 @@ from datetime import datetime, timedelta
SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
sys.path.insert(0, SCRIPT_DIR)
import automationutils
# --------------------------------------------------------------
# TODO: this is a hack for mozbase without virtualenv, remove with bug 849900
@@ -31,6 +30,8 @@ if os.path.isdir(mozbase):
sys.path.append(package_path)
import mozcrash
from mozscreenshot import printstatus, dump_screen
# ---------------------------------------------------------------
@@ -63,6 +64,7 @@ _IS_CYGWIN = False
#expand _CERTS_SRC_DIR = __CERTS_SRC_DIR__
#expand _IS_TEST_BUILD = __IS_TEST_BUILD__
#expand _IS_DEBUG_BUILD = __IS_DEBUG_BUILD__
#expand _CRASHREPORTER = __CRASHREPORTER__ == 1
#expand _IS_ASAN = __IS_ASAN__ == 1
@@ -108,6 +110,7 @@ class Automation(object):
CERTS_SRC_DIR = _CERTS_SRC_DIR
IS_TEST_BUILD = _IS_TEST_BUILD
IS_DEBUG_BUILD = _IS_DEBUG_BUILD
CRASHREPORTER = _CRASHREPORTER
IS_ASAN = _IS_ASAN
# timeout, in seconds
@@ -225,6 +228,12 @@ class Automation(object):
if dmdPath and dmdLibrary and preloadEnvVar:
env[preloadEnvVar] = os.path.join(dmdPath, dmdLibrary)
if crashreporter and not debugger:
env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
env['MOZ_CRASHREPORTER'] = '1'
else:
env['MOZ_CRASHREPORTER_DISABLE'] = '1'
# Crash on non-local network connections by default.
# MOZ_DISABLE_NONLOCAL_CONNECTIONS can be set to "0" to temporarily
# enable non-local connections for the purposes of local testing. Don't
@@ -359,7 +368,7 @@ class Automation(object):
return
self.haveDumpedScreen = True;
automationutils.dumpScreen(utilityPath)
dump_screen(utilityPath, self.log)
def killAndGetStack(self, processPID, utilityPath, debuggerInfo):
@@ -371,6 +380,20 @@ class Automation(object):
def killAndGetStackNoScreenshot(self, processPID, utilityPath, debuggerInfo):
"""Kill the process, preferrably in a way that gets us a stack trace."""
if self.CRASHREPORTER and not debuggerInfo:
if not self.IS_WIN32:
# ABRT will get picked up by Breakpad's signal handler
os.kill(processPID, signal.SIGABRT)
return
else:
# We should have a "crashinject" program in our utility path
crashinject = os.path.normpath(os.path.join(utilityPath, "crashinject.exe"))
if os.path.exists(crashinject):
status = subprocess.Popen([crashinject, str(processPID)]).wait()
printstatus("crashinject", status)
if status == 0:
return
self.log.info("Can't trigger Breakpad, just killing process")
self.killPid(processPID)
def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath):
@@ -436,7 +459,7 @@ class Automation(object):
self.killAndGetStack(browserProcessId, utilityPath, debuggerInfo)
status = proc.wait()
automationutils.printstatus(status, "Main app process")
printstatus("Main app process", status)
if status == 0:
self.lastTestSeen = "Main app process exited normally"
if status != 0 and not didTimeout and not hitMaxTime:
@@ -507,7 +530,8 @@ class Automation(object):
xrePath = None, certPath = None,
debuggerInfo = None, symbolsPath = None,
timeout = -1, maxTime = None, onLaunch = None,
detectShutdownLeaks = False, screenshotOnFail=False, testPath=None, bisectChunk=None):
detectShutdownLeaks = False, screenshotOnFail=False, testPath=None, bisectChunk=None,
valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None):
"""
Run the app, log the duration it took to execute, return the status code.
Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.
@@ -545,7 +569,8 @@ class Automation(object):
self.lastTestSeen = "automation.py"
proc = self.Process([cmd] + args,
env = self.environment(env, xrePath = xrePath),
env = self.environment(env, xrePath = xrePath,
crashreporter = not debuggerInfo),
stdout = outputPipe,
stderr = subprocess.STDOUT)
self.log.info("INFO | automation.py | Application pid: %d", proc.pid)
-103
View File
@@ -1,103 +0,0 @@
#
# 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/.
from __future__ import with_statement
import logging
from operator import itemgetter
import os
import platform
import re
import signal
import subprocess
import sys
import tempfile
import mozinfo
__all__ = [
'dumpScreen',
"setAutomationLog",
]
log = logging.getLogger()
def resetGlobalLog():
while log.handlers:
log.removeHandler(log.handlers[0])
handler = logging.StreamHandler(sys.stdout)
log.setLevel(logging.INFO)
log.addHandler(handler)
resetGlobalLog()
def setAutomationLog(alt_logger):
global log
log = alt_logger
# Python does not provide strsignal() even in the very latest 3.x.
# This is a reasonable fake.
def strsig(n):
# Signal numbers run 0 through NSIG-1; an array with NSIG members
# has exactly that many slots
_sigtbl = [None]*signal.NSIG
for k in dir(signal):
if k.startswith("SIG") and not k.startswith("SIG_") and k != "SIGCLD" and k != "SIGPOLL":
_sigtbl[getattr(signal, k)] = k
# Realtime signals mostly have no names
if hasattr(signal, "SIGRTMIN") and hasattr(signal, "SIGRTMAX"):
for r in range(signal.SIGRTMIN+1, signal.SIGRTMAX+1):
_sigtbl[r] = "SIGRTMIN+" + str(r - signal.SIGRTMIN)
# Fill in any remaining gaps
for i in range(signal.NSIG):
if _sigtbl[i] is None:
_sigtbl[i] = "unrecognized signal, number " + str(i)
if n < 0 or n >= signal.NSIG:
return "out-of-range signal, number "+str(n)
return _sigtbl[n]
def printstatus(status, name = ""):
# 'status' is the exit status
if os.name != 'posix':
# Windows error codes are easier to look up if printed in hexadecimal
if status < 0:
status += 2**32
print "TEST-INFO | %s: exit status %x\n" % (name, status)
elif os.WIFEXITED(status):
print "TEST-INFO | %s: exit %d\n" % (name, os.WEXITSTATUS(status))
elif os.WIFSIGNALED(status):
# The python stdlib doesn't appear to have strsignal(), alas
print "TEST-INFO | {}: killed by {}".format(name,strsig(os.WTERMSIG(status)))
else:
# This is probably a can't-happen condition on Unix, but let's be defensive
print "TEST-INFO | %s: undecodable exit status %04x\n" % (name, status)
def dumpScreen(utilityPath):
"""dumps a screenshot of the entire screen to a directory specified by
the MOZ_UPLOAD_DIR environment variable"""
# Need to figure out which OS-dependent tool to use
if mozinfo.isUnix:
utility = [os.path.join(utilityPath, "screentopng")]
utilityname = "screentopng"
elif mozinfo.isMac:
utility = ['/usr/sbin/screencapture', '-C', '-x', '-t', 'png']
utilityname = "screencapture"
elif mozinfo.isWin:
utility = [os.path.join(utilityPath, "screenshot.exe")]
utilityname = "screenshot"
# Get dir where to write the screenshot file
parent_dir = os.environ.get('MOZ_UPLOAD_DIR', None)
if not parent_dir:
log.info('Failed to retrieve MOZ_UPLOAD_DIR env var')
return
# Run the capture
try:
tmpfd, imgfilename = tempfile.mkstemp(prefix='mozilla-test-fail-screenshot_', suffix='.png', dir=parent_dir)
os.close(tmpfd)
returncode = subprocess.call(utility + [imgfilename])
printstatus(returncode, utilityname)
except OSError, err:
log.info("Failed to start %s for screenshot: %s" %
utility[0], err.strerror)
return
-30
View File
@@ -1,30 +0,0 @@
#!/usr/bin/env python
"""
test dumpScreen functionality
"""
import automationutils
import optparse
import os
import sys
def main(args=sys.argv[1:]):
# parse CLI options
usage = '%prog [options] path/to/OBJDIR/dist/bin'
parser = optparse.OptionParser(usage=usage)
options, args = parser.parse_args(args)
if len(args) != 1:
parser.error("Please provide utility path")
utilityPath = args[0]
# dump the screen to a data: URL
uri = automationutils.dumpScreen(utilityPath)
# print the uri
print uri
if __name__ == '__main__':
main()
+1
View File
@@ -68,6 +68,7 @@ SEARCH_PATHS = [
'testing/mozbase/mozrunner',
'testing/mozbase/mozsystemmonitor',
'testing/mozbase/mozinfo',
'testing/mozbase/mozscreenshot',
'testing/mozbase/moztest',
'testing/mozbase/mozversion',
'testing/mozbase/manifestparser',
-3
View File
@@ -4,9 +4,6 @@
# 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/.
if CONFIG['_MSC_VER'] and CONFIG['OS_TEST'] != 'x86_64':
TEST_DIRS += ['vmwarerecordinghelper']
TEST_DIRS += ['crashinjectdll']
if CONFIG['ENABLE_TESTS']:
@@ -1,15 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
SOURCES += [
'vmwarerecordinghelper.cpp',
]
SharedLibrary('vmwarerecordinghelper')
DEFFILE = '%s/%s.def' % (SRCDIR, LIBRARY_NAME)
USE_STATIC_LIBS = True
@@ -1,34 +0,0 @@
/* 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/. */
/**
* The following code comes from "Starting and Stopping Recording of Virtual
* Machine Activity from Within the Guest":
*
* http://kb.vmware.com/selfservice/documentLink.do?externalID=1001401
*/
void __cdecl
StartRecording()
{
__asm {
mov eax, 564d5868h
mov ebx, 1
mov cx, 47
mov dx, 5658h
in eax, dx
}
}
void __cdecl
StopRecording()
{
__asm {
mov eax, 564d5868h
mov ebx, 2
mov cx, 47
mov dx, 5658h
in eax, dx
}
}
@@ -1,8 +0,0 @@
;+# 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/.
LIBRARY vmwarerecordinghelper
EXPORTS
StartRecording
StopRecording
@@ -5,7 +5,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AbstractTimelineMarker.h"
#include "mozilla/TimeStamp.h"
#include "MainThreadUtils.h"
#include "nsAppRunner.h"
namespace mozilla {
@@ -13,6 +16,8 @@ AbstractTimelineMarker::AbstractTimelineMarker(const char* aName,
MarkerTracingType aTracingType)
: mName(aName)
, mTracingType(aTracingType)
, mProcessType(XRE_GetProcessType())
, mIsOffMainThread(!NS_IsMainThread())
{
MOZ_COUNT_CTOR(AbstractTimelineMarker);
SetCurrentTime();
@@ -23,6 +28,8 @@ AbstractTimelineMarker::AbstractTimelineMarker(const char* aName,
MarkerTracingType aTracingType)
: mName(aName)
, mTracingType(aTracingType)
, mProcessType(XRE_GetProcessType())
, mIsOffMainThread(!NS_IsMainThread())
{
MOZ_COUNT_CTOR(AbstractTimelineMarker);
SetCustomTime(aTime);
@@ -68,4 +75,16 @@ AbstractTimelineMarker::SetCustomTime(DOMHighResTimeStamp aTime)
mTime = aTime;
}
void
AbstractTimelineMarker::SetProcessType(GeckoProcessType aProcessType)
{
mProcessType = aProcessType;
}
void
AbstractTimelineMarker::SetOffMainThread(bool aIsOffMainThread)
{
mIsOffMainThread = aIsOffMainThread;
}
} // namespace mozilla
@@ -9,6 +9,7 @@
#include "TimelineMarkerEnums.h" // for MarkerTracingType
#include "nsDOMNavigationTiming.h" // for DOMHighResTimeStamp
#include "nsXULAppAPI.h" // for GeckoProcessType
#include "mozilla/UniquePtr.h"
struct JSContext;
@@ -48,15 +49,23 @@ public:
DOMHighResTimeStamp GetTime() const { return mTime; }
MarkerTracingType GetTracingType() const { return mTracingType; }
const uint8_t GetProcessType() const { return mProcessType; };
const bool IsOffMainThread() const { return mIsOffMainThread; };
private:
const char* mName;
DOMHighResTimeStamp mTime;
MarkerTracingType mTracingType;
uint8_t mProcessType; // @see `enum GeckoProcessType`.
bool mIsOffMainThread;
protected:
void SetCurrentTime();
void SetCustomTime(const TimeStamp& aTime);
void SetCustomTime(DOMHighResTimeStamp aTime);
void SetProcessType(GeckoProcessType aProcessType);
void SetOffMainThread(bool aIsOffMainThread);
};
} // namespace mozilla
@@ -0,0 +1,33 @@
/* -*- 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/. */
#ifndef mozilla_CompositeTimelineMarker_h_
#define mozilla_CompositeTimelineMarker_h_
#include "TimelineMarker.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
namespace mozilla {
class CompositeTimelineMarker : public TimelineMarker
{
public:
explicit CompositeTimelineMarker(const TimeStamp& aTime,
MarkerTracingType aTracingType)
: TimelineMarker("Composite", aTime, aTracingType)
{
// Even though these markers end up being created on the main thread in the
// content or chrome processes, they actually trace down code in the
// compositor parent process. All the information for creating these markers
// is sent along via IPC to an nsView when a composite finishes.
// Mark this as 'off the main thread' to style it differently in frontends.
SetOffMainThread(true);
}
};
} // namespace mozilla
#endif // mozilla_CompositeTimelineMarker_h_
@@ -40,6 +40,8 @@ public:
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
TimelineMarker::AddDetails(aCx, aMarker);
if (GetTracingType() == MarkerTracingType::START) {
aMarker.mCauseName.Construct(mCause);
} else {
@@ -25,6 +25,8 @@ public:
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
TimelineMarker::AddDetails(aCx, aMarker);
if (GetTracingType() == MarkerTracingType::START) {
aMarker.mType.Construct(mType);
aMarker.mEventPhase.Construct(mPhase);
@@ -39,6 +39,8 @@ public:
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
TimelineMarker::AddDetails(aCx, aMarker);
aMarker.mCauseName.Construct(mCause);
if (!mFunctionName.IsEmpty() || !mFileName.IsEmpty()) {
@@ -26,6 +26,8 @@ public:
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
TimelineMarker::AddDetails(aCx, aMarker);
if (GetTracingType() == MarkerTracingType::START) {
aMarker.mRestyleHint.Construct(mRestyleHint);
}
+4 -1
View File
@@ -28,7 +28,10 @@ TimelineMarker::TimelineMarker(const char* aName,
void
TimelineMarker::AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker)
{
// Nothing to do here for plain markers.
if (GetTracingType() == MarkerTracingType::START) {
aMarker.mProcessType.Construct(GetProcessType());
aMarker.mIsOffMainThread.Construct(IsOffMainThread());
}
}
JSObject*
@@ -22,6 +22,8 @@ public:
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
TimelineMarker::AddDetails(aCx, aMarker);
if (!mCause.IsEmpty()) {
aMarker.mCauseName.Construct(mCause);
}
@@ -30,6 +30,8 @@ public:
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
TimelineMarker::AddDetails(aCx, aMarker);
if (GetTracingType() == MarkerTracingType::START) {
aMarker.mWorkerOperation.Construct(mOperationType);
}
+1
View File
@@ -8,6 +8,7 @@ EXPORTS.mozilla += [
'AbstractTimelineMarker.h',
'AutoGlobalTimelineMarker.h',
'AutoTimelineMarker.h',
'CompositeTimelineMarker.h',
'ConsoleTimelineMarker.h',
'EventTimelineMarker.h',
'JavascriptTimelineMarker.h',
+1 -1
View File
@@ -1,5 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
skip-if = buildapp == 'b2g' || os == 'android'
support-files =
662200a.html
662200b.html
@@ -993,12 +993,6 @@ Convert(const ConvertArray<Tin>& aIn, Tout& aOut)
// Packing
//
nsresult
PackPDU(bool aIn, DaemonSocketPDU& aPDU)
{
return PackPDU(PackConversion<bool, uint8_t>(aIn), aPDU);
}
nsresult
PackPDU(const BluetoothAddress& aIn, DaemonSocketPDU& aPDU)
{
@@ -1366,18 +1360,6 @@ PackPDU(BluetoothGattWriteType aIn, DaemonSocketPDU& aPDU)
// Unpacking
//
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, bool& aOut)
{
return UnpackPDU(aPDU, UnpackConversion<uint8_t, bool>(aOut));
}
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, char& aOut)
{
return UnpackPDU(aPDU, UnpackConversion<uint8_t, char>(aOut));
}
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, BluetoothA2dpAudioState& aOut)
{
@@ -270,9 +270,6 @@ Convert(nsresult aIn, BluetoothStatus& aOut);
// Packing
//
nsresult
PackPDU(bool aIn, DaemonSocketPDU& aPDU);
nsresult
PackPDU(const BluetoothAddress& aIn, DaemonSocketPDU& aPDU);
@@ -380,147 +377,11 @@ PackPDU(BluetoothGattWriteType aIn, DaemonSocketPDU& aPDU);
nsresult
PackPDU(BluetoothTransport aIn, DaemonSocketPDU& aPDU);
/* |PackConversion| is a helper for packing converted values. Pass
* an instance of this structure to |PackPDU| to convert a value from
* the input type to the output type and and write it to the PDU.
*/
template<typename Tin, typename Tout>
struct PackConversion {
PackConversion(const Tin& aIn)
: mIn(aIn)
{ }
const Tin& mIn;
};
template<typename Tin, typename Tout>
inline nsresult
PackPDU(const PackConversion<Tin, Tout>& aIn, DaemonSocketPDU& aPDU)
{
Tout out;
nsresult rv = Convert(aIn.mIn, out);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(out, aPDU);
}
/* |PackArray| is a helper for packing arrays. Pass an instance
* of this structure as the first argument to |PackPDU| to pack
* an array. The array's maximum default length is 255 elements.
*/
template <typename T>
struct PackArray
{
PackArray(const T* aData, size_t aLength)
: mData(aData)
, mLength(aLength)
{ }
const T* mData;
size_t mLength;
};
/* This implementation of |PackPDU| packs the length of an array
* and the elements of the array one-by-one.
*/
template<typename T>
inline nsresult
PackPDU(const PackArray<T>& aIn, DaemonSocketPDU& aPDU)
{
for (size_t i = 0; i < aIn.mLength; ++i) {
nsresult rv = PackPDU(aIn.mData[i], aPDU);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
template<>
inline nsresult
PackPDU<uint8_t>(const PackArray<uint8_t>& aIn, DaemonSocketPDU& aPDU)
{
/* Write raw bytes in one pass */
return aPDU.Write(aIn.mData, aIn.mLength);
}
template<>
inline nsresult
PackPDU<char>(const PackArray<char>& aIn, DaemonSocketPDU& aPDU)
{
/* Write raw bytes in one pass */
return aPDU.Write(aIn.mData, aIn.mLength);
}
/* |PackCString0| is a helper for packing 0-terminated C string,
* including the \0 character. Pass an instance of this structure
* as the first argument to |PackPDU| to pack a string.
*/
struct PackCString0
{
PackCString0(const nsCString& aString)
: mString(aString)
{ }
const nsCString& mString;
};
/* This implementation of |PackPDU| packs a 0-terminated C string.
*/
inline nsresult
PackPDU(const PackCString0& aIn, DaemonSocketPDU& aPDU)
{
return PackPDU(
PackArray<uint8_t>(reinterpret_cast<const uint8_t*>(aIn.mString.get()),
aIn.mString.Length() + 1), aPDU);
}
/* |PackReversed| is a helper for packing data in reversed order. Pass an
* instance of this structure as the first argument to |PackPDU| to pack data
* in reversed order.
*/
template<typename T>
struct PackReversed
{
PackReversed(const T& aValue)
: mValue(aValue)
{ }
const T& mValue;
};
/* No general rules to pack data in reversed order. Signal a link error if the
* type |T| of |PackReversed| is not defined explicitly.
*/
template<typename T>
nsresult
PackPDU(const PackReversed<T>& aIn, DaemonSocketPDU& aPDU);
/* This implementation of |PackPDU| packs elements in |PackArray| in reversed
* order. (ex. reversed GATT UUID, see bug 1171866)
*/
template<typename U>
inline nsresult
PackPDU(const PackReversed<PackArray<U>>& aIn, DaemonSocketPDU& aPDU)
{
for (size_t i = 0; i < aIn.mValue.mLength; ++i) {
nsresult rv = PackPDU(aIn.mValue.mData[aIn.mValue.mLength - i - 1], aPDU);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
/* This implementation of |PackPDU| packs |BluetoothUuid| in reversed order.
* (ex. reversed GATT UUID, see bug 1171866)
*/
template <>
inline nsresult
PackPDU<BluetoothUuid>(const PackReversed<BluetoothUuid>& aIn,
DaemonSocketPDU& aPDU)
PackPDU(const PackReversed<BluetoothUuid>& aIn, DaemonSocketPDU& aPDU)
{
return PackPDU(
PackReversed<PackArray<uint8_t>>(
@@ -528,256 +389,10 @@ PackPDU<BluetoothUuid>(const PackReversed<BluetoothUuid>& aIn,
aPDU);
}
template <typename T1, typename T2>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn2, aPDU);
}
template <typename T1, typename T2, typename T3>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn3, aPDU);
}
template <typename T1, typename T2, typename T3, typename T4>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3, const T4& aIn4,
DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn3, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn4, aPDU);
}
template <typename T1, typename T2, typename T3,
typename T4, typename T5>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
const T4& aIn4, const T5& aIn5,
DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn3, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn4, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn5, aPDU);
}
template <typename T1, typename T2, typename T3,
typename T4, typename T5, typename T6>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
const T4& aIn4, const T5& aIn5, const T6& aIn6,
DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn3, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn4, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn5, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn6, aPDU);
}
template <typename T1, typename T2, typename T3,
typename T4, typename T5, typename T6,
typename T7>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
const T4& aIn4, const T5& aIn5, const T6& aIn6,
const T7& aIn7, DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn3, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn4, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn5, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn6, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn7, aPDU);
}
template <typename T1, typename T2, typename T3,
typename T4, typename T5, typename T6,
typename T7, typename T8>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
const T4& aIn4, const T5& aIn5, const T6& aIn6,
const T7& aIn7, const T8& aIn8, DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn3, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn4, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn5, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn6, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn7, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn8, aPDU);
}
template <typename T1, typename T2, typename T3,
typename T4, typename T5, typename T6,
typename T7, typename T8, typename T9,
typename T10, typename T11, typename T12,
typename T13>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
const T4& aIn4, const T5& aIn5, const T6& aIn6,
const T7& aIn7, const T8& aIn8, const T9& aIn9,
const T10& aIn10, const T11& aIn11, const T12& aIn12,
const T13& aIn13, DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn3, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn4, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn5, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn6, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn7, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn8, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn9, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn10, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn11, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn12, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn13, aPDU);
}
//
// Unpacking
//
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, bool& aOut);
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, char& aOut);
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, BluetoothA2dpAudioState& aOut);
@@ -887,156 +502,11 @@ UnpackPDU(DaemonSocketPDU& aPDU, BluetoothGattWriteParam& aOut);
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, BluetoothGattNotifyParam& aOut);
/* |UnpackConversion| is a helper for convering unpacked values. Pass
* an instance of this structure to |UnpackPDU| to read a value from
* the PDU in the input type and convert it to the output type.
*/
template<typename Tin, typename Tout>
struct UnpackConversion {
UnpackConversion(Tout& aOut)
: mOut(aOut)
{ }
Tout& mOut;
};
template<typename Tin, typename Tout>
inline nsresult
UnpackPDU(DaemonSocketPDU& aPDU, const UnpackConversion<Tin, Tout>& aOut)
{
Tin in;
nsresult rv = UnpackPDU(aPDU, in);
if (NS_FAILED(rv)) {
return rv;
}
return Convert(in, aOut.mOut);
}
/* |UnpackArray| is a helper for unpacking arrays. Pass an instance
* of this structure as the second argument to |UnpackPDU| to unpack
* an array.
*/
template <typename T>
struct UnpackArray
{
UnpackArray(T* aData, size_t aLength)
: mData(aData)
, mLength(aLength)
{ }
UnpackArray(nsAutoArrayPtr<T>& aData, size_t aLength)
: mData(nullptr)
, mLength(aLength)
{
aData = new T[mLength];
mData = aData.get();
}
UnpackArray(nsAutoArrayPtr<T>& aData, size_t aSize, size_t aElemSize)
: mData(nullptr)
, mLength(aSize / aElemSize)
{
aData = new T[mLength];
mData = aData.get();
}
T* mData;
size_t mLength;
};
template<typename T>
inline nsresult
UnpackPDU(DaemonSocketPDU& aPDU, const UnpackArray<T>& aOut)
{
for (size_t i = 0; i < aOut.mLength; ++i) {
nsresult rv = UnpackPDU(aPDU, aOut.mData[i]);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
template<typename T>
inline nsresult
UnpackPDU(DaemonSocketPDU& aPDU, UnpackArray<T>& aOut)
{
for (size_t i = 0; i < aOut.mLength; ++i) {
nsresult rv = UnpackPDU(aPDU, aOut.mData[i]);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
template<>
inline nsresult
UnpackPDU<uint8_t>(DaemonSocketPDU& aPDU, const UnpackArray<uint8_t>& aOut)
{
/* Read raw bytes in one pass */
return aPDU.Read(aOut.mData, aOut.mLength);
}
template<typename T>
inline nsresult
UnpackPDU(DaemonSocketPDU& aPDU, nsTArray<T>& aOut)
{
for (typename nsTArray<T>::size_type i = 0; i < aOut.Length(); ++i) {
nsresult rv = UnpackPDU(aPDU, aOut[i]);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
/* |UnpackReversed| is a helper for unpacking data in reversed order. Pass an
* instance of this structure as the second argument to |UnpackPDU| to unpack
* data in reversed order.
*/
template<typename T>
struct UnpackReversed
{
UnpackReversed(T& aValue)
: mValue(&aValue)
{ }
UnpackReversed(T&& aValue)
: mValue(&aValue)
{ }
T* mValue;
};
/* No general rules to unpack data in reversed order. Signal a link error if
* the type |T| of |UnpackReversed| is not defined explicitly.
*/
template<typename T>
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, const UnpackReversed<T>& aOut);
template<typename U>
inline nsresult
UnpackPDU(DaemonSocketPDU& aPDU, const UnpackReversed<UnpackArray<U>>& aOut)
{
for (size_t i = 0; i < aOut.mValue->mLength; ++i) {
nsresult rv = UnpackPDU(aPDU,
aOut.mValue->mData[aOut.mValue->mLength - i - 1]);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
/* This implementation of |UnpackPDU| unpacks |BluetoothUuid| in reversed
* order. (ex. reversed GATT UUID, see bug 1171866)
*/
template<>
inline nsresult
UnpackPDU<BluetoothUuid>(DaemonSocketPDU& aPDU,
const UnpackReversed<BluetoothUuid>& aOut)
UnpackPDU(DaemonSocketPDU& aPDU, const UnpackReversed<BluetoothUuid>& aOut)
{
return UnpackPDU(
aPDU,
@@ -1044,132 +514,6 @@ UnpackPDU<BluetoothUuid>(DaemonSocketPDU& aPDU,
UnpackArray<uint8_t>(aOut.mValue->mUuid, sizeof(aOut.mValue->mUuid))));
}
//
// Init operators
//
// |UnpackPDUInitOp| is a general-purpose init operator for all variants
// of |BluetoothResultRunnable| and |BluetoothNotificationRunnable|. The
// call operators of |UnpackPDUInitOp| unpack a PDU into the supplied
// arguments.
class UnpackPDUInitOp final : private PDUInitOp
{
public:
UnpackPDUInitOp(DaemonSocketPDU& aPDU)
: PDUInitOp(aPDU)
{ }
nsresult operator () () const
{
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1>
nsresult operator () (T1& aArg1) const
{
nsresult rv = UnpackPDU(GetPDU(), aArg1);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1, typename T2>
nsresult operator () (T1& aArg1, T2& aArg2) const
{
DaemonSocketPDU& pdu = GetPDU();
nsresult rv = UnpackPDU(pdu, aArg1);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg2);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1, typename T2, typename T3>
nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3) const
{
DaemonSocketPDU& pdu = GetPDU();
nsresult rv = UnpackPDU(pdu, aArg1);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg2);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg3);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1, typename T2, typename T3, typename T4>
nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4) const
{
DaemonSocketPDU& pdu = GetPDU();
nsresult rv = UnpackPDU(pdu, aArg1);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg2);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg3);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg4);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1, typename T2, typename T3, typename T4, typename T5>
nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
T5& aArg5) const
{
DaemonSocketPDU& pdu = GetPDU();
nsresult rv = UnpackPDU(pdu, aArg1);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg2);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg3);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg4);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg5);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
};
END_BLUETOOTH_NAMESPACE
#endif // mozilla_dom_bluetooth_bluedroid_BluetoothDaemonHelpers_h
+22
View File
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<script>
function boom()
{
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.setTransform(0.2988847856952777, 26589683732.25, -562949953421312, 5, 4503599627370495, -2735897607.139075);
ctx.bezierCurveTo(-1023, -4611686018427388000, 4194303, -536870911, 45139.65058316886, 35184372088833);
ctx.setLineDash([1.2307692307692308]);
ctx.setTransform(0, 2097152, 0.0005128205128205128, 305943.4982061649, -49282.263290019946, 3);
ctx.clip("evenodd");
ctx.scale(-2.3882113703861325, -2);
ctx.isPointInStroke(2, 86124313031369.77);
}
</script>
</head>
<body onload="boom();"></body>
</html>
+17
View File
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<script>
function boom()
{
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.rotate(1e308);
ctx.fillText("A", 1, 1);
}
</script>
</head>
<body onload="boom();"></body>
</html>
+3
View File
@@ -20,4 +20,7 @@ load 896047-2.html
load 916128-1.html
load 934939-1.html
load 1099143-1.html
load 1161277-1.html
load 1183363.html
load 1190705.html
+1 -1
View File
@@ -6,4 +6,4 @@ support-files =
skip-if = e10s
[test_ipc.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 910661 # b2g(nested ipc not working) b2g-debug(debug-only failure) b2g-desktop(nested ipc not working)
skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 910661 # b2g(nested ipc not working) b2g-debug(debug-only failure) b2g-desktop(nested ipc not working)
+3
View File
@@ -99,7 +99,10 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video suppo
[test_peerConnection_captureStream_canvas_webgl.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_close.html]
[test_peerConnection_closeDuringIce.html]
[test_peerConnection_errorCallbacks.html]
[test_peerConnection_iceFailure.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || os == 'linux' || os == 'mac' || os == 'win' || android_version == '18' # Disabling because of test failures on B2G emulator (Bug 1180388 for win, mac and linux), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_forwarding_basicAudioVideoCombined.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_noTrickleAnswer.html]
+1 -1
View File
@@ -405,7 +405,7 @@ var commandsPeerConnectionOfferAnswer = [
},
function PC_LOCAL_SET_REMOTE_DESCRIPTION(test) {
test.setRemoteDescription(test.pcLocal, test._remote_answer, STABLE)
return test.setRemoteDescription(test.pcLocal, test._remote_answer, STABLE)
.then(() => {
is(test.pcLocal.signalingState, STABLE,
"signalingState after local setRemoteDescription is 'stable'");
@@ -0,0 +1,79 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="pc.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
createHTML({
bug: "1087629",
title: "Close PCs during ICE connectivity check"
});
// Test closeDuringIce to simulate problems during peer connections
function PC_LOCAL_SETUP_NULL_ICE_HANDLER(test) {
test.pcLocal.setupIceCandidateHandler(test, function() {}, function () {});
}
function PC_REMOTE_SETUP_NULL_ICE_HANDLER(test) {
test.pcRemote.setupIceCandidateHandler(test, function() {}, function () {});
}
function PC_REMOTE_ADD_FAKE_ICE_CANDIDATE(test) {
var cand = new mozRTCIceCandidate({"candidate":"candidate:0 1 UDP 2130379007 192.0.2.1 12345 typ host","sdpMid":"","sdpMLineIndex":0});
test.pcRemote.storeOrAddIceCandidate(cand);
info(test.pcRemote + " Stored fake candidate: " + JSON.stringify(cand));
}
function PC_LOCAL_ADD_FAKE_ICE_CANDIDATE(test) {
var cand = new mozRTCIceCandidate({"candidate":"candidate:0 1 UDP 2130379007 192.0.2.2 56789 typ host","sdpMid":"","sdpMLineIndex":0});
test.pcLocal.storeOrAddIceCandidate(cand);
info(test.pcLocal + " Stored fake candidate: " + JSON.stringify(cand));
}
function PC_LOCAL_CLOSE_DURING_ICE(test) {
return test.pcLocal.iceChecking.then(() => {
test.pcLocal.onsignalingstatechange = function () {};
test.pcLocal.close();
});
}
function PC_REMOTE_CLOSE_DURING_ICE(test) {
return test.pcRemote.iceChecking.then(() => {
test.pcRemote.onsignalingstatechange = function () {};
test.pcRemote.close();
});
}
function PC_LOCAL_WAIT_FOR_ICE_CHECKING(test) {
var resolveIceChecking;
test.pcLocal.iceChecking = new Promise(r => resolveIceChecking = r);
test.pcLocal.ice_connection_callbacks.checkIceStatus = () => {
if (test.pcLocal._pc.iceConnectionState === "checking") {
resolveIceChecking();
}
}
}
function PC_REMOTE_WAIT_FOR_ICE_CHECKING(test) {
var resolveIceChecking;
test.pcRemote.iceChecking = new Promise(r => resolveIceChecking = r);
test.pcRemote.ice_connection_callbacks.checkIceStatus = () => {
if (test.pcRemote._pc.iceConnectionState === "checking") {
resolveIceChecking();
}
}
}
runNetworkTest(() => {
var test = new PeerConnectionTest();
test.setMediaConstraints([{audio: true}], [{audio: true}]);
test.chain.replace("PC_LOCAL_SETUP_ICE_HANDLER", PC_LOCAL_SETUP_NULL_ICE_HANDLER);
test.chain.replace("PC_REMOTE_SETUP_ICE_HANDLER", PC_REMOTE_SETUP_NULL_ICE_HANDLER);
test.chain.insertAfter("PC_REMOTE_SETUP_NULL_ICE_HANDLER", PC_LOCAL_WAIT_FOR_ICE_CHECKING);
test.chain.insertAfter("PC_LOCAL_WAIT_FOR_ICE_CHECKING", PC_REMOTE_WAIT_FOR_ICE_CHECKING);
test.chain.removeAfter("PC_LOCAL_SET_REMOTE_DESCRIPTION");
test.chain.append([PC_REMOTE_ADD_FAKE_ICE_CANDIDATE, PC_LOCAL_ADD_FAKE_ICE_CANDIDATE,
PC_LOCAL_CLOSE_DURING_ICE, PC_REMOTE_CLOSE_DURING_ICE]);
test.run();
});
</script>
</pre>
</body>
</html>
@@ -0,0 +1,83 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="pc.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
createHTML({
bug: "1087629",
title: "Wait for ICE failure"
});
// Test iceFailure
function PC_LOCAL_SETUP_NULL_ICE_HANDLER(test) {
test.pcLocal.setupIceCandidateHandler(test, function() {}, function () {});
}
function PC_REMOTE_SETUP_NULL_ICE_HANDLER(test) {
test.pcRemote.setupIceCandidateHandler(test, function() {}, function () {});
}
function PC_REMOTE_ADD_FAKE_ICE_CANDIDATE(test) {
var cand = new mozRTCIceCandidate({"candidate":"candidate:0 1 UDP 2130379007 192.0.2.1 12345 typ host","sdpMid":"","sdpMLineIndex":0});
test.pcRemote.storeOrAddIceCandidate(cand);
info(test.pcRemote + " Stored fake candidate: " + JSON.stringify(cand));
}
function PC_LOCAL_ADD_FAKE_ICE_CANDIDATE(test) {
var cand = new mozRTCIceCandidate({"candidate":"candidate:0 1 UDP 2130379007 192.0.2.2 56789 typ host","sdpMid":"","sdpMLineIndex":0});
test.pcLocal.storeOrAddIceCandidate(cand);
info(test.pcLocal + " Stored fake candidate: " + JSON.stringify(cand));
}
function PC_LOCAL_WAIT_FOR_ICE_FAILURE(test) {
return test.pcLocal.iceFailed.then(() => {
ok(true, this.pcLocal + " Ice Failure Reached.");
});
}
function PC_REMOTE_WAIT_FOR_ICE_FAILURE(test) {
return test.pcRemote.iceFailed.then(() => {
ok(true, this.pcRemote + " Ice Failure Reached.");
});
}
function PC_LOCAL_WAIT_FOR_ICE_FAILED(test) {
var resolveIceFailed;
test.pcLocal.iceFailed = new Promise(r => resolveIceFailed = r);
test.pcLocal.ice_connection_callbacks.checkIceStatus = () => {
if (test.pcLocal._pc.iceConnectionState === "failed") {
resolveIceFailed();
}
}
}
function PC_REMOTE_WAIT_FOR_ICE_FAILED(test) {
var resolveIceFailed;
test.pcRemote.iceFailed = new Promise(r => resolveIceFailed = r);
test.pcRemote.ice_connection_callbacks.checkIceStatus = () => {
if (test.pcRemote._pc.iceConnectionState === "failed") {
resolveIceFailed();
}
}
}
runNetworkTest(() => {
SpecialPowers.pushPrefEnv({
'set': [
['media.peerconnection.ice.stun_client_maximum_transmits', 3],
['media.peerconnection.ice.trickle_grace_period', 3000],
]
}, function() {
var test = new PeerConnectionTest();
test.setMediaConstraints([{audio: true}], [{audio: true}]);
test.chain.replace("PC_LOCAL_SETUP_ICE_HANDLER", PC_LOCAL_SETUP_NULL_ICE_HANDLER);
test.chain.replace("PC_REMOTE_SETUP_ICE_HANDLER", PC_REMOTE_SETUP_NULL_ICE_HANDLER);
test.chain.insertAfter("PC_REMOTE_SETUP_NULL_ICE_HANDLER", PC_LOCAL_WAIT_FOR_ICE_FAILED);
test.chain.insertAfter("PC_LOCAL_WAIT_FOR_ICE_FAILED", PC_REMOTE_WAIT_FOR_ICE_FAILED);
test.chain.removeAfter("PC_LOCAL_SET_REMOTE_DESCRIPTION");
test.chain.append([PC_REMOTE_ADD_FAKE_ICE_CANDIDATE, PC_LOCAL_ADD_FAKE_ICE_CANDIDATE,
PC_LOCAL_WAIT_FOR_ICE_FAILURE, PC_REMOTE_WAIT_FOR_ICE_FAILURE]);
test.run();
});
});
</script>
</pre>
</body>
</html>
@@ -25,4 +25,4 @@ support-files =
iframe_differentDOM.html
[test_pointerlock-api.html]
skip-if = toolkit == "windows" || buildapp == 'b2g' || toolkit == 'android' || e10s # B2G - window.open focus issues using fullscreen, Windows - bug 919106 & bug 931445
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s || os == 'linux' || os == 'win' # B2G - window.open focus issues using fullscreen. (For Linux & Win) Bug1180351
+3
View File
@@ -38,6 +38,9 @@ dictionary ProfileTimelineMarker {
DOMHighResTimeStamp end = 0;
object? stack = null;
unsigned short processType;
boolean isOffMainThread;
/* For ConsoleTime, Timestamp and Javascript markers. */
DOMString causeName;
+4
View File
@@ -171,6 +171,10 @@ function LoadContextCallback(appId, inBrowserElement, isPrivate, isContent) {
this.isInBrowserElement = inBrowserElement;
this.usePrivateBrowsing = isPrivate;
this.isContent = isContent;
this.originAttributes = {
appId: appId,
inBrowser: inBrowserElement
};
}
LoadContextCallback.prototype = {
+1 -1
View File
@@ -1268,7 +1268,7 @@ public:
static bool DoesBackendSupportDataDrawtarget(BackendType aType);
#ifdef XP_MACOSX
#ifdef XP_DARWIN
static already_AddRefed<DrawTarget> CreateDrawTargetForCairoCGContext(CGContextRef cg, const IntSize& aSize);
static already_AddRefed<GlyphRenderingOptions>
CreateCGGlyphRenderingOptions(const Color &aFontSmoothingBackgroundColor);
+1 -1
View File
@@ -137,7 +137,7 @@ private:
};
#endif
#ifdef XP_MACOSX
#ifdef XP_DARWIN
/* This is a helper class that let's you borrow a CGContextRef from a
* DrawTargetCG. This is used for drawing themed widgets.
*
+21
View File
@@ -3,6 +3,7 @@
* 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 <dlfcn.h>
#include "BorrowedContext.h"
#include "DataSurfaceHelpers.h"
#include "DrawTargetCG.h"
@@ -177,6 +178,7 @@ DrawTargetCG::GetType() const
BackendType
DrawTargetCG::GetBackendType() const
{
#ifdef MOZ_WIDGET_COCOA
// It may be worth spliting Bitmap and IOSurface DrawTarget
// into seperate classes.
if (GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) {
@@ -184,15 +186,20 @@ DrawTargetCG::GetBackendType() const
} else {
return BackendType::COREGRAPHICS;
}
#else
return BackendType::COREGRAPHICS;
#endif
}
already_AddRefed<SourceSurface>
DrawTargetCG::Snapshot()
{
if (!mSnapshot) {
#ifdef MOZ_WIDGET_COCOA
if (GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) {
return MakeAndAddRef<SourceSurfaceCGIOSurfaceContext>(this);
}
#endif
Flush();
mSnapshot = new SourceSurfaceCGBitmapContext(this);
}
@@ -1717,12 +1724,14 @@ DrawTargetCG::Init(BackendType aType,
mSize = aSize;
#ifdef MOZ_WIDGET_COCOA
if (aType == BackendType::COREGRAPHICS_ACCELERATED) {
RefPtr<MacIOSurface> ioSurface = MacIOSurface::CreateIOSurface(aSize.width, aSize.height);
mCg = ioSurface->CreateIOSurfaceContext();
// If we don't have the symbol for 'CreateIOSurfaceContext' mCg will be null
// and we will fallback to software below
}
#endif
mFormat = SurfaceFormat::B8G8R8A8;
@@ -1820,6 +1829,7 @@ EnsureValidPremultipliedData(CGContextRef aContext)
void
DrawTargetCG::Flush()
{
#ifdef MOZ_WIDGET_COCOA
if (GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) {
CGContextFlush(mCg);
} else if (GetContextType(mCg) == CG_CONTEXT_TYPE_BITMAP &&
@@ -1835,6 +1845,9 @@ DrawTargetCG::Flush()
EnsureValidPremultipliedData(mCg);
mMayContainInvalidPremultipliedData = false;
}
#else
//TODO
#endif
}
bool
@@ -1874,7 +1887,9 @@ DrawTargetCG::Init(CGContextRef cgContext, const IntSize &aSize)
mOriginalTransform = CGContextGetCTM(mCg);
mFormat = SurfaceFormat::B8G8R8A8;
#ifdef MOZ_WIDGET_COCOA
if (GetContextType(mCg) == CG_CONTEXT_TYPE_BITMAP) {
#endif
CGColorSpaceRef colorspace;
CGBitmapInfo bitinfo = CGBitmapContextGetBitmapInfo(mCg);
colorspace = CGBitmapContextGetColorSpace (mCg);
@@ -1883,7 +1898,9 @@ DrawTargetCG::Init(CGContextRef cgContext, const IntSize &aSize)
} else if ((bitinfo & kCGBitmapAlphaInfoMask) == kCGImageAlphaNoneSkipFirst) {
mFormat = SurfaceFormat::B8G8R8X8;
}
#ifdef MOZ_WIDGET_COCOA
}
#endif
return true;
}
@@ -1906,12 +1923,16 @@ DrawTargetCG::CreatePathBuilder(FillRule aFillRule) const
void*
DrawTargetCG::GetNativeSurface(NativeSurfaceType aType)
{
#ifdef MOZ_WIDGET_COCOA
if ((aType == NativeSurfaceType::CGCONTEXT && GetContextType(mCg) == CG_CONTEXT_TYPE_BITMAP) ||
(aType == NativeSurfaceType::CGCONTEXT_ACCELERATED && GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE)) {
return mCg;
} else {
return nullptr;
}
#else
return mCg;
#endif
}
void
+7
View File
@@ -6,7 +6,14 @@
#ifndef mozilla_gfx_DrawTargetCG_h
#define mozilla_gfx_DrawTargetCG_h
#ifdef MOZ_WIDGET_COCOA
#include <ApplicationServices/ApplicationServices.h>
#import <OpenGL/OpenGL.h>
#else
#include <CoreGraphics/CoreGraphics.h>
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#endif
#include "2D.h"
#include "Rect.h"
+2
View File
@@ -24,8 +24,10 @@
#ifdef CAIRO_HAS_QUARTZ_SURFACE
#include "cairo-quartz.h"
#ifdef MOZ_WIDGET_COCOA
#include <ApplicationServices/ApplicationServices.h>
#endif
#endif
#ifdef CAIRO_HAS_XLIB_SURFACE
#include "cairo-xlib.h"
+6 -6
View File
@@ -23,12 +23,12 @@
#include "ScaledFontWin.h"
#endif
#ifdef XP_MACOSX
#ifdef XP_DARWIN
#include "ScaledFontMac.h"
#endif
#ifdef XP_MACOSX
#ifdef XP_DARWIN
#include "DrawTargetCG.h"
#endif
@@ -347,7 +347,7 @@ Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFor
}
break;
}
#elif defined XP_MACOSX
#elif defined XP_DARWIN
case BackendType::COREGRAPHICS:
case BackendType::COREGRAPHICS_ACCELERATED:
{
@@ -430,7 +430,7 @@ Factory::CreateDrawTargetForData(BackendType aBackend,
break;
}
#endif
#ifdef XP_MACOSX
#ifdef XP_DARWIN
case BackendType::COREGRAPHICS:
{
RefPtr<DrawTargetCG> newTarget = new DrawTargetCG();
@@ -537,7 +537,7 @@ Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSiz
}
#endif
#endif
#ifdef XP_MACOSX
#ifdef XP_DARWIN
case NativeFontType::MAC_FONT_FACE:
{
return MakeAndAddRef<ScaledFontMac>(static_cast<CGFontRef>(aNativeFont.mFont), aSize);
@@ -839,7 +839,7 @@ Factory::CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSiz
return retVal.forget();
}
#ifdef XP_MACOSX
#ifdef XP_DARWIN
already_AddRefed<DrawTarget>
Factory::CreateDrawTargetForCairoCGContext(CGContextRef cg, const IntSize& aSize)
{
+19 -8
View File
@@ -6,10 +6,23 @@
#ifndef MacIOSurface_h__
#define MacIOSurface_h__
#ifdef XP_MACOSX
#ifdef XP_DARWIN
#include <QuartzCore/QuartzCore.h>
#include <CoreVideo/CoreVideo.h>
#include <dlfcn.h>
struct _CGLContextObject;
typedef _CGLContextObject* CGLContextObj;
typedef struct CGContext* CGContextRef;
typedef struct CGImage* CGImageRef;
typedef uint32_t IOSurfaceID;
#ifdef XP_IOS
typedef kern_return_t IOReturn;
typedef int CGLError;
#endif
typedef CFTypeRef IOSurfacePtr;
typedef IOSurfacePtr (*IOSurfaceCreateFunc) (CFDictionaryRef properties);
typedef IOSurfacePtr (*IOSurfaceLookupFunc) (uint32_t io_surface_id);
@@ -42,18 +55,16 @@ typedef IOSurfacePtr (*CVPixelBufferGetIOSurfaceFunc)(
typedef OSType (*IOSurfacePixelFormatFunc)(IOSurfacePtr io_surface);
#ifdef XP_MACOSX
#import <OpenGL/OpenGL.h>
#else
#import <OpenGLES/ES2/gl.h>
#endif
#include "2D.h"
#include "mozilla/RefPtr.h"
#include "mozilla/RefCounted.h"
struct _CGLContextObject;
typedef _CGLContextObject* CGLContextObj;
typedef struct CGContext* CGContextRef;
typedef struct CGImage* CGImageRef;
typedef uint32_t IOSurfaceID;
enum CGContextType {
CG_CONTEXT_TYPE_UNKNOWN = 0,
// These are found by inspection, it's possible they could be changed
+7
View File
@@ -265,6 +265,13 @@ public:
return !(*this == other);
}
bool ExactlyEquals(const Matrix& o) const
{
return _11 == o._11 && _12 == o._12 &&
_21 == o._21 && _22 == o._22 &&
_31 == o._31 && _32 == o._32;
}
/* Verifies that the matrix contains no Infs or NaNs. */
bool IsFinite() const
{
+5
View File
@@ -6,7 +6,12 @@
#ifndef MOZILLA_GFX_PATHCG_H_
#define MOZILLA_GFX_PATHCG_H_
#ifdef MOZ_WIDGET_COCOA
#include <ApplicationServices/ApplicationServices.h>
#else
#include <CoreGraphics/CoreGraphics.h>
#endif
#include "2D.h"
namespace mozilla {
+15 -7
View File
@@ -188,7 +188,7 @@ PathCairo::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
inverse.Invert();
Point transformed = inverse * aPoint;
EnsureContainingContext();
EnsureContainingContext(aTransform);
return cairo_in_fill(mContainingContext, transformed.x, transformed.y);
}
@@ -202,7 +202,7 @@ PathCairo::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
inverse.Invert();
Point transformed = inverse * aPoint;
EnsureContainingContext();
EnsureContainingContext(aTransform);
SetCairoStrokeOptions(mContainingContext, aStrokeOptions);
@@ -212,7 +212,7 @@ PathCairo::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
Rect
PathCairo::GetBounds(const Matrix &aTransform) const
{
EnsureContainingContext();
EnsureContainingContext(aTransform);
double x1, y1, x2, y2;
@@ -225,7 +225,7 @@ Rect
PathCairo::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
const Matrix &aTransform) const
{
EnsureContainingContext();
EnsureContainingContext(aTransform);
double x1, y1, x2, y2;
@@ -266,13 +266,21 @@ PathCairo::StreamToSink(PathSink *aSink) const
}
void
PathCairo::EnsureContainingContext() const
PathCairo::EnsureContainingContext(const Matrix &aTransform) const
{
if (mContainingContext) {
return;
if (mContainingTransform.ExactlyEquals(aTransform)) {
return;
}
} else {
mContainingContext = cairo_create(DrawTargetCairo::GetDummySurface());
}
mContainingContext = cairo_create(DrawTargetCairo::GetDummySurface());
mContainingTransform = aTransform;
cairo_matrix_t mat;
GfxMatrixToCairoMatrix(mContainingTransform, mat);
cairo_set_matrix(mContainingContext, &mat);
SetPathOnContext(mContainingContext);
}
+2 -1
View File
@@ -80,11 +80,12 @@ public:
void AppendPathToBuilder(PathBuilderCairo *aBuilder, const Matrix *aTransform = nullptr) const;
private:
void EnsureContainingContext() const;
void EnsureContainingContext(const Matrix &aTransform) const;
FillRule mFillRule;
std::vector<cairo_path_data_t> mPathData;
mutable cairo_t *mContainingContext;
mutable Matrix mContainingTransform;
Point mCurrentPoint;
};
+3 -1
View File
@@ -401,7 +401,7 @@ inline bool UserToDevicePixelSnapped(Rect& aRect, const DrawTarget& aDrawTarget,
* This function has the same behavior as UserToDevicePixelSnapped except that
* aRect is not transformed to device space.
*/
inline void MaybeSnapToDevicePixels(Rect& aRect, const DrawTarget& aDrawTarget,
inline bool MaybeSnapToDevicePixels(Rect& aRect, const DrawTarget& aDrawTarget,
bool aAllowScaleOr90DegreeRotate = false,
bool aAllowEmptySnaps = true)
{
@@ -412,7 +412,9 @@ inline void MaybeSnapToDevicePixels(Rect& aRect, const DrawTarget& aDrawTarget,
Matrix mat = aDrawTarget.GetTransform();
mat.Invert();
aRect = mat.TransformBounds(aRect);
return true;
}
return false;
}
} // namespace gfx
+8
View File
@@ -173,6 +173,10 @@ SkPathContainsPoint(const SkPath& aPath, const Point& aPoint, const Matrix& aTra
bool
PathSkia::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
{
if (!mPath.isFinite()) {
return false;
}
return SkPathContainsPoint(mPath, aPoint, aTransform);
}
@@ -181,6 +185,10 @@ PathSkia::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
const Point &aPoint,
const Matrix &aTransform) const
{
if (!mPath.isFinite()) {
return false;
}
SkPaint paint;
StrokeOptionsToPaint(paint, aStrokeOptions);
+16 -2
View File
@@ -13,11 +13,16 @@
#include "DrawTargetCG.h"
#include <vector>
#include <dlfcn.h>
#ifdef MOZ_WIDGET_UIKIT
#include <CoreFoundation/CoreFoundation.h>
#endif
#ifdef MOZ_WIDGET_COCOA
// prototype for private API
extern "C" {
CGPathRef CGFontGetGlyphPath(CGFontRef fontRef, CGAffineTransform *textTransform, int unknown, CGGlyph glyph);
};
#endif
namespace mozilla {
@@ -81,11 +86,12 @@ ScaledFontMac::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aT
{
if (aTarget->GetBackendType() == BackendType::COREGRAPHICS ||
aTarget->GetBackendType() == BackendType::COREGRAPHICS_ACCELERATED) {
#ifdef MOZ_WIDGET_COCOA
CGMutablePathRef path = CGPathCreateMutable();
for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
// XXX: we could probably fold both of these transforms together to avoid extra work
CGAffineTransform flip = CGAffineTransformMakeScale(1, -1);
CGPathRef glyphPath = ::CGFontGetGlyphPath(mFont, &flip, 0, aBuffer.mGlyphs[i].mIndex);
CGAffineTransform matrix = CGAffineTransformMake(mSize, 0, 0, mSize,
@@ -97,6 +103,10 @@ ScaledFontMac::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aT
RefPtr<Path> ret = new PathCG(path, FillRule::FILL_WINDING);
CGPathRelease(path);
return ret.forget();
#else
//TODO: probably want CTFontCreatePathForGlyph
MOZ_CRASH("This needs implemented");
#endif
}
return ScaledFontBase::GetPathForGlyphs(aBuffer, aTarget);
}
@@ -108,7 +118,7 @@ ScaledFontMac::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBui
ScaledFontBase::CopyGlyphsToBuilder(aBuffer, aBuilder, aBackendType, aTransformHint);
return;
}
#ifdef MOZ_WIDGET_COCOA
PathBuilderCG *pathBuilderCG =
static_cast<PathBuilderCG*>(aBuilder);
// XXX: check builder type
@@ -123,6 +133,10 @@ ScaledFontMac::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBui
CGPathAddPath(pathBuilderCG->mCGPath, &matrix, glyphPath);
CGPathRelease(glyphPath);
}
#else
//TODO: probably want CTFontCreatePathForGlyph
MOZ_CRASH("This needs implemented");
#endif
}
uint32_t
+7 -1
View File
@@ -6,7 +6,13 @@
#ifndef MOZILLA_GFX_SCALEDFONTMAC_H_
#define MOZILLA_GFX_SCALEDFONTMAC_H_
#import <ApplicationServices/ApplicationServices.h>
#ifdef MOZ_WIDGET_COCOA
#include <ApplicationServices/ApplicationServices.h>
#else
#include <CoreGraphics/CoreGraphics.h>
#include <CoreText/CoreText.h>
#endif
#include "2D.h"
#include "ScaledFontBase.h"
+4
View File
@@ -9,7 +9,9 @@
#include "DataSurfaceHelpers.h"
#include "mozilla/Types.h" // for decltype
#ifdef MOZ_WIDGET_COCOA
#include "MacIOSurface.h"
#endif
#include "Tools.h"
namespace mozilla {
@@ -384,6 +386,7 @@ SourceSurfaceCGBitmapContext::~SourceSurfaceCGBitmapContext()
CGImageRelease(mImage);
}
#ifdef MOZ_WIDGET_COCOA
SourceSurfaceCGIOSurfaceContext::SourceSurfaceCGIOSurfaceContext(DrawTargetCG *aDrawTarget)
{
CGContextRef cg = (CGContextRef)aDrawTarget->GetNativeSurface(NativeSurfaceType::CGCONTEXT_ACCELERATED);
@@ -452,6 +455,7 @@ SourceSurfaceCGIOSurfaceContext::GetData()
{
return (unsigned char*)mData;
}
#endif
} // namespace gfx
} // namespace mozilla
+8
View File
@@ -6,11 +6,17 @@
#ifndef _MOZILLA_GFX_SOURCESURFACECG_H
#define _MOZILLA_GFX_SOURCESURFACECG_H
#ifdef MOZ_WIDGET_COCOA
#include <ApplicationServices/ApplicationServices.h>
#else
#include <CoreGraphics/CoreGraphics.h>
#endif
#include "2D.h"
#ifdef MOZ_WIDGET_COCOA
class MacIOSurface;
#endif
namespace mozilla {
namespace gfx {
@@ -163,6 +169,7 @@ private:
IntSize mSize;
};
#ifdef MOZ_WIDGET_COCOA
class SourceSurfaceCGIOSurfaceContext : public SourceSurfaceCGContext
{
public:
@@ -196,6 +203,7 @@ private:
IntSize mSize;
};
#endif
} // namespace gfx
+4 -2
View File
@@ -48,10 +48,9 @@ EXPORTS.mozilla.gfx += [
'UserData.h',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'uikit'):
EXPORTS.mozilla.gfx += [
'MacIOSurface.h',
'QuartzSupport.h',
]
UNIFIED_SOURCES += [
'DrawTargetCG.cpp',
@@ -163,6 +162,9 @@ SOURCES += [
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
EXPORTS.mozilla.gfx += [
'QuartzSupport.h',
]
SOURCES += [
'MacIOSurface.cpp',
'QuartzSupport.mm',
+1 -1
View File
@@ -410,7 +410,7 @@ BufferTextureHost::UpdatedInternal(const nsIntRegion* aRegion)
// If the last frame wasn't uploaded yet, and we -don't- have a partial update,
// we still need to update the full surface.
if (aRegion && !mNeedsFullUpdate) {
mMaybeUpdatedRegion = mMaybeUpdatedRegion.Or(mMaybeUpdatedRegion, *aRegion);
mMaybeUpdatedRegion.OrWith(*aRegion);
} else {
mNeedsFullUpdate = true;
}
-1
View File
@@ -2090,7 +2090,6 @@ gfxPlatform::UsesOffMainThreadCompositing()
return result;
}
/***
* The preference "layout.frame_rate" has 3 meanings depending on the value:
*
+82 -17
View File
@@ -7,23 +7,60 @@
#include "DaemonSocketPDUHelpers.h"
#include <limits>
// Enable this constant to abort Gecko on IPC errors. This is helpful
// for debugging, but should *never* be enabled by default.
#define MOZ_HAL_ABORT_ON_IPC_ERRORS (0)
#ifdef CHROMIUM_LOG
#undef CHROMIUM_LOG
#endif
#if defined(MOZ_WIDGET_GONK)
#include <android/log.h>
#define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "I/O", args);
#define CHROMIUM_LOG(args...) \
__android_log_print(ANDROID_LOG_INFO, "HAL-IPC", args);
#define CHROMIUM_LOG_VA(fmt, ap) \
__android_log_vprint(ANDROID_LOG_INFO, "HAL-IPC", fmt, ap);
#else
#include <stdio.h>
#define IODEBUG true
#define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
#define CHROMIUM_LOG(args...) if (IODEBUG) { printf(args); }
#define CHROMIUM_LOG_VA(fmt, ap) if (IODEBUG) { vprintf(fmt, ap); }
#endif
namespace mozilla {
namespace ipc {
namespace DaemonSocketPDUHelpers {
//
// Logging
//
namespace detail {
void
LogProtocolError(const char* aFmt, ...)
{
va_list ap;
va_start(ap, aFmt);
CHROMIUM_LOG_VA(aFmt, ap);
va_end(ap);
if (MOZ_HAL_ABORT_ON_IPC_ERRORS) {
MOZ_CRASH("HAL IPC protocol error");
}
}
} // namespace detail
//
// Conversion
//
@@ -35,7 +72,8 @@ Convert(bool aIn, uint8_t& aOut)
[false] = 0x00,
[true] = 0x01
};
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
if (MOZ_HAL_IPC_CONVERT_WARN_IF(
aIn >= MOZ_ARRAY_LENGTH(sValue), bool, uint8_t)) {
aOut = 0;
return NS_ERROR_ILLEGAL_VALUE;
}
@@ -59,8 +97,10 @@ Convert(bool aIn, int32_t& aOut)
nsresult
Convert(int aIn, uint8_t& aOut)
{
if (NS_WARN_IF(aIn < std::numeric_limits<uint8_t>::min()) ||
NS_WARN_IF(aIn > std::numeric_limits<uint8_t>::max())) {
if (MOZ_HAL_IPC_CONVERT_WARN_IF(
aIn < std::numeric_limits<uint8_t>::min(), int, uint8_t) ||
MOZ_HAL_IPC_CONVERT_WARN_IF(
aIn > std::numeric_limits<uint8_t>::max(), int, uint8_t)) {
aOut = 0; // silences compiler warning
return NS_ERROR_ILLEGAL_VALUE;
}
@@ -71,8 +111,10 @@ Convert(int aIn, uint8_t& aOut)
nsresult
Convert(int aIn, int16_t& aOut)
{
if (NS_WARN_IF(aIn < std::numeric_limits<int16_t>::min()) ||
NS_WARN_IF(aIn > std::numeric_limits<int16_t>::max())) {
if (MOZ_HAL_IPC_CONVERT_WARN_IF(
aIn < std::numeric_limits<int16_t>::min(), int, int16_t) ||
MOZ_HAL_IPC_CONVERT_WARN_IF(
aIn > std::numeric_limits<int16_t>::max(), int, int16_t)) {
aOut = 0; // silences compiler warning
return NS_ERROR_ILLEGAL_VALUE;
}
@@ -83,8 +125,10 @@ Convert(int aIn, int16_t& aOut)
nsresult
Convert(int aIn, int32_t& aOut)
{
if (NS_WARN_IF(aIn < std::numeric_limits<int32_t>::min()) ||
NS_WARN_IF(aIn > std::numeric_limits<int32_t>::max())) {
if (MOZ_HAL_IPC_CONVERT_WARN_IF(
aIn < std::numeric_limits<int32_t>::min(), int, int32_t) ||
MOZ_HAL_IPC_CONVERT_WARN_IF(
aIn > std::numeric_limits<int32_t>::max(), int, int32_t)) {
aOut = 0; // silences compiler warning
return NS_ERROR_ILLEGAL_VALUE;
}
@@ -99,7 +143,8 @@ Convert(uint8_t aIn, bool& aOut)
[0x00] = false,
[0x01] = true
};
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sBool))) {
if (MOZ_HAL_IPC_CONVERT_WARN_IF(
aIn >= MOZ_ARRAY_LENGTH(sBool), uint8_t, bool)) {
return NS_ERROR_ILLEGAL_VALUE;
}
aOut = sBool[aIn];
@@ -137,8 +182,10 @@ Convert(uint32_t aIn, int& aOut)
nsresult
Convert(uint32_t aIn, uint8_t& aOut)
{
if (NS_WARN_IF(aIn < std::numeric_limits<uint8_t>::min()) ||
NS_WARN_IF(aIn > std::numeric_limits<uint8_t>::max())) {
if (MOZ_HAL_IPC_CONVERT_WARN_IF(
aIn < std::numeric_limits<uint8_t>::min(), uint32_t, uint8_t) ||
MOZ_HAL_IPC_CONVERT_WARN_IF(
aIn > std::numeric_limits<uint8_t>::max(), uint32_t, uint8_t)) {
aOut = 0; // silences compiler warning
return NS_ERROR_ILLEGAL_VALUE;
}
@@ -149,7 +196,7 @@ Convert(uint32_t aIn, uint8_t& aOut)
nsresult
Convert(size_t aIn, uint16_t& aOut)
{
if (NS_WARN_IF(aIn >= (1ul << 16))) {
if (MOZ_HAL_IPC_CONVERT_WARN_IF(aIn >= (1ul << 16), size_t, uint16_t)) {
aOut = 0; // silences compiler warning
return NS_ERROR_ILLEGAL_VALUE;
}
@@ -161,6 +208,12 @@ Convert(size_t aIn, uint16_t& aOut)
// Packing
//
nsresult
PackPDU(bool aIn, DaemonSocketPDU& aPDU)
{
return PackPDU(PackConversion<bool, uint8_t>(aIn), aPDU);
}
nsresult
PackPDU(const DaemonSocketPDUHeader& aIn, DaemonSocketPDU& aPDU)
{
@@ -183,6 +236,18 @@ PackPDU(const DaemonSocketPDUHeader& aIn, DaemonSocketPDU& aPDU)
// Unpacking
//
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, bool& aOut)
{
return UnpackPDU(aPDU, UnpackConversion<uint8_t, bool>(aOut));
}
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, char& aOut)
{
return UnpackPDU(aPDU, UnpackConversion<uint8_t, char>(aOut));
}
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, nsDependentCString& aOut)
{
@@ -191,19 +256,19 @@ UnpackPDU(DaemonSocketPDU& aPDU, nsDependentCString& aOut)
// the string in the PDU, we can copy the actual bytes.
const char* str = reinterpret_cast<const char*>(aPDU.Consume(1));
if (NS_WARN_IF(!str)) {
if (MOZ_HAL_IPC_UNPACK_WARN_IF(!str, nsDependentCString)) {
return NS_ERROR_ILLEGAL_VALUE; // end of PDU
}
const char* end = static_cast<char*>(memchr(str, '\0', aPDU.GetSize() + 1));
if (NS_WARN_IF(!end)) {
if (MOZ_HAL_IPC_UNPACK_WARN_IF(!end, nsDependentCString)) {
return NS_ERROR_ILLEGAL_VALUE; // no string terminator
}
ptrdiff_t len = end - str;
const uint8_t* rest = aPDU.Consume(len);
if (NS_WARN_IF(!rest)) {
if (MOZ_HAL_IPC_UNPACK_WARN_IF(!rest, nsDependentCString)) {
// We couldn't consume bytes that should have been there.
return NS_ERROR_ILLEGAL_VALUE;
}
@@ -260,7 +325,7 @@ PDUInitOp::WarnAboutTrailingData() const
uint16_t payloadSize;
mPDU->GetHeader(service, opcode, payloadSize);
CHROMIUM_LOG(
detail::LogProtocolError(
"Unpacked PDU of type (%x,%x) still contains %zu Bytes of data.",
service, opcode, size);
}
+755
View File
@@ -34,6 +34,78 @@ struct DaemonSocketPDUHeader {
namespace DaemonSocketPDUHelpers {
//
// Logging
//
// The HAL IPC logging macros below print clear error messages for
// failed IPC operations. Use |MOZ_HAL_IPC_CONVERT_WARN_IF|,
// |MOZ_HAL_IPC_PACK_WARN_IF| and |MOZ_HAL_IPC_UNPACK_WARN_IF| to
// test for failures when processing PDUs.
//
// All macros accept the test condition as their first argument, and
// additional type information: the convert macro takes the input and
// output types, the pack macro takes the input type, and the unpack
// macro takes output type. All macros return the result of the test
// condition. If the test fails (i.e., the condition is true), they
// output a warning to the log.
//
// Don't call the functions in the detail namespace. They are helpers
// and not for general use.
//
namespace detail {
void
LogProtocolError(const char*, ...);
inline bool
ConvertWarnIfImpl(const char* aFile, unsigned long aLine,
bool aCondition, const char* aExpr, const char* aIn,
const char* aOut)
{
if (MOZ_UNLIKELY(aCondition)) {
LogProtocolError("%s:%d: Convert('%s' to '%s') failed: %s",
aFile, aLine, aIn, aOut, aExpr);
}
return aCondition;
}
inline bool
PackWarnIfImpl(const char* aFile, unsigned long aLine,
bool aCondition, const char* aExpr, const char* aIn)
{
if (MOZ_UNLIKELY(aCondition)) {
LogProtocolError("%s:%d: Pack('%s') failed: %s",
aFile, aLine, aIn, aExpr);
}
return aCondition;
}
inline bool
UnpackWarnIfImpl(const char* aFile, unsigned long aLine,
bool aCondition, const char* aExpr, const char* aOut)
{
if (MOZ_UNLIKELY(aCondition)) {
LogProtocolError("%s:%d: Unpack('%s') failed: %s",
aFile, aLine, aOut, aExpr);
}
return aCondition;
}
} // namespace detail
#define MOZ_HAL_IPC_CONVERT_WARN_IF(condition, in, out) \
::mozilla::ipc::DaemonSocketPDUHelpers::detail:: \
ConvertWarnIfImpl(__FILE__, __LINE__, condition, #condition, #in, #out)
#define MOZ_HAL_IPC_PACK_WARN_IF(condition, in) \
::mozilla::ipc::DaemonSocketPDUHelpers::detail:: \
PackWarnIfImpl(__FILE__, __LINE__, condition, #condition, #in)
#define MOZ_HAL_IPC_UNPACK_WARN_IF(condition, out) \
::mozilla::ipc::DaemonSocketPDUHelpers::detail:: \
UnpackWarnIfImpl(__FILE__, __LINE__, condition, #condition, #out)
//
// Conversion
//
@@ -89,6 +161,9 @@ template <typename T>
nsresult
PackPDU(T aIn, DaemonSocketPDU& aPDU);
nsresult
PackPDU(bool aIn, DaemonSocketPDU& aPDU);
inline nsresult
PackPDU(uint8_t aIn, DaemonSocketPDU& aPDU)
{
@@ -116,6 +191,380 @@ PackPDU(uint32_t aIn, DaemonSocketPDU& aPDU)
nsresult
PackPDU(const DaemonSocketPDUHeader& aIn, DaemonSocketPDU& aPDU);
/* |PackConversion| is a helper for packing converted values. Pass
* an instance of this structure to |PackPDU| to convert a value from
* the input type to the output type and and write it to the PDU.
*/
template<typename Tin, typename Tout>
struct PackConversion {
PackConversion(const Tin& aIn)
: mIn(aIn)
{ }
const Tin& mIn;
};
template<typename Tin, typename Tout>
inline nsresult
PackPDU(const PackConversion<Tin, Tout>& aIn, DaemonSocketPDU& aPDU)
{
Tout out;
nsresult rv = Convert(aIn.mIn, out);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(out, aPDU);
}
/* |PackArray| is a helper for packing arrays. Pass an instance
* of this structure as the first argument to |PackPDU| to pack
* an array. The array's maximum default length is 255 elements.
*/
template <typename T>
struct PackArray
{
PackArray(const T* aData, size_t aLength)
: mData(aData)
, mLength(aLength)
{ }
const T* mData;
size_t mLength;
};
/* This implementation of |PackPDU| packs the length of an array
* and the elements of the array one-by-one.
*/
template<typename T>
inline nsresult
PackPDU(const PackArray<T>& aIn, DaemonSocketPDU& aPDU)
{
for (size_t i = 0; i < aIn.mLength; ++i) {
nsresult rv = PackPDU(aIn.mData[i], aPDU);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
template<>
inline nsresult
PackPDU<uint8_t>(const PackArray<uint8_t>& aIn, DaemonSocketPDU& aPDU)
{
/* Write raw bytes in one pass */
return aPDU.Write(aIn.mData, aIn.mLength);
}
template<>
inline nsresult
PackPDU<char>(const PackArray<char>& aIn, DaemonSocketPDU& aPDU)
{
/* Write raw bytes in one pass */
return aPDU.Write(aIn.mData, aIn.mLength);
}
/* |PackCString0| is a helper for packing 0-terminated C string,
* including the \0 character. Pass an instance of this structure
* as the first argument to |PackPDU| to pack a string.
*/
struct PackCString0
{
PackCString0(const nsCString& aString)
: mString(aString)
{ }
const nsCString& mString;
};
/* This implementation of |PackPDU| packs a 0-terminated C string.
*/
inline nsresult
PackPDU(const PackCString0& aIn, DaemonSocketPDU& aPDU)
{
return PackPDU(
PackArray<uint8_t>(reinterpret_cast<const uint8_t*>(aIn.mString.get()),
aIn.mString.Length() + 1), aPDU);
}
/* |PackReversed| is a helper for packing data in reversed order. Pass an
* instance of this structure as the first argument to |PackPDU| to pack data
* in reversed order.
*/
template<typename T>
struct PackReversed
{
PackReversed(const T& aValue)
: mValue(aValue)
{ }
const T& mValue;
};
/* No general rules to pack data in reversed order. Signal a link error if the
* type |T| of |PackReversed| is not defined explicitly.
*/
template<typename T>
nsresult
PackPDU(const PackReversed<T>& aIn, DaemonSocketPDU& aPDU);
/* This implementation of |PackPDU| packs elements in |PackArray| in reversed
* order. (ex. reversed GATT UUID, see bug 1171866)
*/
template<typename U>
inline nsresult
PackPDU(const PackReversed<PackArray<U>>& aIn, DaemonSocketPDU& aPDU)
{
for (size_t i = 0; i < aIn.mValue.mLength; ++i) {
nsresult rv = PackPDU(aIn.mValue.mData[aIn.mValue.mLength - i - 1], aPDU);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
template <typename T1, typename T2>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn2, aPDU);
}
template <typename T1, typename T2, typename T3>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn3, aPDU);
}
template <typename T1, typename T2, typename T3, typename T4>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3, const T4& aIn4,
DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn3, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn4, aPDU);
}
template <typename T1, typename T2, typename T3,
typename T4, typename T5>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
const T4& aIn4, const T5& aIn5,
DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn3, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn4, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn5, aPDU);
}
template <typename T1, typename T2, typename T3,
typename T4, typename T5, typename T6>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
const T4& aIn4, const T5& aIn5, const T6& aIn6,
DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn3, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn4, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn5, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn6, aPDU);
}
template <typename T1, typename T2, typename T3,
typename T4, typename T5, typename T6,
typename T7>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
const T4& aIn4, const T5& aIn5, const T6& aIn6,
const T7& aIn7, DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn3, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn4, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn5, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn6, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn7, aPDU);
}
template <typename T1, typename T2, typename T3,
typename T4, typename T5, typename T6,
typename T7, typename T8>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
const T4& aIn4, const T5& aIn5, const T6& aIn6,
const T7& aIn7, const T8& aIn8, DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn3, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn4, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn5, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn6, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn7, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn8, aPDU);
}
template <typename T1, typename T2, typename T3,
typename T4, typename T5, typename T6,
typename T7, typename T8, typename T9,
typename T10, typename T11, typename T12,
typename T13>
inline nsresult
PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
const T4& aIn4, const T5& aIn5, const T6& aIn6,
const T7& aIn7, const T8& aIn8, const T9& aIn9,
const T10& aIn10, const T11& aIn11, const T12& aIn12,
const T13& aIn13, DaemonSocketPDU& aPDU)
{
nsresult rv = PackPDU(aIn1, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn2, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn3, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn4, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn5, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn6, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn7, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn8, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn9, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn10, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn11, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aIn12, aPDU);
if (NS_FAILED(rv)) {
return rv;
}
return PackPDU(aIn13, aPDU);
}
//
// Unpacking
//
@@ -125,6 +574,12 @@ template <typename T>
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, T& aOut);
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, bool& aOut);
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, char& aOut);
inline nsresult
UnpackPDU(DaemonSocketPDU& aPDU, int8_t& aOut)
{
@@ -210,6 +665,149 @@ struct UnpackString0
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, const UnpackString0& aOut);
/* |UnpackConversion| is a helper for convering unpacked values. Pass
* an instance of this structure to |UnpackPDU| to read a value from
* the PDU in the input type and convert it to the output type.
*/
template<typename Tin, typename Tout>
struct UnpackConversion {
UnpackConversion(Tout& aOut)
: mOut(aOut)
{ }
Tout& mOut;
};
template<typename Tin, typename Tout>
inline nsresult
UnpackPDU(DaemonSocketPDU& aPDU, const UnpackConversion<Tin, Tout>& aOut)
{
Tin in;
nsresult rv = UnpackPDU(aPDU, in);
if (NS_FAILED(rv)) {
return rv;
}
return Convert(in, aOut.mOut);
}
/* |UnpackArray| is a helper for unpacking arrays. Pass an instance
* of this structure as the second argument to |UnpackPDU| to unpack
* an array.
*/
template <typename T>
struct UnpackArray
{
UnpackArray(T* aData, size_t aLength)
: mData(aData)
, mLength(aLength)
{ }
UnpackArray(nsAutoArrayPtr<T>& aData, size_t aLength)
: mData(nullptr)
, mLength(aLength)
{
aData = new T[mLength];
mData = aData.get();
}
UnpackArray(nsAutoArrayPtr<T>& aData, size_t aSize, size_t aElemSize)
: mData(nullptr)
, mLength(aSize / aElemSize)
{
aData = new T[mLength];
mData = aData.get();
}
T* mData;
size_t mLength;
};
template<typename T>
inline nsresult
UnpackPDU(DaemonSocketPDU& aPDU, const UnpackArray<T>& aOut)
{
for (size_t i = 0; i < aOut.mLength; ++i) {
nsresult rv = UnpackPDU(aPDU, aOut.mData[i]);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
template<typename T>
inline nsresult
UnpackPDU(DaemonSocketPDU& aPDU, UnpackArray<T>& aOut)
{
for (size_t i = 0; i < aOut.mLength; ++i) {
nsresult rv = UnpackPDU(aPDU, aOut.mData[i]);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
template<>
inline nsresult
UnpackPDU<uint8_t>(DaemonSocketPDU& aPDU, const UnpackArray<uint8_t>& aOut)
{
/* Read raw bytes in one pass */
return aPDU.Read(aOut.mData, aOut.mLength);
}
template<typename T>
inline nsresult
UnpackPDU(DaemonSocketPDU& aPDU, nsTArray<T>& aOut)
{
for (typename nsTArray<T>::size_type i = 0; i < aOut.Length(); ++i) {
nsresult rv = UnpackPDU(aPDU, aOut[i]);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
/* |UnpackReversed| is a helper for unpacking data in reversed order. Pass an
* instance of this structure as the second argument to |UnpackPDU| to unpack
* data in reversed order.
*/
template<typename T>
struct UnpackReversed
{
UnpackReversed(T& aValue)
: mValue(&aValue)
{ }
UnpackReversed(T&& aValue)
: mValue(&aValue)
{ }
T* mValue;
};
/* No general rules to unpack data in reversed order. Signal a link error if
* the type |T| of |UnpackReversed| is not defined explicitly.
*/
template<typename T>
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, const UnpackReversed<T>& aOut);
template<typename U>
inline nsresult
UnpackPDU(DaemonSocketPDU& aPDU, const UnpackReversed<UnpackArray<U>>& aOut)
{
for (size_t i = 0; i < aOut.mValue->mLength; ++i) {
nsresult rv = UnpackPDU(aPDU,
aOut.mValue->mData[aOut.mValue->mLength - i - 1]);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
//
// Init operators
//
@@ -305,6 +903,163 @@ private:
DaemonSocketPDU* mPDU; // Hold pointer to allow for constant instances
};
// |UnpackPDUInitOp| is a general-purpose init operator for all variants
// of |DaemonResultRunnable| and |DaemonNotificationRunnable|. The call
// operators of |UnpackPDUInitOp| unpack a PDU into the supplied
// arguments.
class UnpackPDUInitOp final : private PDUInitOp
{
public:
UnpackPDUInitOp(DaemonSocketPDU& aPDU)
: PDUInitOp(aPDU)
{ }
nsresult operator () () const
{
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1>
nsresult operator () (T1& aArg1) const
{
nsresult rv = UnpackPDU(GetPDU(), aArg1);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1, typename T2>
nsresult operator () (T1& aArg1, T2& aArg2) const
{
DaemonSocketPDU& pdu = GetPDU();
nsresult rv = UnpackPDU(pdu, aArg1);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg2);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1, typename T2, typename T3>
nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3) const
{
DaemonSocketPDU& pdu = GetPDU();
nsresult rv = UnpackPDU(pdu, aArg1);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg2);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg3);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1, typename T2, typename T3, typename T4>
nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4) const
{
DaemonSocketPDU& pdu = GetPDU();
nsresult rv = UnpackPDU(pdu, aArg1);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg2);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg3);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg4);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1, typename T2, typename T3, typename T4, typename T5>
nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
T5& aArg5) const
{
DaemonSocketPDU& pdu = GetPDU();
nsresult rv = UnpackPDU(pdu, aArg1);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg2);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg3);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg4);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg5);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
template<typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6>
nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
T5& aArg5, T6& aArg6) const
{
DaemonSocketPDU& pdu = GetPDU();
nsresult rv = UnpackPDU(pdu, aArg1);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg2);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg3);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg4);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg5);
if (NS_FAILED(rv)) {
return rv;
}
rv = UnpackPDU(pdu, aArg6);
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
};
} // namespace DaemonSocketPDUHelpers
} // namespace ipc
+1 -1
View File
@@ -971,7 +971,7 @@ TestDataStructuresChild::Test18()
ra.SetCapacity(nelements);
for (int i = 0; i < nelements; ++i) {
nsIntRegion r;
r = r.Or(nsIntRect(0, 0, 10, 10), nsIntRect(10, 10, 10, 10));
r.Or(nsIntRect(0, 0, 10, 10), nsIntRect(10, 10, 10, 10));
ra.AppendElement(r);
}
+1 -6
View File
@@ -181,15 +181,10 @@ static inline bool ShouldFailWithOOM() { return false; }
namespace js {
MOZ_NORETURN MOZ_COLD void
CrashAtUnhandlableOOM(const char* reason);
/* Disable OOM testing in sections which are not OOM safe. */
struct MOZ_RAII AutoEnterOOMUnsafeRegion
{
void crash(const char* reason) {
CrashAtUnhandlableOOM(reason);
}
MOZ_NORETURN MOZ_COLD void crash(const char* reason);
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
AutoEnterOOMUnsafeRegion()
+21 -9
View File
@@ -935,13 +935,16 @@ Statistics::endGC()
for (size_t d = PHASE_DAG_NONE; d < NumTimingArrays; d++)
PodZero(&phaseTimes[d][PHASE_GC_BEGIN], PHASE_LIMIT - PHASE_GC_BEGIN);
aborted = false;
// Clear the OOM flag but only if we are not in a nested GC.
if (gcDepth == 1)
aborted = false;
}
void
Statistics::beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
SliceBudget budget, JS::gcreason::Reason reason)
{
gcDepth++;
this->zoneStats = zoneStats;
bool first = !runtime->gc.isIncrementalGCInProgress();
@@ -950,13 +953,13 @@ Statistics::beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
SliceData data(budget, reason, PRMJ_Now(), JS_GetCurrentEmbedderTime(), GetPageFaultCount());
if (!slices.append(data)) {
// OOM testing fails if we CrashAtUnhandlableOOM here.
// If we are OOM, set a flag to indicate we have missing slice data.
aborted = true;
return;
}
// Slice callbacks should only fire for the outermost level
if (++gcDepth == 1) {
// Slice callbacks should only fire for the outermost level.
if (gcDepth == 1) {
bool wasFullGC = zoneStats.isCollectingAllZones();
if (sliceCallback)
(*sliceCallback)(runtime, first ? JS::GC_CYCLE_BEGIN : JS::GC_SLICE_BEGIN,
@@ -977,8 +980,8 @@ Statistics::endSlice()
if (last)
endGC();
// Slice callbacks should only fire for the outermost level
if (--gcDepth == 0) {
// Slice callbacks should only fire for the outermost level.
if (gcDepth == 1 && !aborted) {
bool wasFullGC = zoneStats.isCollectingAllZones();
if (sliceCallback)
(*sliceCallback)(runtime, last ? JS::GC_CYCLE_END : JS::GC_SLICE_END,
@@ -988,13 +991,21 @@ Statistics::endSlice()
/* Do this after the slice callback since it uses these values. */
if (last)
PodArrayZero(counts);
gcDepth--;
MOZ_ASSERT(gcDepth >= 0);
}
void
bool
Statistics::startTimingMutator()
{
// Should only be called from outside of GC
MOZ_ASSERT(phaseNestingDepth == 0);
if (phaseNestingDepth != 0) {
// Should only be called from outside of GC.
MOZ_ASSERT(phaseNestingDepth == 1);
MOZ_ASSERT(phaseNesting[0] == PHASE_MUTATOR);
return false;
}
MOZ_ASSERT(suspendedPhaseNestingDepth == 0);
timedGCTime = 0;
@@ -1003,6 +1014,7 @@ Statistics::startTimingMutator()
timedGCStart = 0;
beginPhase(PHASE_MUTATOR);
return true;
}
bool
+1 -1
View File
@@ -173,7 +173,7 @@ struct Statistics
SliceBudget budget, JS::gcreason::Reason reason);
void endSlice();
void startTimingMutator();
bool startTimingMutator();
bool stopTimingMutator(double& mutator_ms, double& gc_ms);
void reset(const char* reason) {
+9
View File
@@ -0,0 +1,9 @@
// |jit-test| allow-oom; allow-unhandlable-oom
if (!('oomAfterAllocations' in this))
quit();
setGCCallback({
action: "majorGC",
});
oomAfterAllocations(50);
+17
View File
@@ -0,0 +1,17 @@
if (!('oomAtAllocation' in this && 'resetOOMFailure' in this))
quit();
function f() {
var i = 1;
do {
try {
oomAtAllocation(i);
(function() y)();
} catch (e) {
x = resetOOMFailure();
}
i++;
} while (x);
}
f();
fullcompartmentchecks(true);
+7
View File
@@ -0,0 +1,7 @@
if (!('oomTest' in this) || helperThreadCount() === 0)
quit();
enableSPSProfiling();
var s = newGlobal();
s.offThreadCompileScript('oomTest(() => {});');
s.runOffThreadScript();
@@ -0,0 +1,3 @@
// |jit-test| error: Error
startTimingMutator();
startTimingMutator();
+8
View File
@@ -0,0 +1,8 @@
// |jit-test| --fuzzing-safe
readline = function() {};
Function.prototype.toString = function() {
for (var i = 0; i < 2; i++) {
this()
}
};
getBacktrace({thisprops: true});
+1 -1
View File
@@ -2033,7 +2033,7 @@ SnapshotIterator::maybeRead(const RValueAllocation& a, MaybeReadFallback& fallba
if (fallback.canRecoverResults()) {
if (!initInstructionResults(fallback))
js::CrashAtUnhandlableOOM("Unable to recover allocations.");
MOZ_CRASH("Unable to recover allocations.");
if (allocationReadable(a))
return allocationValue(a);
+1 -1
View File
@@ -993,7 +993,7 @@ class BOffImm
{
MOZ_ASSERT((offset & 0x3) == 0);
if (!IsInRange(offset))
CrashAtUnhandlableOOM("BOffImm");
MOZ_CRASH("BOffImm offset out of range");
}
explicit BOffImm()
+3 -3
View File
@@ -72,11 +72,11 @@ class TempAllocPolicy
void* reallocPtr = nullptr);
template <typename T>
T* onOutOfMemoryTyped(AllocFunction allocFunc, size_t numElems) {
T* onOutOfMemoryTyped(AllocFunction allocFunc, size_t numElems, void* reallocPtr = nullptr) {
size_t bytes;
if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes)))
return nullptr;
return static_cast<T*>(onOutOfMemory(allocFunc, bytes));
return static_cast<T*>(onOutOfMemory(allocFunc, bytes, reallocPtr));
}
public:
@@ -118,7 +118,7 @@ class TempAllocPolicy
T* pod_realloc(T* prior, size_t oldSize, size_t newSize) {
T* p2 = maybe_pod_realloc<T>(prior, oldSize, newSize);
if (MOZ_UNLIKELY(!p2))
p2 = onOutOfMemoryTyped<T>(AllocFunction::Realloc, newSize);
p2 = onOutOfMemoryTyped<T>(AllocFunction::Realloc, newSize, prior);
return p2;
}
+5 -3
View File
@@ -1198,13 +1198,15 @@ JS::AutoCheckRequestDepth::~AutoCheckRequestDepth()
#endif
#ifdef JS_CRASH_DIAGNOSTICS
void CompartmentChecker::check(InterpreterFrame* fp)
void
CompartmentChecker::check(InterpreterFrame* fp)
{
if (fp)
check(fp->scopeChain());
}
void CompartmentChecker::check(AbstractFramePtr frame)
void
CompartmentChecker::check(AbstractFramePtr frame)
{
if (frame)
check(frame.scopeChain());
@@ -1212,7 +1214,7 @@ void CompartmentChecker::check(AbstractFramePtr frame)
#endif
void
js::CrashAtUnhandlableOOM(const char* reason)
AutoEnterOOMUnsafeRegion::crash(const char* reason)
{
char msgbuf[1024];
JS_snprintf(msgbuf, sizeof(msgbuf), "[unhandlable oom] %s", reason);
+2 -1
View File
@@ -164,11 +164,12 @@ JSRuntime::createJitRuntime(JSContext* cx)
JitRuntime::AutoMutateBackedges amb(jrt);
jitRuntime_ = jrt;
AutoEnterOOMUnsafeRegion noOOM;
if (!jitRuntime_->initialize(cx)) {
// Handling OOM here is complicated: if we delete jitRuntime_ now, we
// will destroy the ExecutableAllocator, even though there may still be
// JitCode instances holding references to ExecutablePools.
CrashAtUnhandlableOOM("OOM in createJitRuntime");
noOOM.crash("OOM in createJitRuntime");
}
return jitRuntime_;
+4 -4
View File
@@ -149,10 +149,10 @@ typedef HashMap<CrossCompartmentKey, ReadBarrieredValue,
// set.
//
// * PendingMetadata: This object has been allocated and is still pending its
// metadata. This should never be the case in an allocation
// path, as a constructor function was supposed to have set
// the metadata of the previous object *before* allocating
// another object.
// metadata. This should never be the case when we begin an
// allocation, as a constructor function was supposed to have
// set the metadata of the previous object *before*
// allocating another object.
//
// The js::AutoSetNewObjectMetadata RAII class provides an ergonomic way for
// constructor functions to navigate state transitions, and its instances
+9 -3
View File
@@ -3623,6 +3623,9 @@ js::CloneScriptIntoFunction(JSContext* cx, HandleObject enclosingScope, HandleFu
if (!dst)
return nullptr;
// Save flags in case we need to undo the early mutations.
const int preservedFlags = fun->flags();
dst->setFunction(fun);
Rooted<LazyScript*> lazy(cx);
if (fun->isInterpretedLazy()) {
@@ -3637,6 +3640,7 @@ js::CloneScriptIntoFunction(JSContext* cx, HandleObject enclosingScope, HandleFu
fun->initLazyScript(lazy);
else
fun->setScript(nullptr);
fun->setFlags(preservedFlags);
return nullptr;
}
@@ -3843,9 +3847,11 @@ JSScript::traceChildren(JSTracer* trc)
static_cast<GCMarker*>(trc)->shouldCheckCompartments(),
zone()->isCollecting());
for (uint32_t i = 0; i < natoms(); ++i) {
if (atoms[i])
TraceEdge(trc, &atoms[i], "atom");
if (atoms) {
for (uint32_t i = 0; i < natoms(); ++i) {
if (atoms[i])
TraceEdge(trc, &atoms[i], "atom");
}
}
if (hasObjects()) {
+5 -1
View File
@@ -1579,7 +1579,11 @@ StartTimingMutator(JSContext* cx, unsigned argc, Value* vp)
return false;
}
cx->runtime()->gc.stats.startTimingMutator();
if (!cx->runtime()->gc.stats.startTimingMutator()) {
JS_ReportError(cx, "StartTimingMutator should only be called from outside of GC");
return false;
}
args.rval().setUndefined();
return true;
}
+15 -24
View File
@@ -52,19 +52,17 @@ struct MallocProvider
{
template <class T>
T* maybe_pod_malloc(size_t numElems) {
size_t bytes = numElems * sizeof(T);
T* p = js_pod_malloc<T>(numElems);
if (MOZ_LIKELY(p))
client()->updateMallocCounter(bytes);
client()->updateMallocCounter(numElems * sizeof(T));
return p;
}
template <class T>
T* maybe_pod_calloc(size_t numElems) {
size_t bytes = numElems * sizeof(T);
T* p = js_pod_calloc<T>(numElems);
if (MOZ_LIKELY(p))
client()->updateMallocCounter(bytes);
client()->updateMallocCounter(numElems * sizeof(T));
return p;
}
@@ -90,11 +88,11 @@ struct MallocProvider
T* p = maybe_pod_malloc<T>(numElems);
if (MOZ_LIKELY(p))
return p;
if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
size_t bytes;
if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) {
client()->reportAllocationOverflow();
return nullptr;
}
size_t bytes = numElems * sizeof(T);
p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, bytes);
if (p)
client()->updateMallocCounter(bytes);
@@ -103,16 +101,12 @@ struct MallocProvider
template <class T, class U>
T* pod_malloc_with_extra(size_t numExtra) {
if (MOZ_UNLIKELY(numExtra & mozilla::tl::MulOverflowMask<sizeof(U)>::value)) {
size_t bytes;
if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) {
client()->reportAllocationOverflow();
return nullptr;
}
size_t bytes = sizeof(T) + numExtra * sizeof(U);
if (MOZ_UNLIKELY(bytes < sizeof(T))) {
client()->reportAllocationOverflow();
return nullptr;
}
T* p = reinterpret_cast<T*>(js_pod_malloc<uint8_t>(bytes));
T* p = static_cast<T*>(js_malloc(bytes));
if (MOZ_LIKELY(p)) {
client()->updateMallocCounter(bytes);
return p;
@@ -139,11 +133,11 @@ struct MallocProvider
T* p = maybe_pod_calloc<T>(numElems);
if (MOZ_LIKELY(p))
return p;
if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
size_t bytes;
if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) {
client()->reportAllocationOverflow();
return nullptr;
}
size_t bytes = numElems * sizeof(T);
p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, bytes);
if (p)
client()->updateMallocCounter(bytes);
@@ -152,16 +146,12 @@ struct MallocProvider
template <class T, class U>
T* pod_calloc_with_extra(size_t numExtra) {
if (MOZ_UNLIKELY(numExtra & mozilla::tl::MulOverflowMask<sizeof(U)>::value)) {
size_t bytes;
if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) {
client()->reportAllocationOverflow();
return nullptr;
}
size_t bytes = sizeof(T) + numExtra * sizeof(U);
if (MOZ_UNLIKELY(bytes < sizeof(T))) {
client()->reportAllocationOverflow();
return nullptr;
}
T* p = reinterpret_cast<T*>(js_pod_calloc<uint8_t>(bytes));
T* p = static_cast<T*>(js_calloc(bytes));
if (p) {
client()->updateMallocCounter(bytes);
return p;
@@ -184,11 +174,12 @@ struct MallocProvider
T* p = maybe_pod_realloc(prior, oldSize, newSize);
if (MOZ_LIKELY(p))
return p;
if (newSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
size_t bytes;
if (MOZ_UNLIKELY(!CalculateAllocSize<T>(newSize, &bytes))) {
client()->reportAllocationOverflow();
return nullptr;
}
p = (T*)client()->onOutOfMemory(AllocFunction::Realloc, newSize * sizeof(T), prior);
p = (T*)client()->onOutOfMemory(AllocFunction::Realloc, bytes, prior);
if (p && newSize > oldSize)
client()->updateMallocCounter((newSize - oldSize) * sizeof(T));
return p;
+2 -2
View File
@@ -1561,7 +1561,7 @@ js::NativeDefineElement(ExclusiveContext* cx, HandleNativeObject obj, uint32_t i
bool
js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
HandleValue value, GetterOp getter, SetterOp setter,
HandleValue value, JSGetterOp getter, JSSetterOp setter,
unsigned attrs)
{
ObjectOpResult result;
@@ -1581,7 +1581,7 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
bool
js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, PropertyName* name,
HandleValue value, GetterOp getter, SetterOp setter,
HandleValue value, JSGetterOp getter, JSSetterOp setter,
unsigned attrs)
{
RootedId id(cx, NameToId(name));
+1 -1
View File
@@ -39,7 +39,7 @@ probes::EnterScript(JSContext* cx, JSScript* script, JSFunction* maybeFun,
JSRuntime* rt = cx->runtime();
if (rt->spsProfiler.enabled()) {
if (!rt->spsProfiler.enter(script, maybeFun))
if (!rt->spsProfiler.enter(cx, script, maybeFun))
return false;
MOZ_ASSERT_IF(!fp->script()->isGenerator(), !fp->hasPushedSPSFrame());
fp->setPushedSPSFrame();
+1
View File
@@ -44,6 +44,7 @@
#include "jit/arm64/vixl/Simulator-vixl.h"
#include "jit/JitCompartment.h"
#include "jit/mips32/Simulator-mips32.h"
#include "jit/mips64/Simulator-mips64.h"
#include "jit/PcScriptCache.h"
#include "js/Date.h"
#include "js/MemoryMetrics.h"
+1 -1
View File
@@ -1490,7 +1490,7 @@ struct JSRuntime : public JS::shadow::Runtime,
reportAllocationOverflow();
return nullptr;
}
return static_cast<T*>(onOutOfMemoryCanGC(js::AllocFunction::Realloc, bytes));
return static_cast<T*>(onOutOfMemoryCanGC(js::AllocFunction::Realloc, bytes, p));
}
/*
+4 -2
View File
@@ -188,11 +188,13 @@ SPSProfiler::markEvent(const char* event)
}
bool
SPSProfiler::enter(JSScript* script, JSFunction* maybeFun)
SPSProfiler::enter(JSContext* cx, JSScript* script, JSFunction* maybeFun)
{
const char* str = profileString(script, maybeFun);
if (str == nullptr)
if (str == nullptr) {
ReportOutOfMemory(cx);
return false;
}
#ifdef DEBUG
// In debug builds, assert the JS pseudo frames already on the stack
+1 -1
View File
@@ -173,7 +173,7 @@ class SPSProfiler
* - exit: this function has ceased execution, and no further
* entries/exits will be made
*/
bool enter(JSScript* script, JSFunction* maybeFun);
bool enter(JSContext* cx, JSScript* script, JSFunction* maybeFun);
void exit(JSScript* script, JSFunction* maybeFun);
void updatePC(JSScript* script, jsbytecode* pc) {
if (enabled() && *size_ - 1 < max_) {
+5 -1
View File
@@ -688,21 +688,25 @@ TraceLoggerThreadState::init()
enabledTextIds[TraceLogger_FoldTests] = true;
enabledTextIds[TraceLogger_SplitCriticalEdges] = true;
enabledTextIds[TraceLogger_RenumberBlocks] = true;
enabledTextIds[TraceLogger_ScalarReplacement] = true;
enabledTextIds[TraceLogger_DominatorTree] = true;
enabledTextIds[TraceLogger_PhiAnalysis] = true;
enabledTextIds[TraceLogger_ScalarReplacement] = true;
enabledTextIds[TraceLogger_MakeLoopsContiguous] = true;
enabledTextIds[TraceLogger_ApplyTypes] = true;
enabledTextIds[TraceLogger_EagerSimdUnbox] = true;
enabledTextIds[TraceLogger_AliasAnalysis] = true;
enabledTextIds[TraceLogger_GVN] = true;
enabledTextIds[TraceLogger_LICM] = true;
enabledTextIds[TraceLogger_Sincos] = true;
enabledTextIds[TraceLogger_RangeAnalysis] = true;
enabledTextIds[TraceLogger_LoopUnrolling] = true;
enabledTextIds[TraceLogger_EffectiveAddressAnalysis] = true;
enabledTextIds[TraceLogger_AlignmentMaskAnalysis] = true;
enabledTextIds[TraceLogger_EliminateDeadCode] = true;
enabledTextIds[TraceLogger_ReorderInstructions] = true;
enabledTextIds[TraceLogger_EdgeCaseAnalysis] = true;
enabledTextIds[TraceLogger_EliminateRedundantChecks] = true;
enabledTextIds[TraceLogger_AddKeepAliveInstructions] = true;
enabledTextIds[TraceLogger_GenerateLIR] = true;
enabledTextIds[TraceLogger_RegisterAllocation] = true;
enabledTextIds[TraceLogger_GenerateCode] = true;
+1 -1
View File
@@ -28,7 +28,7 @@
* binary file.
* - treeFormat: The format used to encode the tree. By default "64,64,31,1,32".
* There are currently no other formats to save the tree.
* - 64,64,31,1,31 signifies how many bytes are used for the different
* - 64,64,31,1,32 signifies how many bytes are used for the different
* parts of the tree.
* => 64 bits: Time Stamp Counter of start of event.
* => 64 bits: Time Stamp Counter of end of event.
+2 -2
View File
@@ -3560,8 +3560,8 @@ nsDisplayBoxShadowOuter::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilde
oldShadow = geometry->mBounds;
newShadow = GetBounds(aBuilder, &snap);
} else {
oldShadow = oldShadow.Sub(geometry->mBounds, geometry->mBorderRect);
newShadow = newShadow.Sub(GetBounds(aBuilder, &snap), GetBorderRect());
oldShadow.Sub(geometry->mBounds, geometry->mBorderRect);
newShadow.Sub(GetBounds(aBuilder, &snap), GetBorderRect());
}
aInvalidRegion->Or(oldShadow, newShadow);
}
+1 -1
View File
@@ -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 \
@@ -19,7 +20,6 @@ _HARNESS_FILES = \
$(topsrcdir)/testing/mozbase/mozdevice/mozdevice/Zeroconf.py \
$(topsrcdir)/testing/mozbase/moznetwork/moznetwork/moznetwork.py \
$(topsrcdir)/build/mobile/b2gautomation.py \
$(topsrcdir)/build/automationutils.py \
$(topsrcdir)/build/mobile/remoteautomation.py \
$(topsrcdir)/testing/mochitest/server.js \
$(topsrcdir)/build/pgo/server-locations.txt \
+9 -14
View File
@@ -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
@@ -188,7 +185,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(':')
@@ -200,9 +197,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':
@@ -215,4 +210,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))
+145 -326
View File
@@ -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 \'<width>x<height>\'')
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)
+1 -32
View File
@@ -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;
+52 -47
View File
@@ -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";
@@ -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
@@ -389,10 +390,6 @@ function InitAndStartRefTests()
gThisChunk = 0;
}
try {
gURLFilterRegex = new RegExp(prefs.getCharPref("reftest.filter"));
} catch(e) {}
try {
gFocusFilterMode = prefs.getCharPref("reftest.focusFilterMode");
} catch(e) {}
@@ -449,8 +446,7 @@ function Shuffle(array)
function StartTests()
{
var uri;
#if BOOTSTRAP
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"].
@@ -477,41 +473,32 @@ 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 {
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);
// 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]);
});
BuildUseCounts();
// Filter tests which will be skipped to get a more even distribution when chunking
@@ -795,18 +782,25 @@ function AddPrefSettings(aWhere, aPrefName, aPrefValExpression, aSandbox, aTestP
return true;
}
function ReadTopManifest(aFileURL)
function ReadTopManifest(aFileURL, aFilter)
{
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, aFilter);
}
function AddTestItem(aTest)
function AddTestItem(aTest, aFilter)
{
if (gURLFilterRegex && !gURLFilterRegex.test(aTest.url1.spec))
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))))
return;
if (gFocusFilterMode == FOCUS_FILTER_NEEDS_FOCUS_TESTS &&
!aTest.needsFocus)
@@ -819,8 +813,19 @@ 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, 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);
@@ -1036,7 +1041,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, 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";
@@ -1066,7 +1071,7 @@ function ReadManifest(aURL, inherited_status)
fuzzyMaxPixels: fuzzy_max_pixels,
url1: testURI,
url2: null,
chaosMode: chaosMode });
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";
@@ -1093,7 +1098,7 @@ function ReadManifest(aURL, inherited_status)
fuzzyMaxPixels: fuzzy_max_pixels,
url1: testURI,
url2: null,
chaosMode: chaosMode });
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];
@@ -1123,7 +1128,7 @@ function ReadManifest(aURL, inherited_status)
fuzzyMaxPixels: fuzzy_max_pixels,
url1: testURI,
url2: refURI,
chaosMode: chaosMode });
chaosMode: chaosMode }, aFilter);
} else {
throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": unknown test type " + items[0];
}
+740
View File
@@ -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 <id>.xpi where <id> 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=<ip address>\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 '<width>x<height>'")
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))
+45 -190
View File
@@ -9,169 +9,36 @@ 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
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 <deviceroot>/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.
@@ -259,6 +126,7 @@ class ReftestServer:
class RemoteReftest(RefTest):
remoteApp = ''
resolver_cls = RemoteReftestResolver
def __init__(self, automation, devicemanager, options, scriptDir):
RefTest.__init__(self)
@@ -341,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 = {}
@@ -354,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
@@ -404,9 +275,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:
@@ -437,7 +305,8 @@ class RemoteReftest(RefTest):
def runApp(self, profile, binary, cmdargs, env,
timeout=None, debuggerInfo=None,
symbolsPath=None, options=None):
symbolsPath=None, options=None,
valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None):
status = self.automation.runApp(None, env,
binary,
profile.profile,
@@ -467,10 +336,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"
@@ -496,39 +365,28 @@ 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
parser.validate_remote(options, automation)
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]
installed = dm.shellCheckOutput(['pm', 'list', 'packages', expected])
if expected not in installed:
print "%s is not installed on this device" % expected
return 1
automation.setAppName(options.app)
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
options.timeout = 600
# 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:
@@ -544,11 +402,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()
@@ -561,5 +416,5 @@ def main(args):
return retVal
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
sys.exit(main())
+121 -296
View File
@@ -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,13 +18,10 @@ 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)
from automationutils import (
dumpScreen,
printstatus
)
import mozcrash
import mozdebug
import mozinfo
@@ -33,15 +29,10 @@ import mozleak
import mozprocess
import mozprofile
import mozrunner
from mozrunner.utils import test_environment
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
@@ -134,14 +125,83 @@ 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 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"""
@@ -160,30 +220,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)
@@ -202,11 +247,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.manifests'] = json.dumps(manifests)
# Ensure that telemetry is disabled, so we don't connect to the telemetry
# server in the middle of the tests.
@@ -248,13 +292,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
@@ -335,7 +376,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.
@@ -344,8 +385,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()
@@ -376,7 +421,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:]]
@@ -435,7 +479,7 @@ class RefTest(object):
log.info("Not taking screenshot here: see the one that was previously logged")
return
self.haveDumpedScreen = True
dumpScreen(utilityPath)
dump_screen(utilityPath, log)
def killAndGetStack(self, process, utilityPath, debuggerInfo, dump_screen=False):
"""
@@ -455,7 +499,7 @@ class RefTest(object):
if os.path.exists(crashinject):
status = subprocess.Popen(
[crashinject, str(process.pid)]).wait()
printstatus(status, "crashinject")
printstatus("crashinject", status)
if status == 0:
return
else:
@@ -502,48 +546,9 @@ class RefTest(object):
def stack_fixer(self):
"""
return stackFixerFunction, if any, to use on the output lines
return get_stack_fixer_function, if any, to use on the output lines
"""
if not mozinfo.info.get('debug'):
return None
stack_fixer_function = None
def import_stack_fixer_module(module_name):
sys.path.insert(0, self.utilityPath)
module = __import__(module_name, globals(), locals(), [])
sys.path.pop(0)
return module
if self.symbolsPath and os.path.exists(self.symbolsPath):
# Run each line through a function in fix_stack_using_bpsyms.py (uses breakpad symbol files).
# This method is preferred for Tinderbox builds, since native
# symbols may have been stripped.
stack_fixer_module = import_stack_fixer_module(
'fix_stack_using_bpsyms')
stack_fixer_function = lambda line: stack_fixer_module.fixSymbols(
line, self.symbolsPath)
elif mozinfo.isMac:
# Run each line through fix_macosx_stack.py (uses atos).
# This method is preferred for developer machines, so we don't
# have to run "make buildsymbols".
stack_fixer_module = import_stack_fixer_module(
'fix_macosx_stack')
stack_fixer_function = lambda line: stack_fixer_module.fixSymbols(
line)
elif mozinfo.isLinux:
# Run each line through fix_linux_stack.py (uses addr2line).
# This method is preferred for developer machines, so we don't
# have to run "make buildsymbols".
stack_fixer_module = import_stack_fixer_module(
'fix_linux_stack')
stack_fixer_function = lambda line: stack_fixer_module.fixSymbols(
line)
return stack_fixer_function
return get_stack_fixer_function(self.utilityPath, self.symbolsPath)
# output line handlers:
# these take a line and return a line
@@ -573,7 +578,8 @@ class RefTest(object):
def runApp(self, profile, binary, cmdargs, env,
timeout=None, debuggerInfo=None,
symbolsPath=None, options=None):
symbolsPath=None, options=None,
valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None):
def timeoutHandler():
self.handleTimeout(
@@ -638,7 +644,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,
@@ -646,10 +652,9 @@ class RefTest(object):
profileDir = None
try:
reftestlist = self.getManifestPath(testPath)
if cmdlineArgs == None:
cmdlineArgs = ['-reftest', reftestlist]
profile = self.createReftestProfile(options, reftestlist)
cmdlineArgs = []
profile = self.createReftestProfile(options, manifests)
profileDir = profile.profile # name makes more sense
# browser environment
@@ -668,7 +673,10 @@ class RefTest(object):
debuggerInfo=debuggerInfo)
mozleak.process_leak_log(self.leakLogFile,
leak_thresholds=options.leakThresholds,
log=log)
log=log,
stack_fixer=get_stack_fixer_function(options.utilityPath,
options.symbolsPath),
)
log.info("\nREFTEST INFO | runreftest.py | Running tests: end.")
finally:
self.cleanup(profileDir)
@@ -694,209 +702,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 <id>.xpi where <id> 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()
+28 -229
View File
@@ -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 '<width>x<height>'")
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=<ip address>\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
@@ -493,15 +304,13 @@ 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)
def runApp(self, profile, binary, cmdargs, env,
timeout=None, debuggerInfo=None,
symbolsPath=None, options=None):
symbolsPath=None, options=None,
valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None):
status = self.automation.runApp(None, env,
binary,
profile.profile,
@@ -514,7 +323,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
@@ -557,11 +366,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:
@@ -578,7 +383,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);
@@ -588,16 +393,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
@@ -609,11 +404,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()
@@ -627,13 +418,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__":
+1
View File
@@ -19,6 +19,7 @@ function LoadContext(usePrivateBrowsing) {
this.usePrivateBrowsing = usePrivateBrowsing;
}
LoadContext.prototype = {
originAttributes: {},
QueryInterface: XPCOMUtils.generateQI([Ci.nsILoadContext, Ci.nsIInterfaceRequestor]),
getInterface: XPCOMUtils.generateQI([Ci.nsILoadContext])
};
+1
View File
@@ -20,6 +20,7 @@ function LoadContext(usePrivateBrowsing) {
}
LoadContext.prototype = {
originAttributes: {},
usePrivateBrowsing: false,
// don't bother defining rest of nsILoadContext fields: don't need 'em
+1 -1
View File
@@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
var {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
"use strict";
@@ -4,7 +4,7 @@
"use strict";
const {utils: Cu} = Components;
var {utils: Cu} = Components;
this.EXPORTED_SYMBOLS = ["BagheeraServer"];
+1 -1
View File
@@ -9,7 +9,7 @@ this.EXPORTED_SYMBOLS = [
"initTestLogging",
];
const {utils: Cu} = Components;
var {utils: Cu} = Components;
Cu.import("resource://gre/modules/Log.jsm");

Some files were not shown because too many files have changed in this diff Show More