merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2017-02-06 12:56:49 +01:00
commit c95dc46546
26 changed files with 403 additions and 199 deletions

View File

@ -749,3 +749,7 @@ netmonitor.custom.cancel=Cancel
# LOCALIZATION NOTE (netmonitor.backButton): This is the label displayed
# on the button which exists the performance statistics view
netmonitor.backButton=Back
# LOCALIZATION NOTE (netmonitor.headers.learnMore): This is the label displayed
# next to a header list item, with a link to external documentation
netmonitor.headers.learnMore=Learn More

View File

@ -0,0 +1,119 @@
/* this source code form is subject to the terms of the mozilla public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* A mapping of header names to external documentation. Any header included
* here will show a "Learn More" link alongside it.
*/
"use strict";
var URL_DOMAIN = "https://developer.mozilla.org";
const URL_PATH = "/en-US/docs/Web/HTTP/Headers/";
const URL_PARAMS =
"?utm_source=mozilla&utm_medium=devtools-netmonitor&utm_campaign=default";
var SUPPORTED_HEADERS = [
"Accept",
"Accept-Charset",
"Accept-Encoding",
"Accept-Language",
"Accept-Ranges",
"Access-Control-Allow-Credentials",
"Access-Control-Allow-Headers",
"Access-Control-Allow-Methods",
"Access-Control-Allow-Origin",
"Access-Control-Expose-Headers",
"Access-Control-Max-Age",
"Access-Control-Request-Headers",
"Access-Control-Request-Method",
"Age",
"Cache-Control",
"Connection",
"Content-Disposition",
"Content-Encoding",
"Content-Language",
"Content-Length",
"Content-Location",
"Content-Security-Policy",
"Content-Security-Policy-Report-Only",
"Content-Type",
"Cookie",
"Cookie2",
"DNT",
"Date",
"ETag",
"Expires",
"From",
"Host",
"If-Match",
"If-Modified-Since",
"If-None-Match",
"If-Range",
"If-Unmodified-Since",
"Keep-Alive",
"Last-Modified",
"Location",
"Origin",
"Pragma",
"Public-Key-Pins",
"Public-Key-Pins-Report-Only",
"Referer",
"Referrer-Policy",
"Retry-After",
"Server",
"Set-Cookie",
"Set-Cookie2",
"Strict-Transport-Security",
"TE",
"Tk",
"Trailer",
"Transfer-Encoding",
"Upgrade-Insecure-Requests",
"User-Agent",
"Vary",
"Via",
"Warning",
"X-Content-Type-Options",
"X-DNS-Prefetch-Control",
"X-Frame-Options",
"X-XSS-Protection"
];
/**
* Get the MDN URL for the specified header
*
* @param {string} Name of the header
* The baseURL to use.
*
* @return {string}
* The MDN URL for the header, or null if not available.
*/
exports.getURL = (header) => {
if (SUPPORTED_HEADERS.indexOf(header) === -1) {
return null;
}
return URL_DOMAIN + URL_PATH + header + URL_PARAMS;
};
/**
* Use a different domain for the URLs. Used only for testing.
*
* @param {string} domain
* The domain to use.
*/
exports.setDomain = (domain) => {
URL_DOMAIN = domain;
};
/**
* Use a different list of supported headers. Used only for testing.
*
* @param {array} headers
* The supported headers to use.
*/
exports.setSupportedHeaders = (headers) => {
SUPPORTED_HEADERS = headers;
};

View File

@ -15,11 +15,16 @@ const {
const { L10N } = require("../../l10n");
const { writeHeaderText } = require("../../request-utils");
const { getFormattedSize } = require("../../utils/format-utils");
const Services = require("Services");
const { gDevTools } = require("devtools/client/framework/devtools");
const HeadersMDN = require("devtools/client/netmonitor/shared/components/headers-mdn");
const { REPS, MODE } = require("devtools/client/shared/components/reps/load-reps");
const Rep = createFactory(REPS.Rep);
// Components
const PropertiesView = createFactory(require("./properties-view"));
const { div, input, textarea } = DOM;
const { a, div, input, textarea } = DOM;
const EDIT_AND_RESEND = L10N.getStr("netmonitor.summary.editAndResend");
const RAW_HEADERS = L10N.getStr("netmonitor.summary.rawHeaders");
const RAW_HEADERS_REQUEST = L10N.getStr("netmonitor.summary.rawHeaders.requestHeaders");
@ -45,6 +50,7 @@ const HeadersPanel = createClass({
propTypes: {
cloneSelectedRequest: PropTypes.func.isRequired,
request: PropTypes.object.isRequired,
renderValue: PropTypes.func
},
getInitialState() {
@ -213,10 +219,49 @@ const HeadersPanel = createClass({
object,
filterPlaceHolder: HEADERS_FILTER_TEXT,
sectionNames: Object.keys(object),
renderValue
}),
)
);
}
});
function onLearnMoreClick(e, headerDocURL) {
e.stopPropagation();
e.preventDefault();
let win = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
win.openUILinkIn(headerDocURL, "tab");
}
function renderValue(props) {
const { member, value } = props;
if (typeof value !== "string") {
return null;
}
let headerDocURL = HeadersMDN.getURL(member.name);
return (
div({ className: "treeValueCellDivider" },
Rep(Object.assign(props, {
// FIXME: A workaround for the issue in StringRep
// Force StringRep to crop the text everytime
member: Object.assign({}, member, { open: false }),
mode: MODE.TINY,
cropLimit: 60,
})),
headerDocURL ?
a({
className: "learn-more-link",
title: headerDocURL,
onClick: (e) => onLearnMoreClick(e, headerDocURL),
}, `[${L10N.getStr("netmonitor.headers.learnMore")}]`)
:
null
)
);
}
module.exports = HeadersPanel;

View File

@ -6,6 +6,7 @@ DevToolsModules(
'cookies-panel.js',
'details-panel.js',
'editor.js',
'headers-mdn.js',
'headers-panel.js',
'params-panel.js',
'preview-panel.js',

View File

@ -98,6 +98,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
[browser_net_cyrillic-01.js]
[browser_net_cyrillic-02.js]
[browser_net_frame.js]
[browser_net_header-docs.js]
skip-if = (os == 'linux' && debug && bits == 32) # Bug 1321434
[browser_net_filter-01.js]
skip-if = (os == 'linux' && debug && bits == 32) # Bug 1303439

View File

@ -0,0 +1,56 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const HeadersMDN = require("devtools/client/netmonitor/shared/components/headers-mdn");
/**
* Tests if "Learn More" links are correctly displayed
* next to headers.
*/
add_task(function* () {
let { tab, monitor } = yield initNetMonitor(POST_DATA_URL);
info("Starting test... ");
let { document, NetMonitorView } = monitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
let wait = waitForNetworkEvents(monitor, 0, 2);
yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
content.wrappedJSObject.performRequests();
});
yield wait;
let origItem = RequestsMenu.getItemAtIndex(0);
RequestsMenu.selectedItem = origItem;
EventUtils.sendMouseEvent({ type: "click" },
document.querySelectorAll(".request-list-item")[0]);
testShowLearnMore(origItem);
return teardown(monitor);
/*
* Tests that a "Learn More" button is only shown if
* and only if a header is documented in MDN.
*/
function testShowLearnMore(data) {
document.querySelectorAll(".properties-view .treeRow.stringRow").forEach((rowEl, index) => {
let headerName = rowEl.querySelectorAll(".treeLabelCell .treeLabel")[0].textContent;
let headerDocURL = HeadersMDN.getURL(headerName);
let learnMoreEl = rowEl.querySelectorAll(".treeValueCell .learn-more-link");
if (headerDocURL === null) {
ok(learnMoreEl.length === 0,
"undocumented header does not include a \"Learn More\" button");
} else {
ok(learnMoreEl[0].getAttribute("title") === headerDocURL,
"documented header includes a \"Learn More\" button with a link to MDN");
}
});
}
});

View File

@ -77,6 +77,23 @@
display: none;
}
.treeTable .treeValueCellDivider {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
/* Learn More link */
.treeTable .treeValueCell .learn-more-link {
color: var(--theme-highlight-blue);
cursor: pointer;
margin: 0 5px;
}
.treeTable .treeValueCell .learn-more-link:hover {
text-decoration: underline;
}
/******************************************************************************/
/* Toggle Icon */

View File

@ -67,24 +67,28 @@ namespace {
// The number of queued runnables within the TabGroup ThrottledEventQueue
// at which to begin applying back pressure to the window.
const uint32_t kThrottledEventQueueBackPressure = 5000;
#define DEFAULT_THROTTLED_EVENT_QUEUE_BACK_PRESSURE 5000
static uint32_t gThrottledEventQueueBackPressure;
// The amount of delay to apply to timers when back pressure is triggered.
// As the length of the ThrottledEventQueue grows delay is increased. The
// delay is scaled such that every kThrottledEventQueueBackPressure runnables
// in the queue equates to an additional kBackPressureDelayMS.
const double kBackPressureDelayMS = 500;
#define DEFAULT_BACK_PRESSURE_DELAY_MS 250
static uint32_t gBackPressureDelayMS;
// This defines a limit for how much the delay must drop before we actually
// reduce back pressure throttle amount. This makes the throttle delay
// a bit "sticky" once we enter back pressure.
const double kBackPressureDelayReductionThresholdMS = 400;
#define DEFAULT_BACK_PRESSURE_DELAY_REDUCTION_THRESHOLD_MS 1000
static uint32_t gBackPressureDelayReductionThresholdMS;
// The minimum delay we can reduce back pressure to before we just floor
// the value back to zero. This allows us to ensure that we can exit
// back pressure event if there are always a small number of runnables
// queued up.
const double kBackPressureDelayMinimumMS = 100;
#define DEFAULT_BACK_PRESSURE_DELAY_MINIMUM_MS 100
static uint32_t gBackPressureDelayMinimumMS;
// Convert a ThrottledEventQueue length to a timer delay in milliseconds.
// This will return a value between 0 and INT32_MAX.
@ -92,8 +96,8 @@ int32_t
CalculateNewBackPressureDelayMS(uint32_t aBacklogDepth)
{
double multiplier = static_cast<double>(aBacklogDepth) /
static_cast<double>(kThrottledEventQueueBackPressure);
double value = kBackPressureDelayMS * multiplier;
static_cast<double>(gThrottledEventQueueBackPressure);
double value = static_cast<double>(gBackPressureDelayMS) * multiplier;
// Avoid overflow
if (value > INT32_MAX) {
value = INT32_MAX;
@ -102,7 +106,7 @@ CalculateNewBackPressureDelayMS(uint32_t aBacklogDepth)
// Once we get close to an empty queue just floor the delay back to zero.
// We want to ensure we don't get stuck in a condition where there is a
// small amount of delay remaining due to an active, but reasonable, queue.
else if (value < kBackPressureDelayMinimumMS) {
else if (value < static_cast<double>(gBackPressureDelayMinimumMS)) {
value = 0;
}
return static_cast<int32_t>(value);
@ -153,6 +157,19 @@ TimeoutManager::Initialize()
Preferences::AddBoolVarCache(&gAnnotateTrackingChannels,
"privacy.trackingprotection.annotate_channels",
false);
Preferences::AddUintVarCache(&gThrottledEventQueueBackPressure,
"dom.timeout.throttled_event_queue_back_pressure",
DEFAULT_THROTTLED_EVENT_QUEUE_BACK_PRESSURE);
Preferences::AddUintVarCache(&gBackPressureDelayMS,
"dom.timeout.back_pressure_delay_ms",
DEFAULT_BACK_PRESSURE_DELAY_MS);
Preferences::AddUintVarCache(&gBackPressureDelayReductionThresholdMS,
"dom.timeout.back_pressure_delay_reduction_threshold_ms",
DEFAULT_BACK_PRESSURE_DELAY_REDUCTION_THRESHOLD_MS);
Preferences::AddUintVarCache(&gBackPressureDelayMinimumMS,
"dom.timeout.back_pressure_delay_minimum_ms",
DEFAULT_BACK_PRESSURE_DELAY_MINIMUM_MS);
}
uint32_t
@ -654,7 +671,7 @@ TimeoutManager::MaybeApplyBackPressure()
// rarely fire under normaly circumstances. Its low enough, though,
// that we should have time to slow new runnables from being added before an
// OOM occurs.
if (queue->Length() < kThrottledEventQueueBackPressure) {
if (queue->Length() < gThrottledEventQueueBackPressure) {
return;
}
@ -712,8 +729,8 @@ TimeoutManager::CancelOrUpdateBackPressure(nsGlobalWindow* aWindow)
// can be quite expensive. We only want to call that method if the back log
// is really clearing.
else if (newBackPressureDelayMS == 0 ||
(newBackPressureDelayMS <=
(mBackPressureDelayMS - kBackPressureDelayReductionThresholdMS))) {
(static_cast<uint32_t>(mBackPressureDelayMS) >
(newBackPressureDelayMS + gBackPressureDelayReductionThresholdMS))) {
int32_t oldBackPressureDelayMS = mBackPressureDelayMS;
mBackPressureDelayMS = newBackPressureDelayMS;

View File

@ -147,7 +147,6 @@ class ImageClient;
class ImageCompositeNotification;
class ImageContainer;
class ImageContainerChild;
class PImageContainerChild;
class SharedPlanarYCbCrImage;
class PlanarYCbCrImage;
class TextureClient;
@ -583,8 +582,6 @@ public:
void NotifyComposite(const ImageCompositeNotification& aNotification);
PImageContainerChild* GetPImageContainerChild();
ImageContainerListener* GetImageContainerListener()
{
return mNotifyCompositeListener;

View File

@ -32,7 +32,6 @@ namespace layers {
class ClientPaintedLayer;
class CompositorBridgeChild;
class ImageLayer;
class PLayerChild;
class FrameUniformityData;
class ClientLayerManager final : public LayerManager
@ -380,9 +379,9 @@ public:
}
};
// Create a shadow layer (PLayerChild) for aLayer, if we're forwarding
// our layer tree to a parent process. Record the new layer creation
// in the current open transaction as a side effect.
// Create a LayerHandle for aLayer, if we're forwarding our layer tree
// to a parent process. Record the new layer creation in the current
// open transaction as a side effect.
template<typename CreatedMethod> void
CreateShadowFor(ClientLayer* aLayer,
ClientLayerManager* aMgr,

View File

@ -25,7 +25,6 @@ class ImageBridgeChild;
class ImageContainer;
class CompositableForwarder;
class CompositableChild;
class PCompositableChild;
class TextureClientRecycleAllocator;
class ContentClientRemote;

View File

@ -37,7 +37,6 @@ class EditReply;
class FixedSizeSmallShmemSectionAllocator;
class ImageContainer;
class Layer;
class PLayerChild;
class PLayerTransactionChild;
class LayerTransactionChild;
class ShadowableLayer;

View File

@ -23,7 +23,6 @@ class VRDisplay;
class VREventObserver;
} // namespace dom
namespace layers {
class PCompositableChild;
class TextureClient;
}
namespace gfx {

View File

@ -7,6 +7,7 @@
#include "vm/TypeInference-inl.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/PodOperations.h"
#include "mozilla/SizePrintfMacros.h"
@ -2606,6 +2607,20 @@ TypeZone::addPendingRecompile(JSContext* cx, JSScript* script)
ObjectStateChange(cx, script->functionNonDelazifying()->group(), false);
}
#ifdef JS_CRASH_DIAGNOSTICS
static char sCrashReason[256];
MOZ_NORETURN MOZ_COLD MOZ_NEVER_INLINE void
js::ReportMagicWordFailure(uintptr_t actual, uintptr_t expected)
{
SprintfLiteral(sCrashReason,
"MOZ_CRASH(Got 0x%" PRIxPTR " expected magic word 0x%" PRIxPTR ")",
actual, expected);
MOZ_CRASH_ANNOTATE(sCrashReason);
MOZ_REALLY_CRASH();
}
#endif
void
js::PrintTypes(JSContext* cx, JSCompartment* comp, bool force)
{

View File

@ -543,6 +543,11 @@ static const uintptr_t BaseTypeInferenceMagic = 0xa1a2b3b4c5c6d7d8;
static const uintptr_t TypeConstraintMagic = BaseTypeInferenceMagic + 1;
static const uintptr_t ConstraintTypeSetMagic = BaseTypeInferenceMagic + 2;
#ifdef JS_CRASH_DIAGNOSTICS
extern MOZ_NORETURN MOZ_COLD MOZ_NEVER_INLINE void
ReportMagicWordFailure(uintptr_t actual, uintptr_t expected);
#endif
/*
* A constraint which listens to additions to a type set and propagates those
* changes to other type sets.
@ -567,7 +572,8 @@ class TypeConstraint
void checkMagic() const {
#ifdef JS_CRASH_DIAGNOSTICS
MOZ_RELEASE_ASSERT(magic_ == TypeConstraintMagic);
if (MOZ_UNLIKELY(magic_ != TypeConstraintMagic))
ReportMagicWordFailure(magic_, TypeConstraintMagic);
#endif
}
@ -669,7 +675,8 @@ class ConstraintTypeSet : public TypeSet
void checkMagic() const {
#ifdef JS_CRASH_DIAGNOSTICS
MOZ_RELEASE_ASSERT(magic_ == ConstraintTypeSetMagic);
if (MOZ_UNLIKELY(magic_ != ConstraintTypeSetMagic))
ReportMagicWordFailure(magic_, ConstraintTypeSetMagic);
#endif
}

View File

@ -1717,7 +1717,7 @@ needs-focus != 703186-1.html 703186-2.html
fuzzy-if(true,1,21) fuzzy-if(d2d,68,173) fuzzy-if(cocoaWidget,1,170) == 718521.html 718521-ref.html # bug 773482
== 720987.html 720987-ref.html
== 722888-1.html 722888-1-ref.html
== 722923-1.html 722923-1-ref.html
fuzzy-if(Android,1,40000) == 722923-1.html 722923-1-ref.html
== 723484-1.html 723484-1-ref.html
random-if(Android) == 728983-1.html 728983-1-ref.html
== 729143-1.html 729143-1-ref.html

View File

@ -3,7 +3,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import base64
import copy
import datetime
import json
import os
@ -545,7 +544,7 @@ class Marionette(object):
CONTEXT_CHROME = "chrome" # non-browser content: windows, dialogs, etc.
CONTEXT_CONTENT = "content" # browser content: iframes, divs, etc.
DEFAULT_SOCKET_TIMEOUT = 65
DEFAULT_SOCKET_TIMEOUT = 60
DEFAULT_STARTUP_TIMEOUT = 120
DEFAULT_SHUTDOWN_TIMEOUT = 65 # Firefox will kill hanging threads after 60s
@ -1248,12 +1247,13 @@ class Marionette(object):
return "{0}{1}".format(self.baseurl, relative_url)
@do_process_check
def start_session(self, capabilities=None, session_id=None, timeout=60):
def start_session(self, desired_capabilities=None, session_id=None, timeout=60):
"""Create a new Marionette session.
This method must be called before performing any other action.
:param capabilities: An optional dict of desired or required capabilities.
:param desired_capabilities: An optional dict of desired
capabilities. This is currently ignored.
:param timeout: Timeout in seconds for the server to be ready.
:param session_id: unique identifier for the session. If no session id is
passed in then one will be generated by the marionette server.
@ -1279,25 +1279,7 @@ class Marionette(object):
self.wait_for_port(timeout=timeout)
self.protocol, _ = self.client.connect()
if capabilities is not None:
caps = copy.deepcopy(capabilities)
else:
caps = {}
# Bug 1322277 - Override some default capabilities which are defined by
# the Webdriver spec but which don't really apply to tests executed with
# the Marionette client. Using "desiredCapabilities" here will allow tests
# to override the settings via "desiredCapabilities" and requiredCapabilities".
if "desiredCapabilities" not in caps:
caps.update({
"desiredCapabilities": {
"timeouts": {
"page load": 60000, # webdriver specifies 300000ms
}
}
})
body = {"capabilities": caps, "sessionId": session_id}
body = {"capabilities": desired_capabilities, "sessionId": session_id}
resp = self._send_message("newSession", body)
self.session_id = resp["sessionId"]

View File

@ -240,7 +240,7 @@ class MarionetteTextTestRunner(StructuredTestRunner):
class BaseMarionetteArguments(ArgumentParser):
socket_timeout_default = 65.0
socket_timeout_default = 60.0
def __init__(self, **kwargs):
ArgumentParser.__init__(self, **kwargs)
@ -347,8 +347,7 @@ class BaseMarionetteArguments(ArgumentParser):
self.add_argument('--socket-timeout',
type=float,
default=self.socket_timeout_default,
help='Set the global timeout for marionette socket operations.'
' Default: %(default)ss.')
help='Set the global timeout for marionette socket operations.')
self.add_argument('--disable-e10s',
action='store_false',
dest='e10s',

View File

@ -11,14 +11,7 @@ class TestCapabilities(MarionetteTestCase):
def setUp(self):
super(TestCapabilities, self).setUp()
# Force default webdriver capabilities by default to test
# Marionette server.
self.marionette.delete_session()
self.marionette.start_session({"desiredCapabilities": {}})
self.caps = self.marionette.session_capabilities
with self.marionette.using_context("chrome"):
self.appinfo = self.marionette.execute_script(
"return Services.appinfo")
@ -40,8 +33,10 @@ class TestCapabilities(MarionetteTestCase):
self.assertEqual(self.caps["platformName"], self.os_name)
self.assertEqual(self.caps["platformVersion"], self.os_version)
self.assertFalse(self.caps["acceptInsecureCerts"])
self.assertEqual(self.caps["timeouts"],
{"implicit": 0, "page load": 300000, "script": 30000})
self.assertDictEqual(self.caps["timeouts"],
{"implicit": 0,
"page load": 300000,
"script": 30000})
def test_supported_features(self):
self.assertIn("rotatable", self.caps)
@ -65,14 +60,6 @@ class TestCapabilities(MarionetteTestCase):
self.assertIn("specificationLevel", self.caps)
self.assertEqual(self.caps["specificationLevel"], 0)
def test_default_client_capabilities(self):
self.marionette.delete_session()
self.marionette.start_session()
caps = self.marionette.session_capabilities
self.assertEqual(caps["timeouts"],
{"implicit": 0, "page load": 60000, "script": 30000})
def test_set_specification_level(self):
self.marionette.delete_session()
self.marionette.start_session({"desiredCapabilities": {"specificationLevel": 2}})
@ -135,8 +122,7 @@ class TestCapabilityMatching(MarionetteTestCase):
for typ in self.allowed:
self.marionette.delete_session()
self.marionette.start_session({"desiredCapabilities": {"browserName": typ}})
self.assertEqual(self.marionette.session_capabilities["browserName"],
self.browser_name)
self.assertEqual(self.marionette.session_capabilities["browserName"], self.browser_name)
def test_browser_name_desired_disallowed_types(self):
for typ in self.disallowed:
@ -147,8 +133,7 @@ class TestCapabilityMatching(MarionetteTestCase):
for typ in self.allowed:
self.marionette.delete_session()
self.marionette.start_session({"requiredCapabilities": {"browserName": typ}})
self.assertEqual(self.marionette.session_capabilities["browserName"],
self.browser_name)
self.assertEqual(self.marionette.session_capabilities["browserName"], self.browser_name)
def test_browser_name_requried_disallowed_types(self):
for typ in self.disallowed:
@ -157,33 +142,30 @@ class TestCapabilityMatching(MarionetteTestCase):
def test_browser_name_prefers_required(self):
caps = {"desiredCapabilities": {"browserName": "invalid"},
"requiredCapabilities": {"browserName": "*"}}
"requiredCapabilities": {"browserName": "*"}}
self.marionette.start_session(caps)
def test_browser_name_error_on_invalid_required(self):
with self.assertRaises(SessionNotCreatedException):
caps = {"desiredCapabilities": {"browserName": "*"},
"requiredCapabilities": {"browserName": "invalid"}}
"requiredCapabilities": {"browserName": "invalid"}}
self.marionette.start_session(caps)
# TODO(ato): browser version comparison not implemented yet
def test_platform_name_desired(self):
self.marionette.start_session(
{"desiredCapabilities": {"platformName": self.platform_name}})
self.marionette.start_session({"desiredCapabilities": {"platformName": self.platform_name}})
self.assertEqual(self.marionette.session_capabilities["platformName"], self.platform_name)
def test_platform_name_required(self):
self.marionette.start_session(
{"requiredCapabilities": {"platformName": self.platform_name}})
self.marionette.start_session({"requiredCapabilities": {"platformName": self.platform_name}})
self.assertEqual(self.marionette.session_capabilities["platformName"], self.platform_name)
def test_platform_name_desired_allowed_types(self):
for typ in self.allowed:
self.marionette.delete_session()
self.marionette.start_session({"desiredCapabilities": {"platformName": typ}})
self.assertEqual(self.marionette.session_capabilities["platformName"],
self.platform_name)
self.assertEqual(self.marionette.session_capabilities["platformName"], self.platform_name)
def test_platform_name_desired_disallowed_types(self):
for typ in self.disallowed:
@ -194,8 +176,7 @@ class TestCapabilityMatching(MarionetteTestCase):
for typ in self.allowed:
self.marionette.delete_session()
self.marionette.start_session({"requiredCapabilities": {"platformName": typ}})
self.assertEqual(self.marionette.session_capabilities["platformName"],
self.platform_name)
self.assertEqual(self.marionette.session_capabilities["platformName"], self.platform_name)
def test_platform_name_requried_disallowed_types(self):
for typ in self.disallowed:
@ -204,13 +185,13 @@ class TestCapabilityMatching(MarionetteTestCase):
def test_platform_name_prefers_required(self):
caps = {"desiredCapabilities": {"platformName": "invalid"},
"requiredCapabilities": {"platformName": "*"}}
"requiredCapabilities": {"platformName": "*"}}
self.marionette.start_session(caps)
def test_platform_name_error_on_invalid_required(self):
with self.assertRaises(SessionNotCreatedException):
caps = {"desiredCapabilities": {"platformName": "*"},
"requiredCapabilities": {"platformName": "invalid"}}
"requiredCapabilities": {"platformName": "invalid"}}
self.marionette.start_session(caps)
# TODO(ato): platform version comparison not imlpemented yet
@ -221,8 +202,7 @@ class TestCapabilityMatching(MarionetteTestCase):
for value in ["", 42, {}, []]:
print(" type {}".format(type(value)))
with self.assertRaises(SessionNotCreatedException):
self.marionette.start_session(
{capability_type: {"acceptInsecureCerts": value}})
self.marionette.start_session({capability_type: {"acceptInsecureCerts": value}})
self.marionette.delete_session()
self.marionette.start_session({"desiredCapabilities": {"acceptInsecureCerts": True}})
@ -261,9 +241,9 @@ class TestCapabilityMatching(MarionetteTestCase):
self.assertEqual(self.marionette.get_pref("network.proxy.type"), 1)
def test_timeouts(self):
timeouts = {"implicit": 123, "page load": 456, "script": 789}
timeouts = {u"implicit": 123, u"page load": 456, u"script": 789}
caps = {"desiredCapabilities": {"timeouts": timeouts}}
self.marionette.start_session(caps)
self.assertIn("timeouts", self.marionette.session_capabilities)
self.assertEqual(self.marionette.session_capabilities["timeouts"], timeouts)
self.assertEqual(self.marionette._send_message("getTimeouts"), timeouts)
self.assertDictEqual(self.marionette.session_capabilities["timeouts"], timeouts)
self.assertDictEqual(self.marionette._send_message("getTimeouts"), timeouts)

View File

@ -1,5 +1,6 @@
[idlharness.html]
type: testharness
prefs: [dom.vr.enabled:true]
[Window interface: attribute onvrdisplayblur]
expected: FAIL

View File

@ -199,7 +199,7 @@ hasFeature(const char** aFeatures, uint32_t aFeatureCount, const char* aFeature)
}
std::vector<ThreadInfo*>* Sampler::sRegisteredThreads = nullptr;
mozilla::UniquePtr<mozilla::Mutex> Sampler::sRegisteredThreadsMutex;
StaticMutex Sampler::sRegisteredThreadsMutex;
Sampler::Sampler(double aInterval, int aEntrySize,
const char** aFeatures, uint32_t aFeatureCount,
@ -251,7 +251,7 @@ Sampler::Sampler(double aInterval, int aEntrySize,
sStartTime = mozilla::TimeStamp::ProcessCreation(ignore);
{
MutexAutoLock lock(*sRegisteredThreadsMutex);
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
// Set up profiling for each registered thread, if appropriate
for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
@ -279,7 +279,7 @@ Sampler::~Sampler()
// Destroy ThreadInfo for all threads
{
MutexAutoLock lock(*sRegisteredThreadsMutex);
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
ThreadInfo* info = sRegisteredThreads->at(i);
@ -307,8 +307,9 @@ Sampler::~Sampler()
void
Sampler::Startup()
{
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
sRegisteredThreads = new std::vector<ThreadInfo*>();
sRegisteredThreadsMutex = MakeUnique<Mutex>("sRegisteredThreadsMutex");
// We could create the sLUL object and read unwind info into it at
// this point. That would match the lifetime implied by destruction
@ -321,17 +322,16 @@ Sampler::Startup()
void
Sampler::Shutdown()
{
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
while (sRegisteredThreads->size() > 0) {
delete sRegisteredThreads->back();
sRegisteredThreads->pop_back();
}
sRegisteredThreadsMutex = nullptr;
delete sRegisteredThreads;
// UnregisterThread can be called after shutdown in XPCShell. Thus
// we need to point to null to ignore such a call after shutdown.
sRegisteredThreadsMutex = nullptr;
delete sRegisteredThreads;
sRegisteredThreads = nullptr;
#if defined(USE_LUL_STACKWALK)
@ -348,12 +348,12 @@ Sampler::RegisterCurrentThread(const char* aName,
PseudoStack* aPseudoStack,
bool aIsMainThread, void* stackTop)
{
if (!sRegisteredThreadsMutex) {
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
if (!sRegisteredThreads) {
return false;
}
MutexAutoLock lock(*sRegisteredThreadsMutex);
Thread::tid_t id = Thread::GetCurrentId();
for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
@ -382,12 +382,12 @@ Sampler::RegisterCurrentThread(const char* aName,
void
Sampler::UnregisterCurrentThread()
{
if (!sRegisteredThreadsMutex) {
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
if (!sRegisteredThreads) {
return;
}
MutexAutoLock lock(*sRegisteredThreadsMutex);
Thread::tid_t id = Thread::GetCurrentId();
for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
@ -426,11 +426,14 @@ Sampler::StreamTaskTracer(SpliceableJSONWriter& aWriter)
aWriter.EndArray();
aWriter.StartArrayProperty("threads");
MutexAutoLock lock(*sRegisteredThreadsMutex);
{
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
for (size_t i = 0; i < sRegisteredThreads->size(); i++) {
// Thread meta data
ThreadInfo* info = sRegisteredThreads->at(i);
aWriter.StartObjectElement();
{
if (XRE_GetProcessType() == GeckoProcessType_Plugin) {
// TODO Add the proper plugin name
aWriter.StringProperty("name", "Plugin");
@ -438,8 +441,10 @@ Sampler::StreamTaskTracer(SpliceableJSONWriter& aWriter)
aWriter.StringProperty("name", info->Name());
}
aWriter.IntProperty("tid", static_cast<int>(info->ThreadId()));
}
aWriter.EndObject();
}
}
aWriter.EndArray();
aWriter.DoubleProperty("start", static_cast<double>(mozilla::tasktracer::GetStartTime()));
@ -665,7 +670,7 @@ Sampler::StreamJSON(SpliceableJSONWriter& aWriter, double aSinceTime)
SetPaused(true);
{
MutexAutoLock lock(*sRegisteredThreadsMutex);
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
for (size_t i = 0; i < sRegisteredThreads->size(); i++) {
// Thread not being profiled, skip it
@ -721,7 +726,7 @@ Sampler::FlushOnJSShutdown(JSContext* aContext)
SetPaused(true);
{
MutexAutoLock lock(*sRegisteredThreadsMutex);
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
for (size_t i = 0; i < sRegisteredThreads->size(); i++) {
// Thread not being profiled, skip it.

View File

@ -161,19 +161,6 @@ static void* setup_atfork() {
}
#endif /* !defined(ANDROID) */
struct SamplerRegistry {
static void AddActiveSampler(Sampler *sampler) {
MOZ_ASSERT(!SamplerRegistry::sampler);
SamplerRegistry::sampler = sampler;
}
static void RemoveActiveSampler(Sampler *sampler) {
SamplerRegistry::sampler = NULL;
}
static Sampler *sampler;
};
Sampler *SamplerRegistry::sampler = NULL;
static mozilla::Atomic<ThreadInfo*> sCurrentThreadInfo;
static sem_t sSignalHandlingDone;
@ -304,18 +291,16 @@ static void* SignalSender(void* arg) {
TimeDuration lastSleepOverhead = 0;
TimeStamp sampleStart = TimeStamp::Now();
while (SamplerRegistry::sampler->IsActive()) {
// XXX: this loop is an off-main-thread use of gSampler
while (gSampler->IsActive()) {
gSampler->DeleteExpiredMarkers();
SamplerRegistry::sampler->DeleteExpiredMarkers();
if (!SamplerRegistry::sampler->IsPaused()) {
MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
const std::vector<ThreadInfo*>& threads =
SamplerRegistry::sampler->GetRegisteredThreads();
if (!gSampler->IsPaused()) {
StaticMutexAutoLock lock(Sampler::sRegisteredThreadsMutex);
bool isFirstProfiledThread = true;
for (uint32_t i = 0; i < threads.size(); i++) {
ThreadInfo* info = threads[i];
for (uint32_t i = 0; i < Sampler::sRegisteredThreads->size(); i++) {
ThreadInfo* info = (*Sampler::sRegisteredThreads)[i];
// This will be null if we're not interested in profiling this thread.
if (!info->hasProfile() || info->IsPendingDelete()) {
@ -371,7 +356,8 @@ static void* SignalSender(void* arg) {
}
}
TimeStamp targetSleepEndTime = sampleStart + TimeDuration::FromMicroseconds(SamplerRegistry::sampler->interval() * 1000);
TimeStamp targetSleepEndTime =
sampleStart + TimeDuration::FromMicroseconds(gSampler->interval() * 1000);
TimeStamp beforeSleep = TimeStamp::Now();
TimeDuration targetSleepDuration = targetSleepEndTime - beforeSleep;
double sleepTime = std::max(0.0, (targetSleepDuration - lastSleepOverhead).ToMicroseconds());
@ -395,8 +381,6 @@ void Sampler::Start() {
}
#endif
SamplerRegistry::AddActiveSampler(this);
// Initialize signal handler communication
sCurrentThreadInfo = nullptr;
if (sem_init(&sSignalHandlingDone, /* pshared: */ 0, /* value: */ 0) != 0) {
@ -452,8 +436,6 @@ void Sampler::Stop() {
signal_sender_launched_ = false;
}
SamplerRegistry::RemoveActiveSampler(this);
// Restore old signal handler
if (signal_handler_installed_) {
sigaction(SIGPROF, &old_sigprof_signal_handler_, 0);

View File

@ -43,21 +43,6 @@ using mozilla::TimeDuration;
// this port is based off of v8 svn revision 9837
// XXX: this is a very stubbed out implementation
// that only supports a single Sampler
struct SamplerRegistry {
static void AddActiveSampler(Sampler *sampler) {
MOZ_ASSERT(!SamplerRegistry::sampler);
SamplerRegistry::sampler = sampler;
}
static void RemoveActiveSampler(Sampler *sampler) {
SamplerRegistry::sampler = NULL;
}
static Sampler *sampler;
};
Sampler *SamplerRegistry::sampler = NULL;
#ifdef DEBUG
// 0 is never a valid thread id on MacOSX since a pthread_t is a pointer.
static const pthread_t kNoThread = (pthread_t) 0;
@ -153,19 +138,17 @@ public:
pthread_join(mThread, NULL);
}
static void AddActiveSampler(Sampler* sampler) {
SamplerRegistry::AddActiveSampler(sampler);
static void AddActiveSampler() {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (mInstance == NULL) {
mInstance = new SamplerThread(sampler->interval());
mInstance = new SamplerThread(gSampler->interval());
mInstance->Start();
}
}
static void RemoveActiveSampler(Sampler* sampler) {
static void RemoveActiveSampler() {
mInstance->Join();
//XXX: unlike v8 we need to remove the active sampler after doing the Join
// because we drop the sampler immediately
SamplerRegistry::RemoveActiveSampler(sampler);
delete mInstance;
mInstance = NULL;
}
@ -173,15 +156,17 @@ public:
void Run() {
TimeDuration lastSleepOverhead = 0;
TimeStamp sampleStart = TimeStamp::Now();
while (SamplerRegistry::sampler->IsActive()) {
SamplerRegistry::sampler->DeleteExpiredMarkers();
if (!SamplerRegistry::sampler->IsPaused()) {
MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
const std::vector<ThreadInfo*>& threads =
SamplerRegistry::sampler->GetRegisteredThreads();
// XXX: this loop is an off-main-thread use of gSampler
while (gSampler->IsActive()) {
gSampler->DeleteExpiredMarkers();
if (!gSampler->IsPaused()) {
StaticMutexAutoLock lock(Sampler::sRegisteredThreadsMutex);
bool isFirstProfiledThread = true;
for (uint32_t i = 0; i < threads.size(); i++) {
ThreadInfo* info = threads[i];
for (uint32_t i = 0; i < Sampler::sRegisteredThreads->size(); i++) {
ThreadInfo* info = (*Sampler::sRegisteredThreads)[i];
// This will be null if we're not interested in profiling this thread.
if (!info->hasProfile() || info->IsPendingDelete()) {
@ -196,7 +181,7 @@ public:
info->UpdateThreadResponsiveness();
SampleContext(SamplerRegistry::sampler, info, isFirstProfiledThread);
SampleContext(info, isFirstProfiledThread);
isFirstProfiledThread = false;
}
}
@ -211,8 +196,7 @@ public:
}
}
void SampleContext(Sampler* sampler, ThreadInfo* aThreadInfo,
bool isFirstProfiledThread)
void SampleContext(ThreadInfo* aThreadInfo, bool isFirstProfiledThread)
{
thread_act_t profiled_thread =
aThreadInfo->GetPlatformData()->profiled_thread();
@ -267,7 +251,8 @@ public:
sample->timestamp = mozilla::TimeStamp::Now();
sample->threadInfo = aThreadInfo;
sampler->Tick(sample);
// XXX: this is an off-main-thread use of gSampler
gSampler->Tick(sample);
}
thread_resume(profiled_thread);
}
@ -289,13 +274,13 @@ SamplerThread* SamplerThread::mInstance = NULL;
void Sampler::Start() {
MOZ_ASSERT(!IsActive());
SetActive(true);
SamplerThread::AddActiveSampler(this);
SamplerThread::AddActiveSampler();
}
void Sampler::Stop() {
MOZ_ASSERT(IsActive());
SetActive(false);
SamplerThread::RemoveActiveSampler(this);
SamplerThread::RemoveActiveSampler();
}
/* static */ Thread::tid_t

View File

@ -96,10 +96,9 @@ class SamplerThread
public:
// Initialize a Win32 thread object. The thread has an invalid thread
// handle until it is started.
SamplerThread(double interval, Sampler* sampler)
explicit SamplerThread(double interval)
: mStackSize(0)
, mThread(kNoThread)
, mSampler(sampler)
, mInterval(interval)
{
mInterval = floor(interval + 0.5);
@ -140,12 +139,14 @@ class SamplerThread
}
}
static void StartSampler(Sampler* sampler) {
static void StartSampler() {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (mInstance == NULL) {
mInstance = new SamplerThread(sampler->interval(), sampler);
mInstance = new SamplerThread(gSampler->interval());
mInstance->Start();
} else {
MOZ_ASSERT(mInstance->mInterval == sampler->interval());
MOZ_ASSERT(mInstance->mInterval == gSampler->interval());
}
}
@ -162,16 +163,16 @@ class SamplerThread
if (mInterval < 10)
::timeBeginPeriod(mInterval);
while (mSampler->IsActive()) {
mSampler->DeleteExpiredMarkers();
// XXX: this loop is an off-main-thread use of gSampler
while (gSampler->IsActive()) {
gSampler->DeleteExpiredMarkers();
if (!gSampler->IsPaused()) {
mozilla::StaticMutexAutoLock lock(Sampler::sRegisteredThreadsMutex);
if (!mSampler->IsPaused()) {
mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
const std::vector<ThreadInfo*>& threads =
mSampler->GetRegisteredThreads();
bool isFirstProfiledThread = true;
for (uint32_t i = 0; i < threads.size(); i++) {
ThreadInfo* info = threads[i];
for (uint32_t i = 0; i < Sampler::sRegisteredThreads->size(); i++) {
ThreadInfo* info = (*Sampler::sRegisteredThreads)[i];
// This will be null if we're not interested in profiling this thread.
if (!info->hasProfile() || info->IsPendingDelete()) {
@ -186,7 +187,7 @@ class SamplerThread
info->UpdateThreadResponsiveness();
SampleContext(mSampler, info, isFirstProfiledThread);
SampleContext(info, isFirstProfiledThread);
isFirstProfiledThread = false;
}
}
@ -198,8 +199,7 @@ class SamplerThread
::timeEndPeriod(mInterval);
}
void SampleContext(Sampler* sampler, ThreadInfo* aThreadInfo,
bool isFirstProfiledThread)
void SampleContext(ThreadInfo* aThreadInfo, bool isFirstProfiledThread)
{
uintptr_t thread = Sampler::GetThreadHandle(aThreadInfo->GetPlatformData());
HANDLE profiled_thread = reinterpret_cast<HANDLE>(thread);
@ -281,7 +281,9 @@ class SamplerThread
#endif
sample->context = &context;
sampler->Tick(sample);
// XXX: this is an off-main-thread use of gSampler
gSampler->Tick(sample);
ResumeThread(profiled_thread);
}
@ -291,7 +293,6 @@ private:
HANDLE mThread;
Thread::tid_t mThreadId;
Sampler* mSampler;
int mInterval; // units: ms
// Protects the process wide state below.
@ -305,7 +306,7 @@ SamplerThread* SamplerThread::mInstance = NULL;
void Sampler::Start() {
MOZ_ASSERT(!IsActive());
SetActive(true);
SamplerThread::StartSampler(this);
SamplerThread::StartSampler();
}
void Sampler::Stop() {

View File

@ -744,11 +744,10 @@ profiler_start(int aProfileEntries, double aInterval,
gSampler->Start();
if (gSampler->ProfileJS() || gSampler->InPrivacyMode()) {
mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
const std::vector<ThreadInfo*>& threads = gSampler->GetRegisteredThreads();
mozilla::StaticMutexAutoLock lock(Sampler::sRegisteredThreadsMutex);
for (uint32_t i = 0; i < threads.size(); i++) {
ThreadInfo* info = threads[i];
for (uint32_t i = 0; i < Sampler::sRegisteredThreads->size(); i++) {
ThreadInfo* info = (*Sampler::sRegisteredThreads)[i];
if (info->IsPendingDelete() || !info->hasProfile()) {
continue;
}

View File

@ -42,7 +42,7 @@
#include <stdint.h>
#include <math.h>
#include "MainThreadUtils.h"
#include "mozilla/Mutex.h"
#include "mozilla/StaticMutex.h"
#include "ThreadResponsiveness.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
@ -297,10 +297,6 @@ public:
static uintptr_t GetThreadHandle(PlatformData*);
#endif
static const std::vector<ThreadInfo*>& GetRegisteredThreads() {
return *sRegisteredThreads;
}
static bool RegisterCurrentThread(const char* aName,
PseudoStack* aPseudoStack,
bool aIsMainThread, void* stackTop);
@ -310,7 +306,8 @@ public:
// Should only be called on shutdown
static void Shutdown();
static mozilla::UniquePtr<mozilla::Mutex> sRegisteredThreadsMutex;
static mozilla::StaticMutex sRegisteredThreadsMutex;
static std::vector<ThreadInfo*>* sRegisteredThreads;
static bool CanNotifyObservers() {
#ifdef MOZ_WIDGET_GONK
@ -365,8 +362,6 @@ private:
void SetActive(bool value) { NoBarrier_Store(&active_, value); }
static std::vector<ThreadInfo*>* sRegisteredThreads;
const double interval_;
Atomic32 paused_;
Atomic32 active_;