Merge inbound to m-c.
Merge inbound to m-c.
--- a/addon-sdk/source/lib/toolkit/loader.js
+++ b/addon-sdk/source/lib/toolkit/loader.js
@@ -132,35 +132,39 @@ exports.sourceURI = iced(sourceURI);
function isntLoaderFrame(frame) { return frame.fileName !== module.uri }
var parseStack = iced(function parseStack(stack) {
let lines = String(stack).split("\n");
return lines.reduce(function(frames, line) {
if (line) {
let atIndex = line.indexOf("@");
let columnIndex = line.lastIndexOf(":");
- let fileName = sourceURI(line.slice(atIndex + 1, columnIndex));
- let lineNumber = parseInt(line.slice(columnIndex + 1));
+ let lineIndex = line.lastIndexOf(":", columnIndex - 1);
+ let fileName = sourceURI(line.slice(atIndex + 1, lineIndex));
+ let lineNumber = parseInt(line.slice(lineIndex + 1, columnIndex));
+ let columnNumber = parseInt(line.slice(columnIndex + 1));
let name = line.slice(0, atIndex).split("(").shift();
frames.unshift({
fileName: fileName,
name: name,
- lineNumber: lineNumber
+ lineNumber: lineNumber,
+ columnNumber: columnNumber
});
}
return frames;
}, []);
})
exports.parseStack = parseStack
var serializeStack = iced(function serializeStack(frames) {
return frames.reduce(function(stack, frame) {
return frame.name + "@" +
frame.fileName + ":" +
- frame.lineNumber + "\n" +
+ frame.lineNumber + ":" +
+ frame.columnNumber + "\n" +
stack;
}, "");
})
exports.serializeStack = serializeStack
function readURI(uri) {
let stream = NetUtil.newChannel(uri, 'UTF-8', null).open();
let count = stream.available();
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -679,17 +679,17 @@ var gPluginHandler = {
gPluginHandler._showClickToPlayNotification(browser, null, false);
},
_clickToPlayNotificationEventCallback: function PH_ctpEventCallback(event) {
if (event == "showing") {
Services.telemetry.getHistogramById("PLUGINS_NOTIFICATION_SHOWN")
.add(!this.options.primaryPlugin);
// Histograms always start at 0, even though our data starts at 1
- let histogramCount = this.options.centerActions.size - 1;
+ let histogramCount = this.options.pluginData.size - 1;
if (histogramCount > 4) {
histogramCount = 4;
}
Services.telemetry.getHistogramById("PLUGINS_NOTIFICATION_PLUGIN_COUNT")
.add(histogramCount);
}
else if (event == "dismissed") {
// Once the popup is dismissed, clicking the icon should show the full
@@ -839,34 +839,34 @@ var gPluginHandler = {
PopupNotifications.remove(notification);
}
return;
}
} else {
plugins = [aPlugin];
}
- // If this is a new notification, create a centerActions map, otherwise append
- let centerActions;
+ // If this is a new notification, create a pluginData map, otherwise append
+ let pluginData;
if (notification) {
- centerActions = notification.options.centerActions;
+ pluginData = notification.options.pluginData;
} else {
- centerActions = new Map();
+ pluginData = new Map();
}
let principal = aBrowser.contentDocument.nodePrincipal;
let principalHost = this._getHostFromPrincipal(principal);
for (var plugin of plugins) {
let pluginInfo = this._getPluginInfo(plugin);
if (pluginInfo.permissionString === null) {
Cu.reportError("No permission string for active plugin.");
continue;
}
- if (centerActions.has(pluginInfo.permissionString)) {
+ if (pluginData.has(pluginInfo.permissionString)) {
continue;
}
let permissionObj = Services.perms.
getPermissionObject(principal, pluginInfo.permissionString, false);
if (permissionObj) {
pluginInfo.pluginPermissionHost = permissionObj.host;
pluginInfo.pluginPermissionType = permissionObj.expireType;
@@ -883,18 +883,18 @@ var gPluginHandler = {
}
else if (pluginInfo.blocklistState != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
url = Services.blocklist.getPluginBlocklistURL(pluginInfo.pluginTag);
}
else {
url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "clicktoplay";
}
pluginInfo.detailsLink = url;
-
- centerActions.set(pluginInfo.permissionString, pluginInfo);
+
+ pluginData.set(pluginInfo.permissionString, pluginInfo);
}
let primaryPluginPermission = null;
if (aShowNow) {
primaryPluginPermission = this._getPluginInfo(aPlugin).permissionString;
}
if (notification) {
@@ -907,17 +907,17 @@ var gPluginHandler = {
}
return;
}
let options = {
dismissed: !aShowNow,
eventCallback: this._clickToPlayNotificationEventCallback,
primaryPlugin: primaryPluginPermission,
- centerActions: centerActions
+ pluginData: pluginData
};
PopupNotifications.show(aBrowser, "click-to-play-plugins",
"", "plugins-notification-icon",
null, null, options);
setTimeout(() => { this._setPluginNotificationIcon(aBrowser); }, 0);
},
_setPluginNotificationIcon : function PH_setPluginNotificationIcon(aBrowser) {
@@ -929,17 +929,17 @@ var gPluginHandler = {
let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
if (!notification)
return;
// Make a copy of the actions, removing active plugins and checking for
// outdated plugins.
let haveInsecure = false;
let actions = new Map();
- for (let action of notification.options.centerActions.values()) {
+ for (let action of notification.options.pluginData.values()) {
switch (action.fallbackType) {
// haveInsecure will trigger the red flashing icon and the infobar
// styling below
case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE:
case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE:
haveInsecure = true;
// fall through
--- a/browser/base/content/test/general/browser_CTP_data_urls.js
+++ b/browser/base/content/test/general/browser_CTP_data_urls.js
@@ -110,20 +110,20 @@ function test2a() {
}
function test2b() {
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 2b, Should have a click-to-play notification");
// Simulate choosing "Allow now" for the test plugin
notification.reshow();
- is(notification.options.centerActions.size, 2, "Test 2b, Should have two types of plugin in the notification");
+ is(notification.options.pluginData.size, 2, "Test 2b, Should have two types of plugin in the notification");
var centerAction = null;
- for (var action of notification.options.centerActions.values()) {
+ for (var action of notification.options.pluginData.values()) {
if (action.pluginName == "Test") {
centerAction = action;
break;
}
}
ok(centerAction, "Test 2b, found center action for the Test plugin");
var centerItem = null;
--- a/browser/base/content/test/general/browser_CTP_multi_allow.js
+++ b/browser/base/content/test/general/browser_CTP_multi_allow.js
@@ -71,17 +71,17 @@ function test1a() {
let plugin = doc.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test1a, Plugin should not be activated");
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 1a, Should have a click-to-play notification");
notification.reshow();
- is(notification.options.centerActions.size, 2,
+ is(notification.options.pluginData.size, 2,
"Test 1a, Should have two types of plugin in the notification");
let pluginItem = null;
for (let item of PopupNotifications.panel.firstChild.childNodes) {
is(item.value, "block", "Test 1a, all plugins should start out blocked");
if (item.action.pluginName == "Test") {
pluginItem = item;
}
--- a/browser/base/content/test/general/browser_bug820497.js
+++ b/browser/base/content/test/general/browser_bug820497.js
@@ -35,25 +35,25 @@ function pluginBindingAttached() {
var testplugin = doc.getElementById("test");
ok(testplugin, "should have test plugin");
var secondtestplugin = doc.getElementById("secondtest");
ok(!secondtestplugin, "should not yet have second test plugin");
var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "should have popup notification");
// We don't set up the action list until the notification is shown
notification.reshow();
- is(notification.options.centerActions.size, 1, "should be 1 type of plugin in the popup notification");
+ is(notification.options.pluginData.size, 1, "should be 1 type of plugin in the popup notification");
XPCNativeWrapper.unwrap(gTestBrowser.contentWindow).addSecondPlugin();
} else if (gNumPluginBindingsAttached == 2) {
var doc = gTestBrowser.contentDocument;
var testplugin = doc.getElementById("test");
ok(testplugin, "should have test plugin");
var secondtestplugin = doc.getElementById("secondtest");
ok(secondtestplugin, "should have second test plugin");
var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "should have popup notification");
notification.reshow();
- is(notification.options.centerActions.size, 2, "should be 2 types of plugin in the popup notification");
+ is(notification.options.pluginData.size, 2, "should be 2 types of plugin in the popup notification");
finish();
} else {
ok(false, "if we've gotten here, something is quite wrong");
}
}
--- a/browser/base/content/test/general/browser_pluginnotification.js
+++ b/browser/base/content/test/general/browser_pluginnotification.js
@@ -174,17 +174,17 @@ function prepareTest5() {
function test5() {
info("test5");
ok(!PopupNotifications.getNotification("plugins-not-found", gTestBrowser), "Test 5, Should not have displayed the missing plugin notification");
let notification = PopupNotifications.getNotification("click-to-play-plugins");
ok(notification, "Test 5: There should be a plugin notification for blocked plugins");
ok(notification.dismissed, "Test 5: The plugin notification should be dismissed by default");
notification.reshow();
- is(notification.options.centerActions.size, 1, "Test 5: Only the blocked plugin should be present in the notification");
+ is(notification.options.pluginData.size, 1, "Test 5: Only the blocked plugin should be present in the notification");
ok(PopupNotifications.panel.firstChild._buttonContainer.hidden, "Part 5: The blocked plugins notification should not have any buttons visible.");
ok(!gTestBrowser.missingPlugins, "Test 5, Should not be a missing plugin list");
var pluginNode = gTestBrowser.contentDocument.getElementById("test");
ok(pluginNode, "Test 5, Found plugin in page");
var objLoadingContent = pluginNode.QueryInterface(Ci.nsIObjectLoadingContent);
is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED, "Test 5, plugin fallback type should be PLUGIN_BLOCKLISTED");
@@ -599,20 +599,20 @@ function test21a() {
ok(rect.width == 200, "Test 21a, Plugin with id=" + plugin.id + " overlay rect should have 200px width before being clicked");
ok(rect.height == 200, "Test 21a, Plugin with id=" + plugin.id + " overlay rect should have 200px height before being clicked");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test 21a, Plugin with id=" + plugin.id + " should not be activated");
}
// we have to actually show the panel to get the bindings to instantiate
notification.reshow();
- is(notification.options.centerActions.size, 2, "Test 21a, Should have two types of plugin in the notification");
+ is(notification.options.pluginData.size, 2, "Test 21a, Should have two types of plugin in the notification");
var centerAction = null;
- for (var action of notification.options.centerActions.values()) {
+ for (var action of notification.options.pluginData.values()) {
if (action.pluginName == "Test") {
centerAction = action;
break;
}
}
ok(centerAction, "Test 21b, found center action for the Test plugin");
var centerItem = null;
@@ -636,17 +636,17 @@ function test21a() {
waitForCondition(condition, test21c, "Test 21b, Waited too long for plugin to activate");
}
function test21c() {
var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 21c, Should have a click-to-play notification");
notification.reshow();
- ok(notification.options.centerActions.size == 2, "Test 21c, Should have one type of plugin in the notification");
+ ok(notification.options.pluginData.size == 2, "Test 21c, Should have one type of plugin in the notification");
var doc = gTestBrowser.contentDocument;
var plugin = doc.getElementById("test");
var rect = doc.getAnonymousElementByAttribute(plugin, "anonid", "main").getBoundingClientRect();
ok(rect.width == 0, "Test 21c, Plugin with id=" + plugin.id + " overlay rect should have 0px width after being clicked");
ok(rect.height == 0, "Test 21c, Plugin with id=" + plugin.id + " overlay rect should have 0px height after being clicked");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 21c, Plugin with id=" + plugin.id + " should be activated");
@@ -657,17 +657,17 @@ function test21c() {
var rect = doc.getAnonymousElementByAttribute(plugin, "anonid", "main").getBoundingClientRect();
ok(rect.width == 200, "Test 21c, Plugin with id=" + plugin.id + " overlay rect should have 200px width before being clicked");
ok(rect.height == 200, "Test 21c, Plugin with id=" + plugin.id + " overlay rect should have 200px height before being clicked");
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test 21c, Plugin with id=" + plugin.id + " should not be activated");
}
var centerAction = null;
- for (var action of notification.options.centerActions.values()) {
+ for (var action of notification.options.pluginData.values()) {
if (action.pluginName == "Second Test") {
centerAction = action;
break;
}
}
ok(centerAction, "Test 21d, found center action for the Second Test plugin");
var centerItem = null;
--- a/browser/base/content/test/general/browser_plugins_added_dynamically.js
+++ b/browser/base/content/test/general/browser_plugins_added_dynamically.js
@@ -63,17 +63,17 @@ function testActivateAddSameTypePart2()
popupNotification.reshow();
testActivateAddSameTypePart3();
}
function testActivateAddSameTypePart3() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
let centerAction = null;
- for (let action of popupNotification.options.centerActions.values()) {
+ for (let action of popupNotification.options.pluginData.values()) {
if (action.pluginName == "Test") {
centerAction = action;
break;
}
}
ok(centerAction, "testActivateAddSameTypePart3: found center action for the Test plugin");
let centerItem = null;
@@ -137,17 +137,17 @@ function testActivateAddDifferentTypePar
// we have to actually show the panel to get the bindings to instantiate
popupNotification.reshow();
testActivateAddDifferentTypePart3();
}
function testActivateAddDifferentTypePart3() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
- is(popupNotification.options.centerActions.size, 1, "Should be one plugin action");
+ is(popupNotification.options.pluginData.size, 1, "Should be one plugin action");
let plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[0];
ok(!plugin.activated, "testActivateAddDifferentTypePart3: plugin should not be activated");
// "click" the button to activate the Test plugin
PopupNotifications.panel.firstChild._primaryButton.click();
let condition = function() plugin.activated;
--- a/browser/base/content/test/general/browser_tabopen_reflows.js
+++ b/browser/base/content/test/general/browser_tabopen_reflows.js
@@ -80,17 +80,17 @@ function test() {
finish();
});
}
let observer = {
reflow: function (start, end) {
// Gather information about the current code path.
let path = (new Error().stack).split("\n").slice(1).map(line => {
- return line.replace(/:\d+$/, "");
+ return line.replace(/:\d+:\d+$/, "");
}).join("|");
let pathWithLineNumbers = (new Error().stack).split("\n").slice(1).join("|");
// Stack trace is empty. Reflow was triggered by native code.
if (path === "") {
return;
}
--- a/browser/base/content/test/general/browser_windowopen_reflows.js
+++ b/browser/base/content/test/general/browser_windowopen_reflows.js
@@ -70,17 +70,17 @@ function test() {
});
}
let observer = {
reflow: function (start, end) {
// Gather information about the current code path.
let stack = new Error().stack;
let path = stack.split("\n").slice(1).map(line => {
- return line.replace(/:\d+$/, "");
+ return line.replace(/:\d+:\d+$/, "");
}).join("|");
let pathWithLineNumbers = (new Error().stack).split("\n").slice(1).join("|");
// Stack trace is empty. Reflow was triggered by native code.
if (path === "") {
return;
}
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -1559,17 +1559,17 @@
</field>
<field name="_brandShortName">
document.getElementById("bundle_brand").getString("brandShortName")
</field>
<field name="_items">[]</field>
<constructor><![CDATA[
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
let sortedActions = [];
- for (let action of this.notification.options.centerActions.values()) {
+ for (let action of this.notification.options.pluginData.values()) {
sortedActions.push(action);
}
sortedActions.sort((a, b) => a.pluginName.localeCompare(b.pluginName));
for (let action of sortedActions) {
let item = document.createElementNS(XUL_NS, "row");
item.setAttribute("class", "plugin-popupnotification-centeritem");
item.action = action;
--- a/browser/components/preferences/in-content/moz.build
+++ b/browser/components/preferences/in-content/moz.build
@@ -1,13 +1,15 @@
# -*- 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/.
+TEST_DIRS += ['tests']
+
for var in ('MOZ_APP_NAME', 'MOZ_MACBUNDLE_NAME'):
DEFINES[var] = CONFIG[var]
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'cocoa'):
DEFINES['HAVE_SHELL_SERVICE'] = 1
-JAR_MANIFESTS += ['jar.mn']
\ No newline at end of file
+JAR_MANIFESTS += ['jar.mn']
--- a/browser/components/preferences/in-content/tests/Makefile.in
+++ b/browser/components/preferences/in-content/tests/Makefile.in
@@ -4,14 +4,8 @@
ifdef ENABLE_TESTS
pp_mochitest_browser_files := \
browser_privacypane_4.js \
$(NULL)
pp_mochitest_browser_files_PATH := $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
PP_TARGETS += pp_mochitest_browser_files
endif # ENABLE_TESTS
-
-ifdef MOZ_SERVICES_HEALTHREPORT
-MOCHITEST_BROWSER_FILES += \
- browser_healthreport.js \
- $(NULL)
-endif
--- a/browser/components/preferences/in-content/tests/browser.ini
+++ b/browser/components/preferences/in-content/tests/browser.ini
@@ -2,12 +2,14 @@
support-files =
head.js
privacypane_tests_perwindow.js
[browser_advanced_update.js]
[browser_bug410900.js]
[browser_bug731866.js]
[browser_connection.js]
+[browser_healthreport.js]
+skip-if = (!healthreport) || (os == 'linux' && debug)
[browser_privacypane_1.js]
[browser_privacypane_3.js]
[browser_privacypane_5.js]
[browser_privacypane_8.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/in-content/tests/moz.build
@@ -0,0 +1,5 @@
+# -*- 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/.
--- a/browser/components/preferences/moz.build
+++ b/browser/components/preferences/moz.build
@@ -1,20 +1,21 @@
# -*- 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/.
PARALLEL_DIRS += ['in-content']
+TEST_DIRS += ['tests']
BROWSER_CHROME_MANIFESTS += [
'in-content/tests/browser.ini',
'tests/browser.ini',
]
for var in ('MOZ_APP_NAME', 'MOZ_MACBUNDLE_NAME'):
DEFINES[var] = CONFIG[var]
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'):
DEFINES['HAVE_SHELL_SERVICE'] = 1
-JAR_MANIFESTS += ['jar.mn']
\ No newline at end of file
+JAR_MANIFESTS += ['jar.mn']
--- a/browser/components/preferences/tests/Makefile.in
+++ b/browser/components/preferences/tests/Makefile.in
@@ -4,12 +4,8 @@
ifdef ENABLE_TESTS
pp_mochitest_browser_files := \
browser_privacypane_4.js \
$(NULL)
pp_mochitest_browser_files_PATH := $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
PP_TARGETS += pp_mochitest_browser_files
endif # ENABLE_TESTS
-
-ifdef MOZ_SERVICES_HEALTHREPORT
-MOCHITEST_BROWSER_FILES += browser_healthreport.js
-endif
--- a/browser/components/preferences/tests/browser.ini
+++ b/browser/components/preferences/tests/browser.ini
@@ -2,13 +2,15 @@
support-files =
head.js
privacypane_tests_perwindow.js
[browser_advanced_update.js]
[browser_bug410900.js]
[browser_bug705422.js]
[browser_chunk_permissions.js]
+[browser_healthreport.js]
+skip-if = (!healthreport) || (os == 'linux' && debug)
[browser_permissions.js]
[browser_privacypane_1.js]
[browser_privacypane_3.js]
[browser_privacypane_5.js]
[browser_privacypane_8.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/tests/moz.build
@@ -0,0 +1,5 @@
+# -*- 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/.
--- a/browser/devtools/scratchpad/test/browser_scratchpad_display_non_error_exceptions.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_display_non_error_exceptions.js
@@ -36,17 +36,17 @@ function runTests()
result: message + openComment + "Hello World!" + closeComment,
label: "message display output"
},
{
// Display error1, throw new Error("Ouch")
method: "display",
code: error1,
result: error1 + openComment +
- "Exception: Ouch!\n@" + scratchpad.uniqueName + ":1" + closeComment,
+ "Exception: Ouch!\n@" + scratchpad.uniqueName + ":1:1" + closeComment,
label: "error display output"
},
{
// Display error2, throw "A thrown string"
method: "display",
code: error2,
result: error2 + openComment + "Exception: A thrown string" + closeComment,
label: "thrown string display output"
@@ -73,17 +73,17 @@ function runTests()
result: message,
label: "message run output"
},
{
// Run error1, throw new Error("Ouch")
method: "run",
code: error1,
result: error1 + openComment +
- "Exception: Ouch!\n@" + scratchpad.uniqueName + ":1" + closeComment,
+ "Exception: Ouch!\n@" + scratchpad.uniqueName + ":1:1" + closeComment,
label: "error run output"
},
{
// Run error2, throw "A thrown string"
method: "run",
code: error2,
result: error2 + openComment + "Exception: A thrown string" + closeComment,
label: "thrown string run output"
--- a/browser/devtools/scratchpad/test/browser_scratchpad_display_outputs_errors.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_display_outputs_errors.js
@@ -32,17 +32,17 @@ function runTests()
code: message,
result: message + openComment + "Hello World!" + closeComment,
label: "message display output"
},
{
method: "display",
code: error,
result: error + openComment + "Exception: Ouch!\n@" +
- scratchpad.uniqueName + ":1" + closeComment,
+ scratchpad.uniqueName + ":1:1" + closeComment,
label: "error display output",
},
{
method: "display",
code: syntaxError,
result: syntaxError + openComment + "Exception: syntax error\n@" +
scratchpad.uniqueName + ":1" + closeComment,
label: "syntaxError display output",
@@ -52,17 +52,17 @@ function runTests()
code: message,
result: message,
label: "message run output",
},
{
method: "run",
code: error,
result: error + openComment + "Exception: Ouch!\n@" +
- scratchpad.uniqueName + ":1" + closeComment,
+ scratchpad.uniqueName + ":1:1" + closeComment,
label: "error run output",
},
{
method: "run",
code: syntaxError,
result: syntaxError + openComment + "Exception: syntax error\n@" +
scratchpad.uniqueName + ":1" + closeComment,
label: "syntaxError run output",
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -3219,26 +3219,30 @@ WebGLContext::CompileShader(WebGLShader
#endif
}
#ifdef WEBGL2_BYPASS_ANGLE
if (!ShCompile(compiler, &angleShaderCode, 1, compileOptions)) {
#else
if (!ShCompile(compiler, &s, 1, compileOptions)) {
#endif
- size_t len = 0;
- ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &len);
-
- if (len) {
+ size_t lenWithNull = 0;
+ ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &lenWithNull);
+
+ if (!lenWithNull) {
+ // Error in ShGetInfo.
+ shader->SetTranslationFailure(NS_LITERAL_CSTRING("Internal error: failed to get shader info log"));
+ } else {
+ size_t len = lenWithNull - 1;
+
nsAutoCString info;
- info.SetLength(len);
+ info.SetLength(len); // Allocates len+1, for the null-term.
ShGetInfoLog(compiler, info.BeginWriting());
+
shader->SetTranslationFailure(info);
- } else {
- shader->SetTranslationFailure(NS_LITERAL_CSTRING("Internal error: failed to get shader info log"));
}
ShDestruct(compiler);
shader->SetCompileStatus(false);
return;
}
size_t num_attributes = 0;
ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTES, &num_attributes);
--- a/content/html/content/public/HTMLCanvasElement.h
+++ b/content/html/content/public/HTMLCanvasElement.h
@@ -78,28 +78,25 @@ public:
{
SetUnsignedIntAttr(nsGkAtoms::width, aWidth, aRv);
}
already_AddRefed<nsISupports>
GetContext(JSContext* aCx, const nsAString& aContextId,
JS::Handle<JS::Value> aContextOptions,
ErrorResult& aRv);
void ToDataURL(JSContext* aCx, const nsAString& aType,
- const Optional<JS::Handle<JS::Value> >& aParams,
+ JS::Handle<JS::Value> aParams,
nsAString& aDataURL, ErrorResult& aRv)
{
- JS::Handle<JS::Value> params = aParams.WasPassed()
- ? aParams.Value()
- : JS::UndefinedHandleValue;
- aRv = ToDataURL(aType, params, aCx, aDataURL);
+ aRv = ToDataURL(aType, aParams, aCx, aDataURL);
}
void ToBlob(JSContext* aCx,
FileCallback& aCallback,
const nsAString& aType,
- const Optional<JS::Handle<JS::Value> >& aParams,
+ JS::Handle<JS::Value> aParams,
ErrorResult& aRv);
bool MozOpaque() const
{
return GetBoolAttr(nsGkAtoms::moz_opaque);
}
void SetMozOpaque(bool aValue, ErrorResult& aRv)
{
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -482,38 +482,34 @@ HTMLCanvasElement::ToDataURLImpl(JSConte
return Base64EncodeInputStream(stream, aDataURL, (uint32_t)count, aDataURL.Length());
}
void
HTMLCanvasElement::ToBlob(JSContext* aCx,
FileCallback& aCallback,
const nsAString& aType,
- const Optional<JS::Handle<JS::Value> >& aParams,
+ JS::Handle<JS::Value> aParams,
ErrorResult& aRv)
{
// do a trust check if this is a write-only canvas
if (mWriteOnly && !nsContentUtils::IsCallerChrome()) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
nsAutoString type;
aRv = nsContentUtils::ASCIIToLower(aType, type);
if (aRv.Failed()) {
return;
}
- JS::Value encoderOptions = aParams.WasPassed()
- ? aParams.Value()
- : JS::UndefinedValue();
-
nsAutoString params;
bool usingCustomParseOptions;
- aRv = ParseParams(aCx, type, encoderOptions, params, &usingCustomParseOptions);
+ aRv = ParseParams(aCx, type, aParams, params, &usingCustomParseOptions);
if (aRv.Failed()) {
return;
}
#ifdef DEBUG
if (mCurrentContext) {
// We disallow canvases of width or height zero, and set them to 1, so
// we will have a discrepancy with the sizes of the canvas and the context.
--- a/content/media/gstreamer/GStreamerReader.cpp
+++ b/content/media/gstreamer/GStreamerReader.cpp
@@ -221,16 +221,25 @@ void GStreamerReader::PlayBinSourceSetup
}
void GStreamerReader::PlayBinSourceSetup(GstAppSrc* aSource)
{
mSource = GST_APP_SRC(aSource);
gst_app_src_set_callbacks(mSource, &mSrcCallbacks, (gpointer) this, nullptr);
MediaResource* resource = mDecoder->GetResource();
+ /* do a short read to trigger a network request so that GetLength() below
+ * returns something meaningful and not -1
+ */
+ char buf[512];
+ unsigned int size = 0;
+ resource->Read(buf, sizeof(buf), &size);
+ resource->Seek(SEEK_SET, 0);
+
+ /* now we should have a length */
int64_t resourceLength = resource->GetLength();
gst_app_src_set_size(mSource, resourceLength);
if (resource->IsDataCachedToEndOfResource(0) ||
(resourceLength != -1 && resourceLength <= SHORT_FILE_SIZE)) {
/* let the demuxer work in pull mode for local files (or very short files)
* so that we get optimal seeking accuracy/performance
*/
LOG(PR_LOG_DEBUG, ("configuring random access, len %lld", resourceLength));
@@ -367,37 +376,16 @@ nsresult GStreamerReader::ReadMetadata(M
if (NS_SUCCEEDED(ret))
ret = CheckSupportedFormats();
if (NS_FAILED(ret))
/* we couldn't get this to play */
return ret;
- /* FIXME: workaround for a bug in matroskademux. This seek makes matroskademux
- * parse the index */
- LOG(PR_LOG_DEBUG, ("doing matroskademux seek hack"));
- if (gst_element_seek_simple(mPlayBin, GST_FORMAT_TIME,
- GST_SEEK_FLAG_FLUSH, 0)) {
- /* after a seek we need to wait again for ASYNC_DONE */
- message = gst_bus_timed_pop_filtered(mBus, 5 * GST_SECOND,
- (GstMessageType)(GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR));
- if (message == NULL || GST_MESSAGE_TYPE(message) != GST_MESSAGE_ASYNC_DONE) {
- LOG(PR_LOG_DEBUG, ("matroskademux seek hack failed: %p", message));
- gst_element_set_state(mPlayBin, GST_STATE_NULL);
- if (message) {
- gst_message_unref(message);
- }
- return NS_ERROR_FAILURE;
- }
- LOG(PR_LOG_DEBUG, ("matroskademux seek hack completed"));
- } else {
- LOG(PR_LOG_DEBUG, ("matroskademux seek hack failed (non fatal)"));
- }
-
bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3);
if (isMP3) {
ParseMP3Headers();
}
/* report the duration */
gint64 duration;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -8802,28 +8802,24 @@ nsGlobalWindow::ShowModalDialog(const ns
aError = dialog->GetReturnValue(getter_AddRefs(retVal));
MOZ_ASSERT(!aError.Failed());
return retVal.forget();
}
JS::Value
nsGlobalWindow::ShowModalDialog(JSContext* aCx, const nsAString& aUrl,
- const Optional<JS::Handle<JS::Value> >& aArgument,
+ JS::Handle<JS::Value> aArgument,
const nsAString& aOptions,
ErrorResult& aError)
{
nsCOMPtr<nsIVariant> args;
- if (aArgument.WasPassed()) {
- aError = nsContentUtils::XPConnect()->JSToVariant(aCx,
- aArgument.Value(),
- getter_AddRefs(args));
- } else {
- args = CreateVoidVariant();
- }
+ aError = nsContentUtils::XPConnect()->JSToVariant(aCx,
+ aArgument,
+ getter_AddRefs(args));
nsCOMPtr<nsIVariant> retVal = ShowModalDialog(aUrl, args, aOptions, aError);
if (aError.Failed()) {
return JS::UndefinedValue();
}
JS::Rooted<JS::Value> result(aCx);
if (retVal) {
@@ -11425,17 +11421,19 @@ nsGlobalWindow::SetTimeout(JSContext* aC
const Sequence<JS::Value>& aArguments,
ErrorResult& aError)
{
return SetTimeoutOrInterval(aFunction, aTimeout, aArguments, false, aError);
}
int32_t
nsGlobalWindow::SetTimeout(JSContext* aCx, const nsAString& aHandler,
- int32_t aTimeout, ErrorResult& aError)
+ int32_t aTimeout,
+ const Sequence<JS::Value>& /* unused */,
+ ErrorResult& aError)
{
return SetTimeoutOrInterval(aCx, aHandler, aTimeout, false, aError);
}
static bool
IsInterval(const Optional<int32_t>& aTimeout, int32_t& aResultTimeout)
{
if (aTimeout.WasPassed()) {
@@ -11459,16 +11457,17 @@ nsGlobalWindow::SetInterval(JSContext* a
bool isInterval = IsInterval(aTimeout, timeout);
return SetTimeoutOrInterval(aFunction, timeout, aArguments, isInterval,
aError);
}
int32_t
nsGlobalWindow::SetInterval(JSContext* aCx, const nsAString& aHandler,
const Optional<int32_t>& aTimeout,
+ const Sequence<JS::Value>& /* unused */,
ErrorResult& aError)
{
int32_t timeout;
bool isInterval = IsInterval(aTimeout, timeout);
return SetTimeoutOrInterval(aCx, aHandler, timeout, isInterval, aError);
}
nsresult
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -819,34 +819,37 @@ protected:
mozilla::ErrorResult& aError);
public:
void Alert(const nsAString& aMessage, mozilla::ErrorResult& aError);
bool Confirm(const nsAString& aMessage, mozilla::ErrorResult& aError);
void Prompt(const nsAString& aMessage, const nsAString& aInitial,
nsAString& aReturn, mozilla::ErrorResult& aError);
void Print(mozilla::ErrorResult& aError);
- JS::Value ShowModalDialog(JSContext* aCx, const nsAString& aUrl, const mozilla::dom::Optional<JS::Handle<JS::Value> >& aArgument, const nsAString& aOptions, mozilla::ErrorResult& aError);
+ JS::Value ShowModalDialog(JSContext* aCx, const nsAString& aUrl, JS::Handle<JS::Value> aArgument, const nsAString& aOptions, mozilla::ErrorResult& aError);
void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const nsAString& aTargetOrigin,
const mozilla::dom::Optional<mozilla::dom::Sequence<JS::Value > >& aTransfer,
mozilla::ErrorResult& aError);
int32_t SetTimeout(JSContext* aCx, mozilla::dom::Function& aFunction,
int32_t aTimeout,
const mozilla::dom::Sequence<JS::Value>& aArguments,
mozilla::ErrorResult& aError);
int32_t SetTimeout(JSContext* aCx, const nsAString& aHandler,
- int32_t aTimeout, mozilla::ErrorResult& aError);
+ int32_t aTimeout,
+ const mozilla::dom::Sequence<JS::Value>& /* unused */,
+ mozilla::ErrorResult& aError);
void ClearTimeout(int32_t aHandle, mozilla::ErrorResult& aError);
int32_t SetInterval(JSContext* aCx, mozilla::dom::Function& aFunction,
const mozilla::dom::Optional<int32_t>& aTimeout,
const mozilla::dom::Sequence<JS::Value>& aArguments,
mozilla::ErrorResult& aError);
int32_t SetInterval(JSContext* aCx, const nsAString& aHandler,
const mozilla::dom::Optional<int32_t>& aTimeout,
+ const mozilla::dom::Sequence<JS::Value>& /* unused */,
mozilla::ErrorResult& aError);
void ClearInterval(int32_t aHandle, mozilla::ErrorResult& aError);
void Atob(const nsAString& aAsciiBase64String, nsAString& aBinaryData,
mozilla::ErrorResult& aError);
void Btoa(const nsAString& aBinaryData, nsAString& aAsciiBase64String,
mozilla::ErrorResult& aError);
nsIDOMStorage* GetSessionStorage(mozilla::ErrorResult& aError);
nsIDOMStorage* GetLocalStorage(mozilla::ErrorResult& aError);
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -31,16 +31,17 @@ support-files =
[test_messagemanager_targetchain.html]
[test_messageChannel_transferable.html]
[test_messageChannel_unshipped.html]
[test_named_frames.html]
[test_nondomexception.html]
[test_openDialogChromeOnly.html]
[test_postMessage_solidus.html]
[test_screen_orientation.html]
+[test_settimeout_extra_arguments.html]
[test_settimeout_inner.html]
[test_setting_opener.html]
[test_url.html]
[test_url_empty_port.html]
[test_urlExceptions.html]
[test_urlSearchParams.html]
[test_urlutils_stringify.html]
[test_window_constructor.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_settimeout_extra_arguments.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test for setTimeout with a string argument and more than 2 arguments</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ t1 = async_test("setTimeout with more than 2 arguments, first argument a string, should work");
+ t2 = async_test("setInterval with more than 2 arguments, first argument a string, should work");
+ setTimeout("t1.done()", 0, {});
+ var interval = setInterval("clearInterval(interval); t2.done()", 0, {});
+</script>
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -236,42 +236,24 @@ public:
template <class T1>
void Construct(const T1& t1)
{
Optional_base<JSObject*, JSObject*>::Construct(t1);
}
};
-// A specialization of Optional for JS::Value to make sure that when someone
-// calls Construct() on it we will pre-initialized the JS::Value to
-// JS::UndefinedValue() so it can be traced safely.
+// A specialization of Optional for JS::Value to make sure no one ever uses it.
template<>
-class Optional<JS::Value> : public Optional_base<JS::Value, JS::Value>
+class Optional<JS::Value>
{
-public:
- Optional() :
- Optional_base<JS::Value, JS::Value>()
- {}
+private:
+ Optional() MOZ_DELETE;
- explicit Optional(JS::Value aValue) :
- Optional_base<JS::Value, JS::Value>(aValue)
- {}
-
- // Don't allow us to have an uninitialized JS::Value
- void Construct()
- {
- Optional_base<JS::Value, JS::Value>::Construct(JS::UndefinedValue());
- }
-
- template <class T1>
- void Construct(const T1& t1)
- {
- Optional_base<JS::Value, JS::Value>::Construct(t1);
- }
+ explicit Optional(JS::Value aValue) MOZ_DELETE;
};
// A specialization of Optional for NonNull that lets us get a T& from Value()
template<typename U> class NonNull;
template<typename T>
class Optional<NonNull<T> > : public Optional_base<T, NonNull<T> >
{
public:
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1518,17 +1518,16 @@ DOMInterfaces = {
},
'Window': {
'nativeType': 'nsGlobalWindow',
# When turning on Window, remember to drop the "'register': False"
# from ChromeWindow.
'hasXPConnectImpls': True,
'register': False,
- 'implicitJSContext': [ 'setInterval', 'setTimeout' ],
'binaryNames': {
'postMessage': 'postMessageMoz',
},
},
'WindowProxy': [
{
'nativeType': 'nsIDOMWindow',
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -6,17 +6,17 @@
import operator
import os
import re
import string
import math
import itertools
-from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute
+from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute, IDLUndefinedValue
from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, Descriptor
AUTOGENERATED_WARNING_COMMENT = \
"/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
ADDPROPERTY_HOOK_NAME = '_addProperty'
FINALIZE_HOOK_NAME = '_finalize'
CONSTRUCT_HOOK_NAME = '_constructor'
LEGACYCALLER_HOOK_NAME = '_legacycaller'
@@ -3839,31 +3839,32 @@ for (uint32_t i = 0; i < length; ++i) {
declArgs = None
if (isMember == "Variadic" or isMember == "Sequence" or
isMember == "Dictionary"):
# Rooting is handled by the sequence and dictionary tracers.
declType = "JS::Value"
else:
assert not isMember
- if isOptional:
- # We have a specialization of Optional that will use a
- # Rooted for the storage here.
- declType = "JS::Handle<JS::Value>"
+ declType = "JS::Rooted<JS::Value>"
+ declArgs = "cx"
+
+ assert not isOptional
+ templateBody = "${declName} = ${val};"
+ # We may not have a default value if we're being converted for
+ # a setter, say.
+ if defaultValue:
+ if isinstance(defaultValue, IDLNullValue):
+ defaultHandling = "${declName} = JS::NullValue()"
else:
- declType = "JS::Rooted<JS::Value>"
- declArgs = "cx"
-
- templateBody = "${declName} = ${val};"
- nullHandling = "${declName} = JS::NullValue()"
-
- templateBody = handleDefaultNull(templateBody, nullHandling)
+ assert isinstance(defaultValue, IDLUndefinedValue)
+ defaultHandling = "${declName} = JS::UndefinedValue()"
+ templateBody = handleDefault(templateBody, defaultHandling)
return JSToNativeConversionInfo(templateBody,
declType=CGGeneric(declType),
- dealWithOptional=isOptional,
declArgs=declArgs)
if type.isObject():
assert not isEnforceRange and not isClamp
return handleJSObjectType(type, isMember, failureCode)
if type.isDictionary():
# There are no nullable dictionaries
@@ -4137,16 +4138,18 @@ def instantiateJSToNativeConversion(info
# Add an empty CGGeneric to get an extra newline after the argument
# conversion.
result.append(CGGeneric(""))
return result
def convertConstIDLValueToJSVal(value):
if isinstance(value, IDLNullValue):
return "JS::NullValue()"
+ if isinstance(value, IDLUndefinedValue):
+ return "JS::UndefinedValue()"
tag = value.type.tag()
if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
IDLType.Tags.uint16, IDLType.Tags.int32]:
return "INT_TO_JSVAL(%s)" % (value.value)
if tag == IDLType.Tags.uint32:
return "UINT_TO_JSVAL(%sU)" % (value.value)
if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]:
return "DOUBLE_TO_JSVAL(%s)" % numericValue(tag, value.value)
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -2526,17 +2526,34 @@ class IDLNullValue(IDLObject):
if t.isDictionary():
nullValue.type = t
return nullValue
nullValue.type = type
return nullValue
def _getDependentObjects(self):
return set()
-
+
+class IDLUndefinedValue(IDLObject):
+ def __init__(self, location):
+ IDLObject.__init__(self, location)
+ self.type = None
+ self.value = None
+
+ def coerceToType(self, type, location):
+ if not type.isAny():
+ raise WebIDLError("Cannot coerce undefined value to type %s." % type,
+ [location])
+
+ undefinedValue = IDLUndefinedValue(self.location)
+ undefinedValue.type = type
+ return undefinedValue
+
+ def _getDependentObjects(self):
+ return set()
class IDLInterfaceMember(IDLObjectWithIdentifier):
Tags = enum(
'Const',
'Attr',
'Method'
)
@@ -2904,16 +2921,32 @@ class IDLArgument(IDLObjectWithIdentifie
self.type = type
if ((self.type.isDictionary() or
self.type.isUnion() and self.type.unroll().hasDictionaryType) and
self.optional and not self.defaultValue):
# Default optional dictionaries to null, for simplicity,
# so the codegen doesn't have to special-case this.
self.defaultValue = IDLNullValue(self.location)
+ elif self.type.isAny():
+ assert (self.defaultValue is None or
+ isinstance(self.defaultValue, IDLNullValue))
+ if (self.optional and not self.variadic and
+ not self.dictionaryMember and not self.defaultValue):
+ raise WebIDLError("Arguments of type 'any' are always optional "
+ "and shouldn't have the 'optional' keyword "
+ "unless they're being given a default value "
+ "of 'null'",
+ [self.location])
+ # 'any' values are always optional.
+ self.optional = True
+ if not self.defaultValue and not self.variadic:
+ # Set the default value to undefined, for simplicity, so the
+ # codegen doesn't have to special-case this.
+ self.defaultValue = IDLUndefinedValue(self.location)
# Now do the coercing thing; this needs to happen after the
# above creation of a default value.
if self.defaultValue:
self.defaultValue = self.defaultValue.coerceToType(self.type,
self.location)
assert self.defaultValue
@@ -4283,16 +4316,20 @@ class Parser(Tokenizer):
optional = p[2]
variadic = p[4]
defaultValue = p[6]
if not optional and defaultValue:
raise WebIDLError("Mandatory arguments can't have a default value.",
[self.getLocation(p, 6)])
+ # We can't test t.isAny() here and force optional to true, since at this
+ # point t is not a fully resolved type yet (e.g. it might be a typedef).
+ # We'll handle the 'any' case in IDLArgument.complete.
+
if variadic:
if optional:
raise WebIDLError("Variadic arguments should not be marked optional.",
[self.getLocation(p, 2)])
optional = variadic
p[0] = IDLArgument(self.getLocation(p, 5), identifier, t, optional, defaultValue, variadic)
p[0].addExtendedAttributes(p[1])
--- a/dom/bindings/parser/tests/test_method.py
+++ b/dom/bindings/parser/tests/test_method.py
@@ -107,17 +107,17 @@ def WebIDLTest(parser, harness):
"getObject", [("Object", [])])
checkMethod(methods[10], "::TestMethods::setObject",
"setObject",
[("Void",
[("::TestMethods::setObject::arg1", "arg1", "Object", False, False)])])
checkMethod(methods[11], "::TestMethods::setAny",
"setAny",
[("Void",
- [("::TestMethods::setAny::arg1", "arg1", "Any", False, False)])])
+ [("::TestMethods::setAny::arg1", "arg1", "Any", True, False)])])
checkMethod(methods[12], "::TestMethods::doFloats",
"doFloats",
[("Float",
[("::TestMethods::doFloats::arg1", "arg1", "Float", False, False)])])
parser = parser.reset()
threw = False
try:
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -141,21 +141,21 @@ public:
static
already_AddRefed<TestInterface> Test(const GlobalObject&, const nsACString&,
ErrorResult&);
static
already_AddRefed<TestInterface> Test2(const GlobalObject&,
JSContext*,
const DictForConstructor&,
- JS::Value,
+ JS::Handle<JS::Value>,
JS::Handle<JSObject*>,
JS::Handle<JSObject*>,
const Sequence<Dict>&,
- const Optional<JS::Handle<JS::Value> >&,
+ JS::Handle<JS::Value>,
const Optional<JS::Handle<JSObject*> >&,
const Optional<JS::Handle<JSObject*> >&,
ErrorResult&);
// Integer types
int8_t ReadonlyByte();
int8_t WritableByte();
void SetWritableByte(int8_t);
@@ -461,17 +461,16 @@ public:
void SetTreatAsNullCallback(TestTreatAsNullCallback&);
already_AddRefed<TestTreatAsNullCallback> TreatAsNullCallback();
void SetNullableTreatAsNullCallback(TestTreatAsNullCallback*);
already_AddRefed<TestTreatAsNullCallback> GetNullableTreatAsNullCallback();
// Any types
void PassAny(JSContext*, JS::Handle<JS::Value>);
void PassVariadicAny(JSContext*, const Sequence<JS::Value>&);
- void PassOptionalAny(JSContext*, const Optional<JS::Handle<JS::Value> >&);
void PassAnyDefaultNull(JSContext*, JS::Handle<JS::Value>);
void PassSequenceOfAny(JSContext*, const Sequence<JS::Value>&);
void PassNullableSequenceOfAny(JSContext*, const Nullable<Sequence<JS::Value> >&);
void PassOptionalSequenceOfAny(JSContext*, const Optional<Sequence<JS::Value> >&);
void PassOptionalNullableSequenceOfAny(JSContext*, const Optional<Nullable<Sequence<JS::Value> > >&);
void PassOptionalSequenceOfAnyWithDefaultValue(JSContext*, const Nullable<Sequence<JS::Value> >&);
void PassSequenceOfSequenceOfAny(JSContext*, const Sequence<Sequence<JS::Value> >&);
void PassSequenceOfNullableSequenceOfAny(JSContext*, const Sequence<Nullable<Sequence<JS::Value> > >&);
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -105,17 +105,18 @@ interface OnlyForUseInConstructor {
Constructor(TestInterface? iface),
Constructor(long arg1, IndirectlyImplementedInterface iface),
Constructor(Date arg1),
// Constructor(long arg1, long arg2, (TestInterface or OnlyForUseInConstructor) arg3),
AvailableIn=CertifiedApps,
NamedConstructor=Test,
NamedConstructor=Test(DOMString str),
NamedConstructor=Test2(DictForConstructor dict, any any1, object obj1,
- object? obj2, sequence<Dict> seq, optional any any2,
+ object? obj2, sequence<Dict> seq,
+ optional any any2 = null,
optional object obj3, optional object? obj4)
]
interface TestInterface {
// Integer types
// XXXbz add tests for throwing versions of all the integer stuff
readonly attribute byte readonlyByte;
attribute byte writableByte;
void passByte(byte arg);
@@ -423,17 +424,16 @@ interface TestInterface {
void passOptionalNullableTreatAsNullCallback(optional TestTreatAsNullCallback? arg);
void passOptionalNullableTreatAsNullCallbackWithDefaultValue(optional TestTreatAsNullCallback? arg = null);
attribute TestTreatAsNullCallback treatAsNullCallback;
attribute TestTreatAsNullCallback? nullableTreatAsNullCallback;
// Any types
void passAny(any arg);
void passVariadicAny(any... arg);
- void passOptionalAny(optional any arg);
void passAnyDefaultNull(optional any arg = null);
void passSequenceOfAny(sequence<any> arg);
void passNullableSequenceOfAny(sequence<any>? arg);
void passOptionalSequenceOfAny(optional sequence<any> arg);
void passOptionalNullableSequenceOfAny(optional sequence<any>? arg);
void passOptionalSequenceOfAnyWithDefaultValue(optional sequence<any>? arg = null);
void passSequenceOfSequenceOfAny(sequence<sequence<any>> arg);
void passSequenceOfNullableSequenceOfAny(sequence<sequence<any>?> arg);
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -7,17 +7,18 @@
Constructor(DOMString str),
Constructor(unsigned long num, boolean? boolArg),
Constructor(TestInterface? iface),
Constructor(long arg1, IndirectlyImplementedInterface iface),
// Constructor(long arg1, long arg2, (TestInterface or OnlyForUseInConstructor) arg3),
NamedConstructor=Example,
NamedConstructor=Example(DOMString str),
NamedConstructor=Example2(DictForConstructor dict, any any1, object obj1,
- object? obj2, sequence<Dict> seq, optional any any2,
+ object? obj2, sequence<Dict> seq,
+ optional any any2 = null,
optional object obj3, optional object? obj4)
]
interface TestExampleInterface {
// Integer types
// XXXbz add tests for throwing versions of all the integer stuff
readonly attribute byte readonlyByte;
attribute byte writableByte;
void passByte(byte arg);
@@ -316,17 +317,16 @@ interface TestExampleInterface {
TestCallback? receiveNullableCallback();
void passNullableTreatAsNullCallback(TestTreatAsNullCallback? arg);
void passOptionalNullableTreatAsNullCallback(optional TestTreatAsNullCallback? arg);
void passOptionalNullableTreatAsNullCallbackWithDefaultValue(optional TestTreatAsNullCallback? arg = null);
// Any types
void passAny(any arg);
void passVariadicAny(any... arg);
- void passOptionalAny(optional any arg);
void passAnyDefaultNull(optional any arg = null);
void passSequenceOfAny(sequence<any> arg);
void passNullableSequenceOfAny(sequence<any>? arg);
void passOptionalSequenceOfAny(optional sequence<any> arg);
void passOptionalNullableSequenceOfAny(optional sequence<any>? arg);
void passOptionalSequenceOfAnyWithDefaultValue(optional sequence<any>? arg = null);
void passSequenceOfSequenceOfAny(sequence<sequence<any>> arg);
void passSequenceOfNullableSequenceOfAny(sequence<sequence<any>?> arg);
--- a/dom/bindings/test/TestJSImplGen.webidl
+++ b/dom/bindings/test/TestJSImplGen.webidl
@@ -18,17 +18,17 @@ enum MyTestEnum {
};
// We don't support multiple constructors (bug 869268) or named constructors
// for JS-implemented WebIDL.
[Constructor(DOMString str, unsigned long num, boolean? boolArg,
TestInterface? iface, long arg1,
DictForConstructor dict, any any1,
object obj1,
- object? obj2, sequence<Dict> seq, optional any any2,
+ object? obj2, sequence<Dict> seq, optional any any2 = null,
optional object obj3,
optional object? obj4),
JSImplementation="@mozilla.org/test-js-impl-interface;1"]
interface TestJSImplInterface {
// Integer types
// XXXbz add tests for throwing versions of all the integer stuff
readonly attribute byte readonlyByte;
attribute byte writableByte;
@@ -339,17 +339,16 @@ interface TestJSImplInterface {
// Hmm. These two don't work, I think because I need a locally modified version of TestTreatAsNullCallback.
//void passNullableTreatAsNullCallback(TestTreatAsNullCallback? arg);
//void passOptionalNullableTreatAsNullCallback(optional TestTreatAsNullCallback? arg);
void passOptionalNullableTreatAsNullCallbackWithDefaultValue(optional TestTreatAsNullCallback? arg = null);
// Any types
void passAny(any arg);
void passVariadicAny(any... arg);
- void passOptionalAny(optional any arg);
void passAnyDefaultNull(optional any arg = null);
void passSequenceOfAny(sequence<any> arg);
void passNullableSequenceOfAny(sequence<any>? arg);
void passOptionalSequenceOfAny(optional sequence<any> arg);
void passOptionalNullableSequenceOfAny(optional sequence<any>? arg);
void passOptionalSequenceOfAnyWithDefaultValue(optional sequence<any>? arg = null);
void passSequenceOfSequenceOfAny(sequence<sequence<any>> arg);
void passSequenceOfNullableSequenceOfAny(sequence<sequence<any>?> arg);
--- a/dom/events/nsDOMMessageEvent.cpp
+++ b/dom/events/nsDOMMessageEvent.cpp
@@ -125,19 +125,17 @@ nsDOMMessageEvent::Constructor(const moz
aRv = event->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
if (aRv.Failed()) {
return nullptr;
}
bool trusted = event->Init(t);
event->SetTrusted(trusted);
- if (aParam.mData.WasPassed()) {
- event->mData = aParam.mData.Value();
- }
+ event->mData = aParam.mData;
mozilla::HoldJSObjects(event.get());
if (aParam.mOrigin.WasPassed()) {
event->mOrigin = aParam.mOrigin.Value();
}
if (aParam.mLastEventId.WasPassed()) {
--- a/dom/imptests/html/dom/test_interfaces.html
+++ b/dom/imptests/html/dom/test_interfaces.html
@@ -74,17 +74,17 @@ dictionary EventInit {
boolean bubbles = false;
boolean cancelable = false;
};
[Constructor(DOMString type, optional CustomEventInit eventInitDict)]
interface CustomEvent : Event {
readonly attribute any detail;
- void initCustomEvent(DOMString type, boolean bubbles, boolean cancelable, any details);
+ void initCustomEvent(DOMString type, boolean bubbles, boolean cancelable, optional any details);
};
dictionary CustomEventInit : EventInit {
any detail = null;
};
interface EventTarget {
void addEventListener(DOMString type, EventListener? callback, optional boolean capture);
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -692,26 +692,24 @@ IDBCursor::GetValue(JSContext* aCx, Erro
mHaveCachedValue = true;
}
return mCachedValue;
}
void
IDBCursor::Continue(JSContext* aCx,
- const Optional<JS::Handle<JS::Value> >& aKey,
+ JS::Handle<JS::Value> aKey,
ErrorResult &aRv)
{
MOZ_ASSERT(NS_IsMainThread());
Key key;
- if (aKey.WasPassed()) {
- aRv = key.SetFromJSVal(aCx, aKey.Value());
- ENSURE_SUCCESS_VOID(aRv);
- }
+ aRv = key.SetFromJSVal(aCx, aKey);
+ ENSURE_SUCCESS_VOID(aRv);
if (!key.IsUnset()) {
switch (mDirection) {
case IDBCursor::NEXT:
case IDBCursor::NEXT_UNIQUE:
if (key <= mKey) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
return;
@@ -804,31 +802,27 @@ IDBCursor::Update(JSContext* aCx, JS::Ha
return nullptr;
}
if (key != objectKey) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
return nullptr;
}
- JS::Rooted<JS::Value> value(aCx, aValue);
- Optional<JS::Handle<JS::Value> > keyValue(aCx);
- request = mObjectStore->Put(aCx, value, keyValue, aRv);
+ request = mObjectStore->Put(aCx, aValue, JS::UndefinedHandleValue, aRv);
if (aRv.Failed()) {
return nullptr;
}
}
else {
JS::Rooted<JS::Value> keyVal(aCx);
aRv = objectKey.ToJSVal(aCx, &keyVal);
ENSURE_SUCCESS(aRv, nullptr);
- JS::Rooted<JS::Value> value(aCx, aValue);
- Optional<JS::Handle<JS::Value> > keyValue(aCx, keyVal);
- request = mObjectStore->Put(aCx, value, keyValue, aRv);
+ request = mObjectStore->Put(aCx, aValue, keyVal, aRv);
if (aRv.Failed()) {
return nullptr;
}
}
#ifdef IDB_PROFILER_USE_MARKS
{
uint64_t requestSerial =
--- a/dom/indexedDB/IDBCursor.h
+++ b/dom/indexedDB/IDBCursor.h
@@ -192,18 +192,17 @@ public:
already_AddRefed<IDBRequest>
Update(JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv);
void
Advance(uint32_t aCount, ErrorResult& aRv);
void
- Continue(JSContext* aCx, const Optional<JS::Handle<JS::Value> >& aKey,
- ErrorResult& aRv);
+ Continue(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv);
already_AddRefed<IDBRequest>
Delete(JSContext* aCx, ErrorResult& aRv);
JS::Value
GetValue(JSContext* aCx, ErrorResult& aRv);
protected:
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -891,86 +891,80 @@ IDBIndex::GetKey(JSContext* aCx, JS::Han
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
return nullptr;
}
return GetKeyInternal(keyRange, aRv);
}
already_AddRefed<IDBRequest>
-IDBIndex::GetAll(JSContext* aCx, const Optional<JS::Handle<JS::Value> >& aKey,
+IDBIndex::GetAll(JSContext* aCx, JS::Handle<JS::Value> aKey,
const Optional<uint32_t>& aLimit, ErrorResult& aRv)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
IDBTransaction* transaction = mObjectStore->Transaction();
if (!transaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
return nullptr;
}
nsRefPtr<IDBKeyRange> keyRange;
- if (aKey.WasPassed()) {
- aRv = IDBKeyRange::FromJSVal(aCx, aKey.Value(), getter_AddRefs(keyRange));
- ENSURE_SUCCESS(aRv, nullptr);
- }
+ aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
+ ENSURE_SUCCESS(aRv, nullptr);
uint32_t limit = UINT32_MAX;
if (aLimit.WasPassed() && aLimit.Value() > 0) {
limit = aLimit.Value();
}
return GetAllInternal(keyRange, limit, aRv);
}
already_AddRefed<IDBRequest>
IDBIndex::GetAllKeys(JSContext* aCx,
- const Optional<JS::Handle<JS::Value> >& aKey,
+ JS::Handle<JS::Value> aKey,
const Optional<uint32_t>& aLimit, ErrorResult& aRv)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
IDBTransaction* transaction = mObjectStore->Transaction();
if (!transaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
return nullptr;
}
nsRefPtr<IDBKeyRange> keyRange;
- if (aKey.WasPassed()) {
- aRv = IDBKeyRange::FromJSVal(aCx, aKey.Value(), getter_AddRefs(keyRange));
- ENSURE_SUCCESS(aRv, nullptr);
- }
+ aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
+ ENSURE_SUCCESS(aRv, nullptr);
uint32_t limit = UINT32_MAX;
if (aLimit.WasPassed() && aLimit.Value() > 0) {
limit = aLimit.Value();
}
return GetAllKeysInternal(keyRange, limit, aRv);
}
already_AddRefed<IDBRequest>
IDBIndex::OpenCursor(JSContext* aCx,
- const Optional<JS::Handle<JS::Value> >& aRange,
+ JS::Handle<JS::Value> aRange,
IDBCursorDirection aDirection, ErrorResult& aRv)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
IDBTransaction* transaction = mObjectStore->Transaction();
if (!transaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
return nullptr;
}
nsRefPtr<IDBKeyRange> keyRange;
- if (aRange.WasPassed()) {
- aRv = IDBKeyRange::FromJSVal(aCx, aRange.Value(), getter_AddRefs(keyRange));
- ENSURE_SUCCESS(aRv, nullptr);
- }
+ aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange));
+ ENSURE_SUCCESS(aRv, nullptr);
IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
nsRefPtr<IDBRequest> request = GenerateRequest(this);
if (!request) {
IDB_WARNING("Failed to generate request!");
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return nullptr;
@@ -986,53 +980,49 @@ IDBIndex::OpenCursor(JSContext* aCx,
return nullptr;
}
return request.forget();
}
already_AddRefed<IDBRequest>
IDBIndex::OpenKeyCursor(JSContext* aCx,
- const Optional<JS::Handle<JS::Value> >& aRange,
+ JS::Handle<JS::Value> aRange,
IDBCursorDirection aDirection, ErrorResult& aRv)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
IDBTransaction* transaction = mObjectStore->Transaction();
if (!transaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
return nullptr;
}
nsRefPtr<IDBKeyRange> keyRange;
- if (aRange.WasPassed()) {
- aRv = IDBKeyRange::FromJSVal(aCx, aRange.Value(), getter_AddRefs(keyRange));
- ENSURE_SUCCESS(aRv, nullptr);
- }
+ aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange));
+ ENSURE_SUCCESS(aRv, nullptr);
IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
return OpenKeyCursorInternal(keyRange, direction, aRv);
}
already_AddRefed<IDBRequest>
-IDBIndex::Count(JSContext* aCx, const Optional<JS::Handle<JS::Value> >& aKey,
+IDBIndex::Count(JSContext* aCx, JS::Handle<JS::Value> aKey,
ErrorResult& aRv)
{
IDBTransaction* transaction = mObjectStore->Transaction();
if (!transaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
return nullptr;
}
nsRefPtr<IDBKeyRange> keyRange;
- if (aKey.WasPassed()) {
- aRv = IDBKeyRange::FromJSVal(aCx, aKey.Value(), getter_AddRefs(keyRange));
- ENSURE_SUCCESS(aRv, nullptr);
- }
+ aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
+ ENSURE_SUCCESS(aRv, nullptr);
return CountInternal(keyRange, aRv);
}
void
IndexHelper::ReleaseMainThreadObjects()
{
mIndex = nullptr;
--- a/dom/indexedDB/IDBIndex.h
+++ b/dom/indexedDB/IDBIndex.h
@@ -189,46 +189,46 @@ public:
bool
Unique() const
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return mUnique;
}
already_AddRefed<IDBRequest>
- OpenCursor(JSContext* aCx, const Optional<JS::Handle<JS::Value> >& aRange,
+ OpenCursor(JSContext* aCx, JS::Handle<JS::Value> aRange,
IDBCursorDirection aDirection, ErrorResult& aRv);
already_AddRefed<IDBRequest>
- OpenKeyCursor(JSContext* aCx, const Optional<JS::Handle<JS::Value> >& aRange,
+ OpenKeyCursor(JSContext* aCx, JS::Handle<JS::Value> aRange,
IDBCursorDirection aDirection, ErrorResult& aRv);
already_AddRefed<IDBRequest>
Get(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv);
already_AddRefed<IDBRequest>
GetKey(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv);
already_AddRefed<IDBRequest>
- Count(JSContext* aCx, const Optional<JS::Handle<JS::Value> >& aKey,
+ Count(JSContext* aCx, JS::Handle<JS::Value> aKey,
ErrorResult& aRv);
void
GetStoreName(nsString& aStoreName) const
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
mObjectStore->GetName(aStoreName);
}
already_AddRefed<IDBRequest>
- GetAll(JSContext* aCx, const Optional<JS::Handle<JS::Value> >& aKey,
+ GetAll(JSContext* aCx, JS::Handle<JS::Value> aKey,
const Optional<uint32_t>& aLimit, ErrorResult& aRv);
already_AddRefed<IDBRequest>
- GetAllKeys(JSContext* aCx, const Optional<JS::Handle<JS::Value> >& aKey,
+ GetAllKeys(JSContext* aCx, JS::Handle<JS::Value> aKey,
const Optional<uint32_t>& aLimit, ErrorResult& aRv);
private:
IDBIndex();
~IDBIndex();
nsRefPtr<IDBObjectStore> mObjectStore;
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -1902,40 +1902,37 @@ IDBObjectStore::GetAddInfo(JSContext* aC
rv = GetAddInfoCallback(aCx, &data);
}
return rv;
}
already_AddRefed<IDBRequest>
IDBObjectStore::AddOrPut(JSContext* aCx, JS::Handle<JS::Value> aValue,
- const Optional<JS::Handle<JS::Value> >& aKey,
+ JS::Handle<JS::Value> aKey,
bool aOverwrite, ErrorResult& aRv)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (!mTransaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
return nullptr;
}
if (!IsWriteAllowed()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
return nullptr;
}
- JS::Rooted<JS::Value> keyval(aCx, aKey.WasPassed() ? aKey.Value()
- : JSVAL_VOID);
-
StructuredCloneWriteInfo cloneWriteInfo;
Key key;
nsTArray<IndexUpdateInfo> updateInfo;
JS::Rooted<JS::Value> value(aCx, aValue);
- aRv = GetAddInfo(aCx, value, keyval, cloneWriteInfo, key, updateInfo);
+ aRv = GetAddInfo(aCx, value, aKey, cloneWriteInfo, key, updateInfo);
if (aRv.Failed()) {
return nullptr;
}
nsRefPtr<IDBRequest> request = GenerateRequest(this);
if (!request) {
IDB_WARNING("Failed to generate request!");
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@@ -2695,31 +2692,29 @@ IDBObjectStore::Get(JSContext* aCx, JS::
return nullptr;
}
return GetInternal(keyRange, aRv);
}
already_AddRefed<IDBRequest>
IDBObjectStore::GetAll(JSContext* aCx,
- const Optional<JS::Handle<JS::Value> >& aKey,
+ JS::Handle<JS::Value> aKey,
const Optional<uint32_t>& aLimit, ErrorResult& aRv)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (!mTransaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
return nullptr;
}
nsRefPtr<IDBKeyRange> keyRange;
- if (aKey.WasPassed()) {
- aRv = IDBKeyRange::FromJSVal(aCx, aKey.Value(), getter_AddRefs(keyRange));
- ENSURE_SUCCESS(aRv, nullptr);
- }
+ aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
+ ENSURE_SUCCESS(aRv, nullptr);
uint32_t limit = UINT32_MAX;
if (aLimit.WasPassed() && aLimit.Value() != 0) {
limit = aLimit.Value();
}
return GetAllInternal(keyRange, limit, aRv);
}
@@ -2750,31 +2745,29 @@ IDBObjectStore::Delete(JSContext* aCx, J
return nullptr;
}
return DeleteInternal(keyRange, aRv);
}
already_AddRefed<IDBRequest>
IDBObjectStore::OpenCursor(JSContext* aCx,
- const Optional<JS::Handle<JS::Value> >& aRange,
+ JS::Handle<JS::Value> aRange,
IDBCursorDirection aDirection, ErrorResult& aRv)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (!mTransaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
return nullptr;
}
nsRefPtr<IDBKeyRange> keyRange;
- if (aRange.WasPassed()) {
- aRv = IDBKeyRange::FromJSVal(aCx, aRange.Value(), getter_AddRefs(keyRange));
- ENSURE_SUCCESS(aRv, nullptr);
- }
+ aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange));
+ ENSURE_SUCCESS(aRv, nullptr);
IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
size_t argDirection = static_cast<size_t>(direction);
return OpenCursorInternal(keyRange, argDirection, aRv);
}
already_AddRefed<IDBIndex>
@@ -2936,76 +2929,70 @@ IDBObjectStore::DeleteIndex(const nsAStr
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(this),
NS_ConvertUTF16toUTF8(aName).get());
}
already_AddRefed<IDBRequest>
IDBObjectStore::Count(JSContext* aCx,
- const Optional<JS::Handle<JS::Value> >& aKey,
+ JS::Handle<JS::Value> aKey,
ErrorResult& aRv)
{
if (!mTransaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
return nullptr;
}
nsRefPtr<IDBKeyRange> keyRange;
- if (aKey.WasPassed()) {
- aRv = IDBKeyRange::FromJSVal(aCx, aKey.Value(), getter_AddRefs(keyRange));
- ENSURE_SUCCESS(aRv, nullptr);
- }
+ aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
+ ENSURE_SUCCESS(aRv, nullptr);
return CountInternal(keyRange, aRv);
}
already_AddRefed<IDBRequest>
IDBObjectStore::GetAllKeys(JSContext* aCx,
- const Optional<JS::Handle<JS::Value>>& aKey,
+ JS::Handle<JS::Value> aKey,
const Optional<uint32_t>& aLimit, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
if (!mTransaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
return nullptr;
}
nsRefPtr<IDBKeyRange> keyRange;
- if (aKey.WasPassed()) {
- aRv = IDBKeyRange::FromJSVal(aCx, aKey.Value(), getter_AddRefs(keyRange));
- ENSURE_SUCCESS(aRv, nullptr);
- }
+ aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
+ ENSURE_SUCCESS(aRv, nullptr);
uint32_t limit = UINT32_MAX;
if (aLimit.WasPassed() && aLimit.Value() != 0) {
limit = aLimit.Value();
}
return GetAllKeysInternal(keyRange, limit, aRv);
}
already_AddRefed<IDBRequest>
IDBObjectStore::OpenKeyCursor(JSContext* aCx,
- const Optional<JS::Handle<JS::Value>>& aRange,
+ JS::Handle<JS::Value> aRange,
IDBCursorDirection aDirection, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
if (!mTransaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
return nullptr;
}
nsRefPtr<IDBKeyRange> keyRange;
- if (aRange.WasPassed()) {
- aRv = IDBKeyRange::FromJSVal(aCx, aRange.Value(), getter_AddRefs(keyRange));
- ENSURE_SUCCESS(aRv, nullptr);
- }
+ aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange));
+ ENSURE_SUCCESS(aRv, nullptr);
IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
return OpenKeyCursorInternal(keyRange, static_cast<size_t>(direction), aRv);
}
inline nsresult
CopyData(nsIInputStream* aInputStream, nsIOutputStream* aOutputStream)
--- a/dom/indexedDB/IDBObjectStore.h
+++ b/dom/indexedDB/IDBObjectStore.h
@@ -299,41 +299,41 @@ public:
AutoIncrement() const
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return mAutoIncrement;
}
already_AddRefed<IDBRequest>
Put(JSContext* aCx, JS::Handle<JS::Value> aValue,
- const Optional<JS::Handle<JS::Value> >& aKey, ErrorResult& aRv)
+ JS::Handle<JS::Value> aKey, ErrorResult& aRv)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return AddOrPut(aCx, aValue, aKey, true, aRv);
}
already_AddRefed<IDBRequest>
Add(JSContext* aCx, JS::Handle<JS::Value> aValue,
- const Optional<JS::Handle<JS::Value> >& aKey, ErrorResult& aRv)
+ JS::Handle<JS::Value> aKey, ErrorResult& aRv)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return AddOrPut(aCx, aValue, aKey, false, aRv);
}
already_AddRefed<IDBRequest>
Delete(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv);
already_AddRefed<IDBRequest>
Get(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv);
already_AddRefed<IDBRequest>
Clear(ErrorResult& aRv);
already_AddRefed<IDBRequest>
- OpenCursor(JSContext* aCx, const Optional<JS::Handle<JS::Value> >& aRange,
+ OpenCursor(JSContext* aCx, JS::Handle<JS::Value> aRange,
IDBCursorDirection aDirection, ErrorResult& aRv);
already_AddRefed<IDBIndex>
CreateIndex(JSContext* aCx, const nsAString& aName, const nsAString& aKeyPath,
const IDBIndexParameters& aOptionalParameters, ErrorResult& aRv);
already_AddRefed<IDBIndex>
CreateIndex(JSContext* aCx, const nsAString& aName,
@@ -342,45 +342,45 @@ public:
already_AddRefed<IDBIndex>
Index(const nsAString& aName, ErrorResult &aRv);
void
DeleteIndex(const nsAString& aIndexName, ErrorResult& aRv);
already_AddRefed<IDBRequest>
- Count(JSContext* aCx, const Optional<JS::Handle<JS::Value> >& aKey,
+ Count(JSContext* aCx, JS::Handle<JS::Value> aKey,
ErrorResult& aRv);
already_AddRefed<IDBRequest>
- GetAll(JSContext* aCx, const Optional<JS::Handle<JS::Value> >& aKey,
+ GetAll(JSContext* aCx, JS::Handle<JS::Value> aKey,
const Optional<uint32_t>& aLimit, ErrorResult& aRv);
already_AddRefed<IDBRequest>
- GetAllKeys(JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aKey,
+ GetAllKeys(JSContext* aCx, JS::Handle<JS::Value> aKey,
const Optional<uint32_t>& aLimit, ErrorResult& aRv);
already_AddRefed<IDBRequest>
- OpenKeyCursor(JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aRange,
+ OpenKeyCursor(JSContext* aCx, JS::Handle<JS::Value> aRange,
IDBCursorDirection aDirection, ErrorResult& aRv);
protected:
IDBObjectStore();
~IDBObjectStore();
nsresult GetAddInfo(JSContext* aCx,
JS::Handle<JS::Value> aValue,
JS::Handle<JS::Value> aKeyVal,
StructuredCloneWriteInfo& aCloneWriteInfo,
Key& aKey,
nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
already_AddRefed<IDBRequest>
AddOrPut(JSContext* aCx, JS::Handle<JS::Value> aValue,
- const Optional<JS::Handle<JS::Value> >& aKey, bool aOverwrite,
+ JS::Handle<JS::Value> aKey, bool aOverwrite,
ErrorResult& aRv);
already_AddRefed<IDBIndex>
CreateIndex(JSContext* aCx, const nsAString& aName, KeyPath& aKeyPath,
const IDBIndexParameters& aOptionalParameters, ErrorResult& aRv);
static void
ClearStructuredCloneBuffer(JSAutoStructuredCloneBuffer& aBuffer);
--- a/dom/ipc/TabContext.cpp
+++ b/dom/ipc/TabContext.cpp
@@ -167,17 +167,17 @@ TabContext::SetTabContextForAppFrame(moz
if (aOwnApp) {
nsresult rv = aOwnApp->GetLocalId(&ownAppId);
NS_ENSURE_SUCCESS(rv, false);
NS_ENSURE_TRUE(ownAppId != NO_APP_ID, false);
}
uint32_t containingAppId = NO_APP_ID;
if (aAppFrameOwnerApp) {
- nsresult rv = aOwnApp->GetLocalId(&containingAppId);
+ nsresult rv = aAppFrameOwnerApp->GetLocalId(&containingAppId);
NS_ENSURE_SUCCESS(rv, false);
NS_ENSURE_TRUE(containingAppId != NO_APP_ID, false);
}
mInitialized = true;
mIsBrowser = false;
mOwnAppId = ownAppId;
mContainingAppId = containingAppId;
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -495,23 +495,21 @@ Promise::Constructor(const GlobalObject&
promise->MaybeRejectInternal(cx, value);
}
return promise.forget();
}
/* static */ already_AddRefed<Promise>
Promise::Resolve(const GlobalObject& aGlobal, JSContext* aCx,
- const Optional<JS::Handle<JS::Value>>& aValue, ErrorResult& aRv)
+ JS::Handle<JS::Value> aValue, ErrorResult& aRv)
{
// If a Promise was passed, just return it.
- JS::Rooted<JS::Value> value(aCx, aValue.WasPassed() ? aValue.Value() :
- JS::UndefinedValue());
- if (value.isObject()) {
- JS::Rooted<JSObject*> valueObj(aCx, &value.toObject());
+ if (aValue.isObject()) {
+ JS::Rooted<JSObject*> valueObj(aCx, &aValue.toObject());
Promise* nextPromise;
nsresult rv = UNWRAP_OBJECT(Promise, valueObj, nextPromise);
if (NS_SUCCEEDED(rv)) {
nsRefPtr<Promise> addRefed = nextPromise;
return addRefed.forget();
}
}
@@ -520,46 +518,44 @@ Promise::Resolve(const GlobalObject& aGl
if (MOZ_LIKELY(NS_IsMainThread())) {
window = do_QueryInterface(aGlobal.GetAsSupports());
if (!window) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
}
- return Resolve(window, aCx, value, aRv);
+ return Resolve(window, aCx, aValue, aRv);
}
/* static */ already_AddRefed<Promise>
Promise::Resolve(nsPIDOMWindow* aWindow, JSContext* aCx,
JS::Handle<JS::Value> aValue, ErrorResult& aRv)
{
// aWindow may be null.
nsRefPtr<Promise> promise = new Promise(aWindow);
promise->MaybeResolveInternal(aCx, aValue);
return promise.forget();
}
/* static */ already_AddRefed<Promise>
Promise::Reject(const GlobalObject& aGlobal, JSContext* aCx,
- const Optional<JS::Handle<JS::Value>>& aValue, ErrorResult& aRv)
+ JS::Handle<JS::Value> aValue, ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> window;
if (MOZ_LIKELY(NS_IsMainThread())) {
window = do_QueryInterface(aGlobal.GetAsSupports());
if (!window) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
}
- return Reject(window, aCx,
- aValue.WasPassed() ? aValue.Value() : JS::UndefinedHandleValue,
- aRv);
+ return Reject(window, aCx, aValue, aRv);
}
/* static */ already_AddRefed<Promise>
Promise::Reject(nsPIDOMWindow* aWindow, JSContext* aCx,
JS::Handle<JS::Value> aValue, ErrorResult& aRv)
{
// aWindow may be null.
nsRefPtr<Promise> promise = new Promise(aWindow);
@@ -731,29 +727,29 @@ Promise::All(const GlobalObject& aGlobal
}
if (aIterable.Length() == 0) {
JS::Rooted<JSObject*> empty(aCx, JS_NewArrayObject(aCx, 0));
if (!empty) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
- Optional<JS::Handle<JS::Value>> optValue(aCx, JS::ObjectValue(*empty));
- return Promise::Resolve(aGlobal, aCx, optValue, aRv);
+ JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*empty));
+ return Promise::Resolve(aGlobal, aCx, value, aRv);
}
nsRefPtr<Promise> promise = new Promise(window);
nsRefPtr<CountdownHolder> holder =
new CountdownHolder(aGlobal, promise, aIterable.Length());
nsRefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(promise);
for (uint32_t i = 0; i < aIterable.Length(); ++i) {
- Optional<JS::Handle<JS::Value>> optValue(aCx, aIterable.ElementAt(i));
- nsRefPtr<Promise> nextPromise = Promise::Resolve(aGlobal, aCx, optValue, aRv);
+ JS::Rooted<JS::Value> value(aCx, aIterable.ElementAt(i));
+ nsRefPtr<Promise> nextPromise = Promise::Resolve(aGlobal, aCx, value, aRv);
MOZ_ASSERT(!aRv.Failed());
nsRefPtr<PromiseNativeHandler> resolveHandler =
new AllResolveHandler(holder, i);
nsRefPtr<PromiseCallback> resolveCb =
new NativePromiseCallback(resolveHandler, Resolved);
@@ -778,18 +774,18 @@ Promise::Race(const GlobalObject& aGloba
}
}
nsRefPtr<Promise> promise = new Promise(window);
nsRefPtr<PromiseCallback> resolveCb = new ResolvePromiseCallback(promise);
nsRefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(promise);
for (uint32_t i = 0; i < aIterable.Length(); ++i) {
- Optional<JS::Handle<JS::Value>> optValue(aCx, aIterable.ElementAt(i));
- nsRefPtr<Promise> nextPromise = Promise::Resolve(aGlobal, aCx, optValue, aRv);
+ JS::Rooted<JS::Value> value(aCx, aIterable.ElementAt(i));
+ nsRefPtr<Promise> nextPromise = Promise::Resolve(aGlobal, aCx, value, aRv);
// According to spec, Resolve can throw, but our implementation never does.
// Well it does when window isn't passed on the main thread, but that is an
// implementation detail which should never be reached since we are checking
// for window above. Remove this when subclassing is supported.
MOZ_ASSERT(!aRv.Failed());
nextPromise->AppendCallbacks(resolveCb, rejectCb);
}
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -61,25 +61,25 @@ public:
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
static already_AddRefed<Promise>
Constructor(const GlobalObject& aGlobal, PromiseInit& aInit,
ErrorResult& aRv);
static already_AddRefed<Promise>
Resolve(const GlobalObject& aGlobal, JSContext* aCx,
- const Optional<JS::Handle<JS::Value>>& aValue, ErrorResult& aRv);
+ JS::Handle<JS::Value> aValue, ErrorResult& aRv);
static already_AddRefed<Promise>
Resolve(nsPIDOMWindow* aWindow, JSContext* aCx,
JS::Handle<JS::Value> aValue, ErrorResult& aRv);
static already_AddRefed<Promise>
Reject(const GlobalObject& aGlobal, JSContext* aCx,
- const Optional<JS::Handle<JS::Value>>& aValue, ErrorResult& aRv);
+ JS::Handle<JS::Value> aValue, ErrorResult& aRv);
static already_AddRefed<Promise>
Reject(nsPIDOMWindow* aWindow, JSContext* aCx,
JS::Handle<JS::Value> aValue, ErrorResult& aRv);
already_AddRefed<Promise>
Then(AnyCallback* aResolveCallback, AnyCallback* aRejectCallback);
--- a/dom/webidl/HTMLCanvasElement.webidl
+++ b/dom/webidl/HTMLCanvasElement.webidl
@@ -21,21 +21,21 @@ interface HTMLCanvasElement : HTMLElemen
[Pure, SetterThrows]
attribute unsigned long height;
[Throws]
nsISupports? getContext(DOMString contextId, optional any contextOptions = null);
[Throws]
DOMString toDataURL(optional DOMString type = "",
- optional any encoderOptions);
+ any encoderOptions);
[Throws]
void toBlob(FileCallback _callback,
optional DOMString type = "",
- optional any encoderOptions);
+ any encoderOptions);
};
// Mozilla specific bits
partial interface HTMLCanvasElement {
[Pure, SetterThrows]
attribute boolean mozOpaque;
[Throws]
File mozGetAsFile(DOMString name, optional DOMString? type = null);
--- a/dom/webidl/IDBCursor.webidl
+++ b/dom/webidl/IDBCursor.webidl
@@ -27,17 +27,17 @@ interface IDBCursor {
[Throws]
IDBRequest update (any value);
[Throws]
void advance ([EnforceRange] unsigned long count);
[Throws]
- void continue (optional any key);
+ void continue (any key);
[Throws]
IDBRequest delete ();
};
interface IDBCursorWithValue : IDBCursor {
[Throws]
readonly attribute any value;
--- a/dom/webidl/IDBIndex.webidl
+++ b/dom/webidl/IDBIndex.webidl
@@ -18,32 +18,32 @@ interface IDBIndex {
[Throws]
readonly attribute any keyPath;
readonly attribute boolean multiEntry;
readonly attribute boolean unique;
[Throws]
- IDBRequest openCursor (optional any range, optional IDBCursorDirection direction = "next");
+ IDBRequest openCursor (any range, optional IDBCursorDirection direction = "next");
[Throws]
- IDBRequest openKeyCursor (optional any range, optional IDBCursorDirection direction = "next");
+ IDBRequest openKeyCursor (any range, optional IDBCursorDirection direction = "next");
[Throws]
IDBRequest get (any key);
[Throws]
IDBRequest getKey (any key);
[Throws]
- IDBRequest count (optional any key);
+ IDBRequest count (any key);
};
partial interface IDBIndex {
readonly attribute DOMString storeName;
[Throws]
- IDBRequest mozGetAll (optional any key, optional unsigned long limit);
+ IDBRequest mozGetAll (any key, optional unsigned long limit);
[Throws]
- IDBRequest mozGetAllKeys (optional any key, optional unsigned long limit);
+ IDBRequest mozGetAllKeys (any key, optional unsigned long limit);
};
--- a/dom/webidl/IDBObjectStore.webidl
+++ b/dom/webidl/IDBObjectStore.webidl
@@ -20,32 +20,32 @@ interface IDBObjectStore {
readonly attribute any keyPath;
[Throws]
readonly attribute DOMStringList indexNames;
readonly attribute IDBTransaction transaction;
readonly attribute boolean autoIncrement;
[Throws]
- IDBRequest put (any value, optional any key);
+ IDBRequest put (any value, any key);
[Throws]
- IDBRequest add (any value, optional any key);
+ IDBRequest add (any value, any key);
[Throws]
IDBRequest delete (any key);
[Throws]
IDBRequest get (any key);
[Throws]
IDBRequest clear ();
[Throws]
- IDBRequest openCursor (optional any range, optional IDBCursorDirection direction = "next");
+ IDBRequest openCursor (any range, optional IDBCursorDirection direction = "next");
// Bug 899972
// IDBIndex createIndex (DOMString name, (DOMString or sequence<DOMString>) keyPath, optional IDBIndexParameters optionalParameters);
[Throws]
IDBIndex createIndex (DOMString name, DOMString keyPath, optional IDBIndexParameters optionalParameters);
[Throws]
@@ -53,25 +53,25 @@ interface IDBObjectStore {
[Throws]
IDBIndex index (DOMString name);
[Throws]
void deleteIndex (DOMString indexName);
[Throws]
- IDBRequest count (optional any key);
+ IDBRequest count (any key);
};
partial interface IDBObjectStore {
// Success fires IDBTransactionEvent, result == array of values for given keys
[Throws]
- IDBRequest mozGetAll (optional any key, optional unsigned long limit);
+ IDBRequest mozGetAll (any key, optional unsigned long limit);
[Pref="dom.indexedDB.experimental", Throws]
- IDBRequest getAll (optional any key, optional unsigned long limit);
+ IDBRequest getAll (any key, optional unsigned long limit);
[Pref="dom.indexedDB.experimental", Throws]
- IDBRequest getAllKeys (optional any key, optional unsigned long limit);
+ IDBRequest getAllKeys (any key, optional unsigned long limit);
[Pref="dom.indexedDB.experimental", Throws]
- IDBRequest openKeyCursor (optional any range, optional IDBCursorDirection direction = "next");
+ IDBRequest openKeyCursor (any range, optional IDBCursorDirection direction = "next");
};
--- a/dom/webidl/Promise.webidl
+++ b/dom/webidl/Promise.webidl
@@ -21,19 +21,19 @@ interface Promise {
// TODO bug 875289 - static Promise fulfill(any value);
// Disable the static methods when the interface object is supposed to be
// disabled, just in case some code decides to walk over to .constructor from
// the proto of a promise object or someone screws up and manages to create a
// Promise object in this scope without having resolved the interface object
// first.
[NewObject, Throws]
- static Promise resolve(optional any value);
+ static Promise resolve(any value);
[NewObject, Throws]
- static Promise reject(optional any value);
+ static Promise reject(any value);
// The [TreatNonCallableAsNull] annotation is required since then() should do
// nothing instead of throwing errors when non-callable arguments are passed.
[NewObject]
Promise then([TreatNonCallableAsNull] optional AnyCallback? fulfillCallback = null,
[TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null);
[NewObject]
--- a/dom/webidl/RTCStatsReport.webidl
+++ b/dom/webidl/RTCStatsReport.webidl
@@ -141,12 +141,12 @@ dictionary RTCStatsReportInternal {
[Pref="media.peerconnection.enabled",
// TODO: Use MapClass here once it's available (Bug 928114)
// MapClass(DOMString, object)
JSImplementation="@mozilla.org/dom/rtcstatsreport;1"]
interface RTCStatsReport {
[ChromeOnly]
readonly attribute DOMString mozPcid;
- void forEach(RTCStatsReportCallback callbackFn, optional any thisArg);
+ void forEach(RTCStatsReportCallback callbackFn, any thisArg);
object get(DOMString key);
boolean has(DOMString key);
};
--- a/dom/webidl/TestInterfaceJS.webidl
+++ b/dom/webidl/TestInterfaceJS.webidl
@@ -1,17 +1,17 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
[JSImplementation="@mozilla.org/dom/test-interface-js;1",
Pref="dom.expose_test_interfaces",
- Constructor(optional any anyArg, optional object objectArg)]
+ Constructor(any anyArg, optional object objectArg)]
interface TestInterfaceJS {
readonly attribute any anyArg;
readonly attribute object objectArg;
attribute any anyAttr;
attribute object objectAttr;
any pingPongAny(any arg);
object pingPongObject(any obj);
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -69,33 +69,33 @@ typedef any Transferable;
[Throws] readonly attribute ApplicationCache applicationCache;
// user prompts
[Throws] void alert(optional DOMString message = "");
[Throws] boolean confirm(optional DOMString message = "");
[Throws] DOMString? prompt(optional DOMString message = "", optional DOMString default = "");
[Throws] void print();
//[Throws] any showModalDialog(DOMString url, optional any argument);
- [Throws] any showModalDialog(DOMString url, optional any argument, optional DOMString options = "");
+ [Throws] any showModalDialog(DOMString url, any argument, optional DOMString options = "");
[Throws, CrossOriginCallable] void postMessage(any message, DOMString targetOrigin, optional sequence<Transferable> transfer);
// also has obsolete members
};
Window implements GlobalEventHandlers;
Window implements WindowEventHandlers;
// http://www.whatwg.org/specs/web-apps/current-work/
[NoInterfaceObject]
interface WindowTimers {
[Throws] long setTimeout(Function handler, optional long timeout = 0, any... arguments);
- [Throws] long setTimeout(DOMString handler, optional long timeout = 0);
+ [Throws] long setTimeout(DOMString handler, optional long timeout = 0, any... unused);
[Throws] void clearTimeout(long handle);
[Throws] long setInterval(Function handler, optional long timeout, any... arguments);
- [Throws] long setInterval(DOMString handler, optional long timeout);
+ [Throws] long setInterval(DOMString handler, optional long timeout, any... unused);
[Throws] void clearInterval(long handle);
};
Window implements WindowTimers;
// http://www.whatwg.org/specs/web-apps/current-work/
[NoInterfaceObject]
interface WindowBase64 {
[Throws] DOMString btoa(DOMString btoa);
--- a/dom/webidl/WorkerConsole.webidl
+++ b/dom/webidl/WorkerConsole.webidl
@@ -7,22 +7,22 @@
interface WorkerConsole {
void log(any... data);
void info(any... data);
void warn(any... data);
void error(any... data);
void _exception(any... data);
void debug(any... data);
void trace();
- void dir(optional any data);
+ void dir(any data);
void group(any... data);
void groupCollapsed(any... data);
void groupEnd(any... data);
- void time(optional any time);
- void timeEnd(optional any time);
+ void time(any time);
+ void timeEnd(any time);
void profile(any... data);
void profileEnd(any... data);
void assert(boolean condition, any... data);
void ___noSuchMethod__();
};
// This dictionary is used internally to send the stack trace from the worker to
// the main thread Console API implementation.
--- a/dom/workers/Console.cpp
+++ b/dom/workers/Console.cpp
@@ -336,20 +336,20 @@ private:
const char* mMethod;
JSAutoStructuredCloneBuffer mArguments;
nsTArray<ConsoleStackData> mStackData;
nsTArray<nsString> mStrings;
};
-class TeardownRunnable : public nsRunnable
+class TeardownConsoleRunnable : public nsRunnable
{
public:
- TeardownRunnable(ConsoleProxy* aProxy)
+ TeardownConsoleRunnable(ConsoleProxy* aProxy)
: mProxy(aProxy)
{
}
NS_IMETHOD Run()
{
AssertIsOnMainThread();
@@ -387,17 +387,18 @@ WorkerConsole::WorkerConsole()
SetIsDOMBinding();
}
WorkerConsole::~WorkerConsole()
{
MOZ_COUNT_DTOR(WorkerConsole);
if (mProxy) {
- nsRefPtr<TeardownRunnable> runnable = new TeardownRunnable(mProxy);
+ nsRefPtr<TeardownConsoleRunnable> runnable =
+ new TeardownConsoleRunnable(mProxy);
mProxy = nullptr;
if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
NS_ERROR("Failed to dispatch teardown runnable!");
}
}
}
@@ -486,56 +487,54 @@ void
WorkerConsole::Trace(JSContext* aCx)
{
Sequence<JS::Value> data;
SequenceRooter<JS::Value> rooter(aCx, &data);
Method(aCx, "trace", data, DEFAULT_MAX_STACKTRACE_DEPTH);
}
void
-WorkerConsole::Dir(JSContext* aCx,
- const Optional<JS::Handle<JS::Value>>& aValue)
+WorkerConsole::Dir(JSContext* aCx, JS::Handle<JS::Value> aValue)
{
Sequence<JS::Value> data;
SequenceRooter<JS::Value> rooter(aCx, &data);
- if (aValue.WasPassed()) {
- data.AppendElement(aValue.Value());
+ if (!aValue.isUndefined()) {
+ data.AppendElement(aValue);
}
Method(aCx, "dir", data, 1);
}
METHOD(Group, "group")
METHOD(GroupCollapsed, "groupCollapsed")
METHOD(GroupEnd, "groupEnd")
void
-WorkerConsole::Time(JSContext* aCx,
- const Optional<JS::Handle<JS::Value>>& aTimer)
+WorkerConsole::Time(JSContext* aCx, JS::Handle<JS::Value> aTimer)
{
Sequence<JS::Value> data;
SequenceRooter<JS::Value> rooter(aCx, &data);
- if (aTimer.WasPassed()) {
- data.AppendElement(aTimer.Value());
+ if (!aTimer.isUndefined()) {
+ data.AppendElement(aTimer);
}
Method(aCx, "time", data, 1);
}
void
WorkerConsole::TimeEnd(JSContext* aCx,
- const Optional<JS::Handle<JS::Value>>& aTimer)
+ JS::Handle<JS::Value> aTimer)
{
Sequence<JS::Value> data;
SequenceRooter<JS::Value> rooter(aCx, &data);
- if (aTimer.WasPassed()) {
- data.AppendElement(aTimer.Value());
+ if (!aTimer.isUndefined()) {
+ data.AppendElement(aTimer);
}
Method(aCx, "timeEnd", data, 1);
}
METHOD(Profile, "profile")
METHOD(ProfileEnd, "profileEnd")
--- a/dom/workers/Console.h
+++ b/dom/workers/Console.h
@@ -65,32 +65,32 @@ public:
void
Debug(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Trace(JSContext* aCx);
void
- Dir(JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aValue);
+ Dir(JSContext* aCx, JS::Handle<JS::Value> aValue);
void
Group(JSContext* aCx, const Sequence<JS::Value>& aData);
void
GroupCollapsed(JSContext* aCx, const Sequence<JS::Value>& aData);
void
GroupEnd(JSContext* aCx, const Sequence<JS::Value>& aData);
void
- Time(JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aTimer);
+ Time(JSContext* aCx, JS::Handle<JS::Value> aTimer);
void
- TimeEnd(JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aTimer);
+ TimeEnd(JSContext* aCx, JS::Handle<JS::Value> aTimer);
void
Profile(JSContext* aCx, const Sequence<JS::Value>& aData);
void
ProfileEnd(JSContext* aCx, const Sequence<JS::Value>& aData);
void
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -838,21 +838,23 @@ CreateJSContextForWorker(WorkerPrivate*
return workerCx;
}
class WorkerJSRuntime : public mozilla::CycleCollectedJSRuntime
{
public:
// The heap size passed here doesn't matter, we will change it later in the
// call to JS_SetGCParameter inside CreateJSContextForWorker.
- WorkerJSRuntime(WorkerPrivate* aWorkerPrivate)
- : CycleCollectedJSRuntime(WORKER_DEFAULT_RUNTIME_HEAPSIZE,
- JS_NO_HELPER_THREADS),
+ WorkerJSRuntime(JSRuntime* aParentRuntime, WorkerPrivate* aWorkerPrivate)
+ : CycleCollectedJSRuntime(aParentRuntime,
+ WORKER_DEFAULT_RUNTIME_HEAPSIZE,
+ JS_NO_HELPER_THREADS),
mWorkerPrivate(aWorkerPrivate)
- { }
+ {
+ }
~WorkerJSRuntime()
{
auto rtPrivate = static_cast<WorkerThreadRuntimePrivate*>(JS_GetRuntimePrivate(Runtime()));
delete rtPrivate;
JS_SetRuntimePrivate(Runtime(), nullptr);
// The worker global should be unrooted and the shutdown cycle collection
@@ -907,16 +909,17 @@ public:
private:
WorkerPrivate* mWorkerPrivate;
};
class WorkerThreadPrimaryRunnable MOZ_FINAL : public nsRunnable
{
WorkerPrivate* mWorkerPrivate;
nsRefPtr<RuntimeService::WorkerThread> mThread;
+ JSRuntime* mParentRuntime;
class FinishedRunnable MOZ_FINAL : public nsRunnable
{
nsRefPtr<RuntimeService::WorkerThread> mThread;
public:
FinishedRunnable(already_AddRefed<RuntimeService::WorkerThread> aThread)
: mThread(aThread)
@@ -930,18 +933,19 @@ class WorkerThreadPrimaryRunnable MOZ_FI
~FinishedRunnable()
{ }
NS_DECL_NSIRUNNABLE
};
public:
WorkerThreadPrimaryRunnable(WorkerPrivate* aWorkerPrivate,
- RuntimeService::WorkerThread* aThread)
- : mWorkerPrivate(aWorkerPrivate), mThread(aThread)
+ RuntimeService::WorkerThread* aThread,
+ JSRuntime* aParentRuntime)
+ : mWorkerPrivate(aWorkerPrivate), mThread(aThread), mParentRuntime(aParentRuntime)
{
MOZ_ASSERT(aWorkerPrivate);
MOZ_ASSERT(aThread);
}
NS_DECL_ISUPPORTS_INHERITED
private:
@@ -1524,17 +1528,17 @@ RuntimeService::ScheduleWorker(JSContext
nsISupportsPriority::PRIORITY_NORMAL :
nsISupportsPriority::PRIORITY_LOW;
if (NS_FAILED(thread->SetPriority(priority))) {
NS_WARNING("Could not set the thread's priority!");
}
nsCOMPtr<nsIRunnable> runnable =
- new WorkerThreadPrimaryRunnable(aWorkerPrivate, thread);
+ new WorkerThreadPrimaryRunnable(aWorkerPrivate, thread, JS_GetParentRuntime(aCx));
if (NS_FAILED(thread->Dispatch(runnable, NS_DISPATCH_NORMAL))) {
UnregisterWorker(aCx, aWorkerPrivate);
JS_ReportError(aCx, "Could not dispatch to thread!");
return false;
}
#ifdef DEBUG
thread->SetAcceptingNonWorkerRunnables(false);
@@ -2530,17 +2534,17 @@ WorkerThreadPrimaryRunnable::Run()
mThread->SetWorker(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
{
nsCycleCollector_startup();
- WorkerJSRuntime runtime(mWorkerPrivate);
+ WorkerJSRuntime runtime(mParentRuntime, mWorkerPrivate);
JSRuntime* rt = runtime.Runtime();
JSContext* cx = CreateJSContextForWorker(mWorkerPrivate, rt);
if (!cx) {
// XXX need to fire an error at parent.
NS_ERROR("Failed to create runtime and context!");
return NS_ERROR_FAILURE;
}
--- a/dom/workers/URL.cpp
+++ b/dom/workers/URL.cpp
@@ -307,20 +307,20 @@ public:
URLProxy*
GetURLProxy()
{
return mRetval;
}
};
-class TeardownRunnable : public nsRunnable
+class TeardownURLRunnable : public nsRunnable
{
public:
- TeardownRunnable(URLProxy* aURLProxy)
+ TeardownURLRunnable(URLProxy* aURLProxy)
: mURLProxy(aURLProxy)
{
}
NS_IMETHOD Run()
{
AssertIsOnMainThread();
@@ -571,17 +571,18 @@ URL::URL(WorkerPrivate* aWorkerPrivate,
MOZ_COUNT_CTOR(workers::URL);
}
URL::~URL()
{
MOZ_COUNT_DTOR(workers::URL);
if (mURLProxy) {
- nsRefPtr<TeardownRunnable> runnable = new TeardownRunnable(mURLProxy);
+ nsRefPtr<TeardownURLRunnable> runnable =
+ new TeardownURLRunnable(mURLProxy);
mURLProxy = nullptr;
if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
NS_ERROR("Failed to dispatch teardown runnable!");
}
}
}
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -175,18 +175,20 @@ WorkerGlobalScope::SetTimeout(JSContext*
ErrorResult& aRv)
{
mWorkerPrivate->AssertIsOnWorkerThread();
return mWorkerPrivate->SetTimeout(aCx, &aHandler, EmptyString(), aTimeout,
aArguments, false, aRv);
}
int32_t
-WorkerGlobalScope::SetTimeout(const nsAString& aHandler,
+WorkerGlobalScope::SetTimeout(JSContext* /* unused */,
+ const nsAString& aHandler,
const int32_t aTimeout,
+ const Sequence<JS::Value>& /* unused */,
ErrorResult& aRv)
{
mWorkerPrivate->AssertIsOnWorkerThread();
Sequence<JS::Value> dummy;
return mWorkerPrivate->SetTimeout(GetCurrentThreadJSContext(), nullptr,
aHandler, aTimeout, dummy, false, aRv);
}
@@ -208,18 +210,20 @@ WorkerGlobalScope::SetInterval(JSContext
int32_t timeout = aTimeout.WasPassed() ? aTimeout.Value() : 0;
return mWorkerPrivate->SetTimeout(aCx, &aHandler, EmptyString(), timeout,
aArguments, !!timeout, aRv);
}
int32_t
-WorkerGlobalScope::SetInterval(const nsAString& aHandler,
+WorkerGlobalScope::SetInterval(JSContext* /* unused */,
+ const nsAString& aHandler,
const Optional<int32_t>& aTimeout,
+ const Sequence<JS::Value>& /* unused */,
ErrorResult& aRv)
{
mWorkerPrivate->AssertIsOnWorkerThread();
Sequence<JS::Value> dummy;
int32_t timeout = aTimeout.WasPassed() ? aTimeout.Value() : 0;
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -83,27 +83,29 @@ public:
void
ImportScripts(JSContext* aCx, const Sequence<nsString>& aScriptURLs,
ErrorResult& aRv);
int32_t
SetTimeout(JSContext* aCx, Function& aHandler, const int32_t aTimeout,
const Sequence<JS::Value>& aArguments, ErrorResult& aRv);
int32_t
- SetTimeout(const nsAString& aHandler, const int32_t aTimeout,
+ SetTimeout(JSContext* /* unused */, const nsAString& aHandler,
+ const int32_t aTimeout, const Sequence<JS::Value>& /* unused */,
ErrorResult& aRv);
void
ClearTimeout(int32_t aHandle, ErrorResult& aRv);
int32_t
SetInterval(JSContext* aCx, Function& aHandler,
const Optional<int32_t>& aTimeout,
const Sequence<JS::Value>& aArguments, ErrorResult& aRv);
int32_t
- SetInterval(const nsAString& aHandler, const Optional<int32_t>& aTimeout,
- ErrorResult& aRv);
+ SetInterval(JSContext* /* unused */, const nsAString& aHandler,
+ const Optional<int32_t>& aTimeout,
+ const Sequence<JS::Value>& /* unused */, ErrorResult& aRv);
void
ClearInterval(int32_t aHandle, ErrorResult& aRv);
void
Atob(const nsAString& aAtob, nsAString& aOutput, ErrorResult& aRv) const;
void
Btoa(const nsAString& aBtoa, nsAString& aOutput, ErrorResult& aRv) const;
--- a/embedding/tests/winEmbed/Makefile.in
+++ b/embedding/tests/winEmbed/Makefile.in
@@ -23,17 +23,17 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
# Contributor(s):
#
# ***** END LICENSE BLOCK *****
LIBS = \
- $(DEPTH)/profile/dirserviceprovider/standalone/$(LIB_PREFIX)profdirserviceprovidersa_s.$(LIB_SUFFIX) \
+ $(DEPTH)/profile/dirserviceprovider/src/$(LIB_PREFIX)profdirserviceprovidersa_s.$(LIB_SUFFIX) \
$(XPCOM_STANDALONE_GLUE_LDOPTS) \
$(NULL)
STL_FLAGS=
OS_LIBS += $(call EXPAND_LIBNAME,ole32 comdlg32 shell32 version)
include $(topsrcdir)/config/rules.mk
--- a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff
+++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff
@@ -9476,146 +9476,149 @@ 38891a44715,44716
38951c44776
< proprietorship/M
---
> proprietorship/MS
39039a44865
> provender/M
39564a45391
> quinoa
-40036a45864
+39873a45701,45702
+> rasterization/M
+> rasterize/SGDR
+40036a45866
> recency
-40140a45969
+40140a45971
> recurse/DGSV
-40141a45971
+40141a45973
> recuse/DGS
-40208a46039
+40208a46041
> refactor/SMDG
-40244d46074
+40244d46076
< reflexion/SM
-40659d46488
+40659d46490
< resizing
-40829c46658
+40829c46660
< reverie/M
---
> reverie/MS
-41415a47245
+41415a47247
> sabre/MS
-41914c47744
+41914c47746
< schnaps's
---
> schnaps/M
-41949c47779
+41949c47781
< schrod's
---
> schrod/SM
-41998a47829
+41998a47831
> scot-free
-42883,42885c48714
+42883,42885c48716
< shit's
< shit/S!
< shite/S!
---
> shit/MS!
-42887,42888c48716,48717
+42887,42888c48718,48719
< shithead/S!
< shitload/!
---
> shithead/MS!
> shitload/MS!
-42891c48720
+42891c48722
< shitty/RT!
---
> shitty/TR!
-42976a48806
+42976a48808
> should've
-43008c48838
+43008c48840
< showtime
---
> showtime/MS
-43328c49158
+43328c49160
< size/MGBDRS
---
> size/AMGBDRS
-43724,43726c49554
+43724,43726c49556
< smoulder's
< smouldered
< smoulders
---
> smoulder/GSMD
-44062c49890
+44062c49892
< sonofabitch
---
> sonofabitch/!
-44346a50175
+44346a50177
> spelled
-44348a50178
+44348a50180
> spelt
-44371a50202
+44371a50204
> spick/S!
-44383c50214
+44383c50216
< spik/S
---
> spik/S!
-46106a51938
+46106a51940
> syllabi
-46160c51992
+46160c51994
< synch/GMD
---
> synch/GMDS
-46167d51998
+46167d52000
< synchs
-46203,46204c52034,52035
+46203,46204c52036,52037
< sysadmin/S
< sysop/S
---
> sysadmin/MS
> sysop/MS
-46752a52584
+46752a52586
> terabit/MS
-46753a52586,52587
+46753a52588,52589
> terahertz/M
> terapixel/MS
-46817a52652
+46817a52654
> testcase/MS
-46831a52667
+46831a52669
> testsuite/MS
-46925a52762
+46925a52764
> theremin/MS
-47455c53292
+47455c53294
< toolbar
---
> toolbar/MS
-47755a53593
+47755a53595
> transfect/DSMG
-47774a53613,53614
+47774a53615,53616
> transgenderism
> transgene/MS
-47951c53791
+47951c53793
< triage/M
---
> triage/MG
-48869a54710
+48869a54712
> unlikeable
-49211c55052
+49211c55054
< vagina/M
---
> vagina/MS
-49368,49369c55209
+49368,49369c55211
< velour's
< velours's
---
> velour/MS
-49478a55319
+49478a55321
> vertices
-50148a55990
+50148a55992
> weaponize/DSG
-50260,50261d56101
+50260,50261d56103
< werwolf/M
< werwolves
-50728c56568
+50728c56570
< women
---
> women/M
-50794c56634
+50794c56636
< wop/S!
---
> wop/MS!
--- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
+++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
@@ -1,9 +1,9 @@
-57456
+57458
0/nm
0th/pt
1/n1
1st/p
1th/tc
2/nm
2nd/p
2th/tc
@@ -46019,16 +46019,18 @@ rarity/SM
rascal/SMY
rash/ZTMRSYP
rasher/M
rashness/M
rasp/GMDRS
raspberry/SM
raspy/RT
raster
+rasterization/M
+rasterize/SGDR
rat/SM
ratatouille/M
ratbag/S
ratchet/GMDS
rate/BJXMZGNDRS
rateable
rated/U
ratepayer/S
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -333,16 +333,17 @@ Factory::CreateDrawTargetForData(Backend
switch (aBackend) {
#ifdef USE_SKIA
case BackendType::SKIA:
{
RefPtr<DrawTargetSkia> newTarget;
newTarget = new DrawTargetSkia();
newTarget->Init(aData, aSize, aStride, aFormat);
retVal = newTarget;
+ break;
}
#endif
#ifdef XP_MACOSX
case BackendType::COREGRAPHICS:
{
RefPtr<DrawTargetCG> newTarget = new DrawTargetCG();
if (newTarget->Init(aBackend, aData, aSize, aStride, aFormat))
return newTarget;
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -71,30 +71,34 @@ CanvasClient2D::Update(gfx::IntSize aSiz
bufferCreated = true;
}
if (!mBuffer->Lock(OPEN_WRITE_ONLY)) {
return;
}
- RefPtr<DrawTarget> drawTarget =
- mBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget();
- if (drawTarget) {
- aLayer->UpdateTarget(drawTarget);
+ bool updated = false;
+ {
+ // Restrict drawTarget to a scope so that terminates before Unlock.
+ RefPtr<DrawTarget> drawTarget =
+ mBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget();
+ if (drawTarget) {
+ aLayer->UpdateTarget(drawTarget);
+ updated = true;
+ }
}
-
mBuffer->Unlock();
if (bufferCreated && !AddTextureClient(mBuffer)) {
mBuffer = nullptr;
return;
}
- if (drawTarget) {
+ if (updated) {
GetForwarder()->UpdatedTexture(this, mBuffer, nullptr);
GetForwarder()->UseTexture(this, mBuffer);
}
}
TemporaryRef<BufferTextureClient>
CanvasClient2D::CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags)
{
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -545,41 +545,43 @@ CompositorD3D11::DrawQuad(const gfx::Rec
scissor.bottom = aClipRect.YMost();
mContext->RSSetScissorRects(1, &scissor);
mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
mContext->VSSetShader(mAttachments->mVSQuadShader[maskType], nullptr, 0);
switch (aEffectChain.mPrimaryEffect->mType) {
case EFFECT_SOLID_COLOR: {
+ SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, SurfaceFormat::UNKNOWN);
+
Color color =
static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get())->mColor;
mPSConstants.layerColor[0] = color.r * color.a * aOpacity;
mPSConstants.layerColor[1] = color.g * color.a * aOpacity;
mPSConstants.layerColor[2] = color.b * color.a * aOpacity;
mPSConstants.layerColor[3] = color.a * aOpacity;
}
break;
case EFFECT_RGB:
case EFFECT_RENDER_TARGET:
{
TexturedEffect* texturedEffect =
static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
- SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, texturedEffect->mTexture->GetFormat());
-
mVSConstants.textureCoords = texturedEffect->mTextureCoords;
TextureSourceD3D11* source = texturedEffect->mTexture->AsSourceD3D11();
if (!source) {
NS_WARNING("Missing texture source!");
return;
}
+ SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, texturedEffect->mTexture->GetFormat());
+
RefPtr<ID3D11ShaderResourceView> view;
mDevice->CreateShaderResourceView(source->GetD3D11Texture(), nullptr, byRef(view));
ID3D11ShaderResourceView* srView = view;
mContext->PSSetShaderResources(0, 1, &srView);
if (!texturedEffect->mPremultiplied) {
mContext->OMSetBlendState(mAttachments->mNonPremulBlendState, sBlendFactor, 0xFFFFFFFF);
@@ -588,29 +590,30 @@ CompositorD3D11::DrawQuad(const gfx::Rec
SetSamplerForFilter(texturedEffect->mFilter);
}
break;
case EFFECT_YCBCR: {
EffectYCbCr* ycbcrEffect =
static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
- SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, ycbcrEffect->mTexture->GetFormat());
SetSamplerForFilter(Filter::LINEAR);
mVSConstants.textureCoords = ycbcrEffect->mTextureCoords;
const int Y = 0, Cb = 1, Cr = 2;
TextureSource* source = ycbcrEffect->mTexture;
if (!source) {
NS_WARNING("No texture to composite");
return;
}
+ SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, ycbcrEffect->mTexture->GetFormat());
+
if (!source->GetSubSource(Y) || !source->GetSubSource(Cb) || !source->GetSubSource(Cr)) {
// This can happen if we failed to upload the textures, most likely
// because of unsupported dimensions (we don't tile YCbCr textures).
return;
}
TextureSourceD3D11* sourceY = source->GetSubSource(Y)->AsSourceD3D11();
TextureSourceD3D11* sourceCb = source->GetSubSource(Cb)->AsSourceD3D11();
@@ -630,25 +633,26 @@ CompositorD3D11::DrawQuad(const gfx::Rec
break;
case EFFECT_COMPONENT_ALPHA:
{
MOZ_ASSERT(gfxPlatform::ComponentAlphaEnabled());
MOZ_ASSERT(mAttachments->mComponentBlendState);
EffectComponentAlpha* effectComponentAlpha =
static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
- SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, effectComponentAlpha->mTexture->GetFormat());
TextureSourceD3D11* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceD3D11();
TextureSourceD3D11* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceD3D11();
if (!sourceOnWhite || !sourceOnBlack) {
NS_WARNING("Missing texture source(s)!");
return;
}
+ SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, effectComponentAlpha->mOnWhite->GetFormat());
+
SetSamplerForFilter(effectComponentAlpha->mFilter);
mVSConstants.textureCoords = effectComponentAlpha->mTextureCoords;
RefPtr<ID3D11ShaderResourceView> views[2];
mDevice->CreateShaderResourceView(sourceOnBlack->GetD3D11Texture(), nullptr, byRef(views[0]));
mDevice->CreateShaderResourceView(sourceOnWhite->GetD3D11Texture(), nullptr, byRef(views[1]));
ID3D11ShaderResourceView* srViews[2] = { views[0], views[1] };
--- a/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
@@ -286,16 +286,26 @@ GrallocBufferActor::Create(const gfx::In
uint32_t format = aFormat;
uint32_t usage = aUsage;
if (format == 0 || usage == 0) {
printf_stderr("GrallocBufferActor::Create -- format and usage must be non-zero");
return actor;
}
+ // If the requested size is too big (i.e. exceeds the commonly used max GL texture size)
+ // then we risk OOMing the parent process. It's better to just deny the allocation and
+ // kill the child process, which is what the following code does.
+ // TODO: actually use GL_MAX_TEXTURE_SIZE instead of hardcoding 4096
+ if (aSize.width > 4096 || aSize.height > 4096) {
+ printf_stderr("GrallocBufferActor::Create -- requested gralloc buffer is too big. Killing child instead.");
+ delete actor;
+ return nullptr;
+ }
+
sp<GraphicBuffer> buffer(new GraphicBuffer(aSize.width, aSize.height, format, usage));
if (buffer->initCheck() != OK)
return actor;
size_t bpp = BytesPerPixelForPixelFormat(format);
actor->mAllocBytes = aSize.width * aSize.height * bpp;
GrallocReporter::sAmount += actor->mAllocBytes;
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
@@ -104,22 +104,25 @@ SharedPlanarYCbCrImage::SetData(const Pl
Data data = aData;
if (!Allocate(data)) {
NS_WARNING("SharedPlanarYCbCrImage::SetData failed to allocate");
return;
}
}
MOZ_ASSERT(mTextureClient->AsTextureClientYCbCr());
-
+ if (!mTextureClient->Lock(OPEN_WRITE_ONLY)) {
+ MOZ_ASSERT(false, "Failed to lock the texture.");
+ return;
+ }
+ TextureClientAutoUnlock unlock(mTextureClient);
if (!mTextureClient->AsTextureClientYCbCr()->UpdateYCbCr(aData)) {
MOZ_ASSERT(false, "Failed to copy YCbCr data into the TextureClient");
return;
}
-
// do not set mBuffer like in PlanarYCbCrImage because the later
// will try to manage this memory without knowing it belongs to a
// shmem.
mBufferSize = YCbCrImageDataSerializer::ComputeMinBufferSize(mData.mYSize,
mData.mCbCrSize);
mSize = mData.mPicSize;
YCbCrImageDataSerializer serializer(mTextureClient->GetBuffer());
--- a/gfx/tests/gtest/TestTextures.cpp
+++ b/gfx/tests/gtest/TestTextures.cpp
@@ -103,23 +103,23 @@ void AssertYCbCrSurfacesEqual(PlanarYCbC
void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) {
// client allocation
ASSERT_TRUE(texture->AsTextureClientSurface() != nullptr);
TextureClientSurface* client = texture->AsTextureClientSurface();
client->AllocateForSurface(ToIntSize(surface->GetSize()));
ASSERT_TRUE(texture->IsAllocated());
+ ASSERT_TRUE(texture->Lock(OPEN_READ_WRITE));
// client painting
client->UpdateSurface(surface);
nsRefPtr<gfxASurface> aSurface = client->GetAsSurface();
nsRefPtr<gfxImageSurface> clientSurface = aSurface->GetAsImageSurface();
- ASSERT_TRUE(texture->Lock(OPEN_READ_ONLY));
AssertSurfacesEqual(surface, clientSurface);
texture->Unlock();
// client serialization
SurfaceDescriptor descriptor;
ASSERT_TRUE(texture->ToSurfaceDescriptor(descriptor));
ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);
@@ -150,20 +150,19 @@ void TestTextureClientYCbCr(TextureClien
// client allocation
ASSERT_TRUE(client->AsTextureClientYCbCr() != nullptr);
TextureClientYCbCr* texture = client->AsTextureClientYCbCr();
texture->AllocateForYCbCr(ycbcrData.mYSize,
ycbcrData.mCbCrSize,
ycbcrData.mStereoMode);
ASSERT_TRUE(client->IsAllocated());
+ ASSERT_TRUE(client->Lock(OPEN_READ_WRITE));
// client painting
texture->UpdateYCbCr(ycbcrData);
-
- ASSERT_TRUE(client->Lock(OPEN_READ_ONLY));
client->Unlock();
// client serialization
SurfaceDescriptor descriptor;
ASSERT_TRUE(client->ToSurfaceDescriptor(descriptor));
ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);
@@ -171,23 +170,21 @@ void TestTextureClientYCbCr(TextureClien
RefPtr<TextureHost> textureHost = CreateBackendIndependentTextureHost(descriptor, nullptr,
client->GetFlags());
RefPtr<BufferTextureHost> host = static_cast<BufferTextureHost*>(textureHost.get());
ASSERT_TRUE(host.get() != nullptr);
ASSERT_EQ(host->GetFlags(), client->GetFlags());
- // This will work iff the compositor is not BasicCompositor
- ASSERT_EQ(host->GetFormat(), mozilla::gfx::SurfaceFormat::YUV);
-
// host read
ASSERT_TRUE(host->Lock());
- ASSERT_TRUE(host->GetFormat() == mozilla::gfx::SurfaceFormat::YUV);
+ // This will work iff the compositor is not BasicCompositor
+ ASSERT_EQ(host->GetFormat(), mozilla::gfx::SurfaceFormat::YUV);
YCbCrImageDataDeserializer yuvDeserializer(host->GetBuffer());
ASSERT_TRUE(yuvDeserializer.IsValid());
PlanarYCbCrData data;
data.mYChannel = yuvDeserializer.GetYData();
data.mCbChannel = yuvDeserializer.GetCbData();
data.mCrChannel = yuvDeserializer.GetCrData();
data.mYStride = yuvDeserializer.GetYStride();
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -14,103 +14,82 @@
#include "jsobjinlines.h"
using namespace js;
using namespace js::types;
using mozilla::ArrayLength;
bool
-js::CreateRegExpMatchResult(JSContext *cx, HandleString input_, const jschar *chars, size_t length,
- MatchPairs &matches, MutableHandleValue rval)
+js::CreateRegExpMatchResult(JSContext *cx, HandleString input, const MatchPairs &matches,
+ MutableHandleValue rval)
{
- RootedString input(cx, input_);
+ JS_ASSERT(input);
/*
* Create the (slow) result array for a match.
*
* Array contents:
* 0: matched string
* 1..pairCount-1: paren matches
* input: input string
* index: start index for the match
*/
- if (!input) {
- input = js_NewStringCopyN<CanGC>(cx, chars, length);
- if (!input)
- return false;
- }
-
- size_t numPairs = matches.length();
- JS_ASSERT(numPairs > 0);
-
- AutoValueVector elements(cx);
- if (!elements.reserve(numPairs))
- return false;
-
- /* Accumulate a Value for each pair, in a rooted vector. */
- for (size_t i = 0; i < numPairs; ++i) {
- const MatchPair &pair = matches[i];
-
- if (pair.isUndefined()) {
- JS_ASSERT(i != 0); /* Since we had a match, first pair must be present. */
- elements.infallibleAppend(UndefinedHandleValue);
- } else {
- JSLinearString *str = js_NewDependentString(cx, input, pair.start, pair.length());
- if (!str)
- return false;
- elements.infallibleAppend(StringValue(str));
- }
- }
/* Get the templateObject that defines the shape and type of the output object */
JSObject *templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
if (!templateObject)
return false;
- /* Copy the rooted vector into the array object. */
- RootedObject arr(cx, NewDenseCopiedArrayWithTemplate(cx, elements.length(), elements.begin(),
- templateObject));
+ size_t numPairs = matches.length();
+ JS_ASSERT(numPairs > 0);
+
+ RootedObject arr(cx, NewDenseAllocatedArrayWithTemplate(cx, numPairs, templateObject));
if (!arr)
return false;
+ /* Store a Value for each pair. */
+ for (size_t i = 0; i < numPairs; i++) {
+ const MatchPair &pair = matches[i];
+
+ if (pair.isUndefined()) {
+ JS_ASSERT(i != 0); /* Since we had a match, first pair must be present. */
+ arr->setDenseInitializedLength(i + 1);
+ arr->initDenseElement(i, UndefinedValue());
+ } else {
+ JSLinearString *str = js_NewDependentString(cx, input, pair.start, pair.length());
+ if (!str)
+ return false;
+ arr->setDenseInitializedLength(i + 1);
+ arr->initDenseElement(i, StringValue(str));
+ }
+ }
+
/* Set the |index| property. (TemplateObject positions it in slot 0) */
- RootedValue index(cx, Int32Value(matches[0].start));
- arr->nativeSetSlot(0, index);
+ arr->nativeSetSlot(0, Int32Value(matches[0].start));
/* Set the |input| property. (TemplateObject positions it in slot 1) */
- RootedValue inputVal(cx, StringValue(input));
- arr->nativeSetSlot(1, inputVal);
+ arr->nativeSetSlot(1, StringValue(input));
#ifdef DEBUG
RootedValue test(cx);
RootedId id(cx, NameToId(cx->names().index));
if (!baseops::GetProperty(cx, arr, id, &test))
return false;
- JS_ASSERT(test == index);
+ JS_ASSERT(test == arr->nativeGetSlot(0));
id = NameToId(cx->names().input);
if (!baseops::GetProperty(cx, arr, id, &test))
return false;
- JS_ASSERT(test == inputVal);
+ JS_ASSERT(test == arr->nativeGetSlot(1));
#endif
rval.setObject(*arr);
return true;
}
-bool
-js::CreateRegExpMatchResult(JSContext *cx, HandleString string, MatchPairs &matches,
- MutableHandleValue rval)
-{
- Rooted<JSLinearString*> input(cx, string->ensureLinear(cx));
- if (!input)
- return false;
- return CreateRegExpMatchResult(cx, input, input->chars(), input->length(), matches, rval);
-}
-
static RegExpRunStatus
ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, RegExpShared &re,
Handle<JSLinearString*> input, const jschar *chars, size_t length,
size_t *lastIndex, MatchConduit &matches)
{
RegExpRunStatus status;
/* Switch between MatchOnly and IncludeSubpatterns modes. */
@@ -128,45 +107,52 @@ ExecuteRegExpImpl(JSContext *cx, RegExpS
}
return status;
}
/* Legacy ExecuteRegExp behavior is baked into the JSAPI. */
bool
js::ExecuteRegExpLegacy(JSContext *cx, RegExpStatics *res, RegExpObject &reobj,
- Handle<JSLinearString*> input, const jschar *chars, size_t length,
+ Handle<JSLinearString*> input_, const jschar *chars, size_t length,
size_t *lastIndex, bool test, MutableHandleValue rval)
{
RegExpGuard shared(cx);
if (!reobj.getShared(cx, &shared))
return false;
ScopedMatchPairs matches(&cx->tempLifoAlloc());
MatchConduit conduit(&matches);
RegExpRunStatus status =
- ExecuteRegExpImpl(cx, res, *shared, input, chars, length, lastIndex, conduit);
+ ExecuteRegExpImpl(cx, res, *shared, input_, chars, length, lastIndex, conduit);
if (status == RegExpRunStatus_Error)
return false;
if (status == RegExpRunStatus_Success_NotFound) {
/* ExecuteRegExp() previously returned an array or null. */
rval.setNull();
return true;
}
if (test) {
/* Forbid an array, as an optimization. */
rval.setBoolean(true);
return true;
}
- return CreateRegExpMatchResult(cx, input, chars, length, matches, rval);
+ RootedString input(cx, input_);
+ if (!input) {
+ input = js_NewStringCopyN<CanGC>(cx, chars, length);
+ if (!input)
+ return false;
+ }
+
+ return CreateRegExpMatchResult(cx, input, matches, rval);
}
/* Note: returns the original if no escaping need be performed. */
static JSAtom *
EscapeNakedForwardSlashes(JSContext *cx, HandleAtom unescaped)
{
size_t oldLen = unescaped->length();
const jschar *oldChars = unescaped->chars();
--- a/js/src/builtin/RegExp.h
+++ b/js/src/builtin/RegExp.h
@@ -36,23 +36,19 @@ ExecuteRegExp(JSContext *cx, HandleObjec
*/
bool
ExecuteRegExpLegacy(JSContext *cx, RegExpStatics *res, RegExpObject &reobj,
Handle<JSLinearString*> input, const jschar *chars, size_t length,
size_t *lastIndex, bool test, MutableHandleValue rval);
/* Translation from MatchPairs to a JS array in regexp_exec()'s output format. */
bool
-CreateRegExpMatchResult(JSContext *cx, HandleString string, MatchPairs &matches,
+CreateRegExpMatchResult(JSContext *cx, HandleString input, const MatchPairs &matches,
MutableHandleValue rval);
-bool
-CreateRegExpMatchResult(JSContext *cx, HandleString input, const jschar *chars, size_t length,
- MatchPairs &matches, MutableHandleValue rval);
-
extern bool
regexp_exec_raw(JSContext *cx, HandleObject regexp, HandleString input, Value *vp);
extern bool
regexp_exec(JSContext *cx, unsigned argc, Value *vp);
bool
regexp_test_raw(JSContext *cx, HandleObject regexp, HandleString input, bool *result);
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2064,19 +2064,19 @@ Parser<SyntaxParseHandler>::finishFuncti
if (funbox->inWith)
return abortIfSyntaxParser();
size_t numFreeVariables = pc->lexdeps->count();
size_t numInnerFunctions = pc->innerFunctions.length();
RootedFunction fun(context, funbox->function());
- LazyScript *lazy = LazyScript::Create(context, fun, numFreeVariables, numInnerFunctions, versionNumber(),
- funbox->bufStart, funbox->bufEnd,
- funbox->startLine, funbox->startColumn);
+ LazyScript *lazy = LazyScript::CreateRaw(context, fun, numFreeVariables, numInnerFunctions,
+ versionNumber(), funbox->bufStart, funbox->bufEnd,
+ funbox->startLine, funbox->startColumn);
if (!lazy)
return false;
HeapPtrAtom *freeVariables = lazy->freeVariables();
size_t i = 0;
for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront())
freeVariables[i++].init(r.front().key());
JS_ASSERT(i == numFreeVariables);
--- a/js/src/gc/Barrier.cpp
+++ b/js/src/gc/Barrier.cpp
@@ -52,9 +52,15 @@ HeapSlot::preconditionForWriteBarrierPos
bool
RuntimeFromMainThreadIsHeapMajorCollecting(JS::shadow::Zone *shadowZone)
{
return shadowZone->runtimeFromMainThread()->isHeapMajorCollecting();
}
#endif // DEBUG
+bool
+StringIsPermanentAtom(JSString *str)
+{
+ return str->isPermanentAtom();
+}
+
} // namespace js
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -600,16 +600,19 @@ struct EncapsulatedPtrHasher
static HashNumber hash(Lookup obj) { return DefaultHasher<T *>::hash(obj); }
static bool match(const Key &k, Lookup l) { return k.get() == l; }
static void rekey(Key &k, const Key& newKey) { k.unsafeSet(newKey); }
};
template <class T>
struct DefaultHasher< EncapsulatedPtr<T> > : EncapsulatedPtrHasher<T> { };
+bool
+StringIsPermanentAtom(JSString *str);
+
/*
* Base class for barriered value types.
*/
class BarrieredValue : public ValueOperations<BarrieredValue>
{
protected:
Value value;
@@ -652,16 +655,18 @@ class BarrieredValue : public ValueOpera
#ifdef JSGC_INCREMENTAL
if (v.isMarkable() && shadowRuntimeFromAnyThread(v)->needsBarrier())
writeBarrierPre(ZoneOfValueFromAnyThread(v), v);
#endif
}
static void writeBarrierPre(Zone *zone, const Value &v) {
#ifdef JSGC_INCREMENTAL
+ if (v.isString() && StringIsPermanentAtom(v.toString()))
+ return;
JS::shadow::Zone *shadowZone = JS::shadow::Zone::asShadowZone(zone);
if (shadowZone->needsBarrier()) {
JS_ASSERT_IF(v.isMarkable(), shadowRuntimeFromMainThread(v)->needsBarrier());
Value tmp(v);
js::gc::MarkValueUnbarriered(shadowZone->barrierTracer(), &tmp, "write barrier");
JS_ASSERT(tmp == v);
}
#endif
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -113,28 +113,42 @@ IsThingPoisoned(T *thing)
static GCMarker *
AsGCMarker(JSTracer *trc)
{
JS_ASSERT(IS_GC_MARKING_TRACER(trc));
return static_cast<GCMarker *>(trc);
}
+template <typename T> bool ThingIsPermanentAtom(T *thing) { return false; }
+template <> bool ThingIsPermanentAtom<JSString>(JSString *str) { return str->isPermanentAtom(); }
+template <> bool ThingIsPermanentAtom<JSFlatString>(JSFlatString *str) { return str->isPermanentAtom(); }
+template <> bool ThingIsPermanentAtom<JSLinearString>(JSLinearString *str) { return str->isPermanentAtom(); }
+template <> bool ThingIsPermanentAtom<JSAtom>(JSAtom *atom) { return atom->isPermanent(); }
+template <> bool ThingIsPermanentAtom<PropertyName>(PropertyName *name) { return name->isPermanent(); }
+
template<typename T>
static inline void
CheckMarkedThing(JSTracer *trc, T *thing)
{
#ifdef DEBUG
JS_ASSERT(trc);
JS_ASSERT(thing);
/* This function uses data that's not available in the nursery. */
if (IsInsideNursery(trc->runtime, thing))
return;
+ /*
+ * Permanent atoms are not associated with this runtime, but will be ignored
+ * during marking.
+ */
+ if (ThingIsPermanentAtom(thing))
+ return;
+
JS_ASSERT(thing->zone());
JS_ASSERT(thing->zone()->runtimeFromMainThread() == trc->runtime);
JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
DebugOnly<JSRuntime *> rt = trc->runtime;
JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc) && rt->gcManipulatingDeadZones,
!thing->zone()->scheduledForDestruction);
@@ -183,16 +197,24 @@ MarkInternal(JSTracer *trc, T **thingp)
* MinorCollectionTracer because of a pre-barrier. The pre-barrier is
* not needed in this case because we perform a minor collection before
* each incremental slice.
*/
if (IsInsideNursery(trc->runtime, thing))
return;
/*
+ * Don't mark permanent atoms, as they may be associated with another
+ * runtime. Note that PushMarkStack() also checks this, but the tests
+ * and maybeAlive write below should only be done on the main thread.
+ */
+ if (ThingIsPermanentAtom(thing))
+ return;
+
+ /*
* Don't mark things outside a compartment if we are in a
* per-compartment GC.
*/
if (!thing->zone()->isGCMarking())
return;
PushMarkStack(AsGCMarker(trc), thing);
thing->zone()->maybeAlive = true;
@@ -224,16 +246,40 @@ MarkUnbarriered(JSTracer *trc, T **thing
template <typename T>
static void
Mark(JSTracer *trc, BarrieredPtr<T> *thing, const char *name)
{
JS_SET_TRACING_NAME(trc, name);
MarkInternal(trc, thing->unsafeGet());
}
+void
+MarkPermanentAtom(JSTracer *trc, JSAtom *atom, const char *name)
+{
+ JS_SET_TRACING_NAME(trc, name);
+
+ JS_ASSERT(atom->isPermanent());
+
+ CheckMarkedThing(trc, atom);
+
+ if (!trc->callback) {
+ // Atoms do not refer to other GC things so don't need to go on the mark stack.
+ // Additionally, PushMarkStack will ignore permanent atoms.
+ atom->markIfUnmarked();
+ } else {
+ void *thing = atom;
+ trc->callback(trc, &thing, JSTRACE_STRING);
+ JS_ASSERT(thing == atom);
+ JS_UNSET_TRACING_LOCATION(trc);
+ }
+
+ trc->debugPrinter = nullptr;
+ trc->debugPrintArg = nullptr;
+}
+
} /* namespace gc */
} /* namespace js */
template <typename T>
static void
MarkRoot(JSTracer *trc, T **thingp, const char *name)
{
JS_ROOT_MARKING_ASSERT(trc);
@@ -288,16 +334,23 @@ IsMarked(T **thingp)
template <typename T>
static bool
IsAboutToBeFinalized(T **thingp)
{
JS_ASSERT(thingp);
JS_ASSERT(*thingp);
+ /* Permanent atoms are never finalized by non-owning runtimes. */
+ if (ThingIsPermanentAtom(*thingp) &&
+ !TlsPerThreadData.get()->associatedWith((*thingp)->runtimeFromAnyThread()))
+ {
+ return false;
+ }
+
#ifdef JSGC_GENERATIONAL
Nursery &nursery = (*thingp)->runtimeFromMainThread()->gcNursery;
if (nursery.isInside(*thingp))
return !nursery.getForwardedPointer(thingp);
#endif
if (!(*thingp)->tenuredZone()->isGCSweeping())
return false;
@@ -935,16 +988,18 @@ ScanLinearString(GCMarker *gcmarker, JSL
/*
* Add extra asserts to confirm the static type to detect incorrect string
* mutations.
*/
JS_ASSERT(str->JSString::isLinear());
while (str->hasBase()) {
str = str->base();
JS_ASSERT(str->JSString::isLinear());
+ if (str->isPermanentAtom())
+ break;
JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, str);
if (!str->markIfUnmarked())
break;
}
}
/*
* The function tries to scan the whole rope tree using the marking stack as
@@ -963,25 +1018,25 @@ ScanRope(GCMarker *gcmarker, JSRope *rop
for (;;) {
JS_DIAGNOSTICS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING);
JS_DIAGNOSTICS_ASSERT(rope->JSString::isRope());
JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, rope);
JS_ASSERT(rope->isMarked());
JSRope *next = nullptr;
JSString *right = rope->rightChild();
- if (right->markIfUnmarked()) {
+ if (!right->isPermanentAtom() && right->markIfUnmarked()) {
if (right->isLinear())
ScanLinearString(gcmarker, &right->asLinear());
else
next = &right->asRope();
}
JSString *left = rope->leftChild();
- if (left->markIfUnmarked()) {
+ if (!left->isPermanentAtom() && left->markIfUnmarked()) {
if (left->isLinear()) {
ScanLinearString(gcmarker, &left->asLinear());
} else {
/*
* When both children are ropes, set aside the right one to
* scan it later.
*/
if (next && !gcmarker->stack.push(reinterpret_cast<uintptr_t>(next)))
@@ -1008,16 +1063,20 @@ ScanString(GCMarker *gcmarker, JSString
ScanLinearString(gcmarker, &str->asLinear());
else
ScanRope(gcmarker, &str->asRope());
}
static inline void
PushMarkStack(GCMarker *gcmarker, JSString *str)
{
+ // Permanent atoms might not be associated with this runtime.
+ if (str->isPermanentAtom())
+ return;
+
JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, str);
/*
* As string can only refer to other strings we fully scan its GC graph
* using the explicit stack when navigating the rope tree to avoid
* dealing with strings on the stack in drainMarkStack.
*/
if (str->markIfUnmarked())
@@ -1393,20 +1452,22 @@ GCMarker::processMarkStackTop(SliceBudge
return;
scan_value_array:
JS_ASSERT(vp <= end);
while (vp != end) {
const Value &v = *vp++;
if (v.isString()) {
JSString *str = v.toString();
- JS_COMPARTMENT_ASSERT_STR(runtime, str);
- JS_ASSERT(runtime->isAtomsZone(str->zone()) || str->zone() == obj->zone());
- if (str->markIfUnmarked())
- ScanString(this, str);
+ if (!str->isPermanentAtom()) {
+ JS_COMPARTMENT_ASSERT_STR(runtime, str);
+ JS_ASSERT(runtime->isAtomsZone(str->zone()) || str->zone() == obj->zone());
+ if (str->markIfUnmarked())
+ ScanString(this, str);
+ }
} else if (v.isObject()) {
JSObject *obj2 = &v.toObject();
JS_COMPARTMENT_ASSERT(runtime, obj2);
JS_ASSERT(obj->compartment() == obj2->compartment());
if (obj2->markIfUnmarked(getMarkColor())) {
pushValueArray(obj, vp, end);
obj = obj2;
goto scan_obj;
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -109,16 +109,19 @@ DeclMarker(String, JSAtom)
DeclMarker(String, JSString)
DeclMarker(String, JSFlatString)
DeclMarker(String, JSLinearString)
DeclMarker(String, PropertyName)
DeclMarker(TypeObject, types::TypeObject)
#undef DeclMarker
+void
+MarkPermanentAtom(JSTracer *trc, JSAtom *atom, const char *name);
+
/* Return true if the pointer is nullptr, or if it is a tagged pointer to
* nullptr.
*/
MOZ_ALWAYS_INLINE bool
IsNullTaggedPointer(void *p)
{
return uintptr_t(p) < 32;
}
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -731,18 +731,18 @@ js::gc::MarkRuntime(JSTracer *trc, bool
if (rt->scriptAndCountsVector) {
ScriptAndCountsVector &vec = *rt->scriptAndCountsVector;
for (size_t i = 0; i < vec.length(); i++)
MarkScriptRoot(trc, &vec[i].script, "scriptAndCountsVector");
}
if (!rt->isBeingDestroyed() && !trc->runtime->isHeapMinorCollecting()) {
if (!IS_GC_MARKING_TRACER(trc) || rt->atomsCompartment()->zone()->isCollecting()) {
+ MarkPermanentAtoms(trc);
MarkAtoms(trc);
- rt->staticStrings.trace(trc);
#ifdef JS_ION
jit::JitRuntime::Mark(trc);
#endif
}
}
for (ContextIter acx(rt); !acx.done(); acx.next())
acx->mark(trc);
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -577,16 +577,20 @@ CheckEdge(JSTracer *jstrc, void **thingp
}
static void
AssertMarkedOrAllocated(const EdgeValue &edge)
{
if (!edge.thing || IsMarkedOrAllocated(static_cast<Cell *>(edge.thing)))
return;
+ // Permanent atoms aren't marked during graph traversal.
+ if (edge.kind == JSTRACE_STRING && static_cast<JSString *>(edge.thing)->isPermanentAtom())
+ return;
+
char msgbuf[1024];
const char *label = edge.label ? edge.label : "<unknown>";
JS_snprintf(msgbuf, sizeof(msgbuf), "[barrier verifier] Unmarked edge: %s", label);
MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
MOZ_CRASH();
}
--- a/js/src/jit-test/tests/basic/cross-context-stack-1.js
+++ b/js/src/jit-test/tests/basic/cross-context-stack-1.js
@@ -2,16 +2,16 @@
function g() {
evaluate("function h() {\nstack = Error().stack;\n };\n h();", {newContext: true});
}
function f() {
g();
}
f();
assertEq(stack,
- "h@@evaluate:2\n" +
- "@@evaluate:4\n");
+ "h@@evaluate:2:1\n" +
+ "@@evaluate:4:2\n");
function k() {
evaluate("stack = Error().stack", {newContext: true});
}
k();
-assertEq(stack, "@@evaluate:1\n");
+assertEq(stack, "@@evaluate:1:1\n");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/evaluate-worker.js
@@ -0,0 +1,19 @@
+// |jit-test| slow
+
+gcslice(10);
+evalInWorker("print('helo world');");
+for (i = 0; i < 100000; i++) {}
+
+evalInWorker("\
+ for (var i = 0; i < 10; i++) { \
+ var o = {}; \
+ for (var j = 0; j < 100; j++) \
+ o['a' + j] = j; \
+ JSON.stringify(o); \
+ o = null; \
+ gc(); \
+}");
+for (var i = 0; i < 10; i++) {
+ gc();
+ for (var j = 0; j < 100000; j++) {}
+}
--- a/js/src/jit-test/tests/basic/offThreadCompileScript-02.js
+++ b/js/src/jit-test/tests/basic/offThreadCompileScript-02.js
@@ -1,16 +1,16 @@
// Test offThreadCompileScript option handling.
offThreadCompileScript('Error()');
-assertEq(!!runOffThreadScript().stack.match(/^@<string>:1\n/), true);
+assertEq(!!runOffThreadScript().stack.match(/^@<string>:1:1\n/), true);
offThreadCompileScript('Error()',
{ fileName: "candelabra", lineNumber: 6502 });
-assertEq(!!runOffThreadScript().stack.match(/^@candelabra:6502\n/), true);
+assertEq(!!runOffThreadScript().stack.match(/^@candelabra:6502:1\n/), true);
var element = {};
offThreadCompileScript('Error()', { element: element }); // shouldn't crash
runOffThreadScript();
var elementAttributeName = "molybdenum";
elementAttributeName += elementAttributeName + elementAttributeName + elementAttributeName;
offThreadCompileScript('Error()', { elementAttributeName: elementAttributeName }); // shouldn't crash
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -5679,16 +5679,18 @@ CheckFunctionsParallel(ModuleCompiler &m
// pref, etc) or another thread is currently compiling asm.js in parallel,
// fall back to sequential compilation. (We could lift the latter
// constraint by hoisting asmJS* state out of WorkerThreadState so multiple
// concurrent asm.js parallel compilations don't race.)
ParallelCompilationGuard g;
if (!ParallelCompilationEnabled(m.cx()) || !g.claim())
return CheckFunctionsSequential(m);
+ IonSpew(IonSpew_Logs, "Can't log asm.js script. (Compiled on background thread.)");
+
// Saturate all worker threads plus the main thread.
size_t numParallelJobs = WorkerThreadState().threadCount + 1;
// Allocate scoped AsmJSParallelTask objects. Each contains a unique
// LifoAlloc that provides all necessary memory for compilation.
js::Vector<AsmJSParallelTask, 0> tasks(m.cx());
if (!tasks.initCapacity(numParallelJobs))
return false;
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -4435,17 +4435,17 @@ ICGetElem_String::Compiler::generateStub
masm.loadPtr(charsAddr, scratchReg);
masm.load16ZeroExtend(BaseIndex(scratchReg, key, TimesTwo, 0), scratchReg);
// Check if char code >= UNIT_STATIC_LIMIT.
masm.branch32(Assembler::AboveOrEqual, scratchReg, Imm32(StaticStrings::UNIT_STATIC_LIMIT),
&failure);
// Load static string.
- masm.movePtr(ImmPtr(&cx->runtime()->staticStrings.unitStaticTable), str);
+ masm.movePtr(ImmPtr(&cx->staticStrings().unitStaticTable), str);
masm.loadPtr(BaseIndex(str, scratchReg, ScalePointer), str);
// Return.
masm.tagValue(JSVAL_TYPE_STRING, str, R0);
EmitReturnFromIC(masm);
// Failure case - jump to next stub
masm.bind(&failure);
@@ -9382,17 +9382,17 @@ ICInstanceOf_Fallback::Compiler::generat
//
static bool
DoTypeOfFallback(JSContext *cx, BaselineFrame *frame, ICTypeOf_Fallback *stub, HandleValue val,
MutableHandleValue res)
{
FallbackICSpew(cx, stub, "TypeOf");
JSType type = js::TypeOfValue(val);
- RootedString string(cx, TypeName(type, cx->runtime()->atomState));
+ RootedString string(cx, TypeName(type, cx->names()));
res.setString(string);
JS_ASSERT(type != JSTYPE_NULL);
if (type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION) {
// Create a new TypeOf stub.
IonSpew(IonSpew_BaselineIC, " Generating TypeOf stub for JSType (%d)", (int) type);
ICTypeOf_Typed::Compiler compiler(cx, type, string);
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -107,23 +107,23 @@ bool
CompileRuntime::hadOutOfMemory()
{
return runtime()->hadOutOfMemory;
}
const JSAtomState &
CompileRuntime::names()
{
- return runtime()->atomState;
+ return *runtime()->commonNames;
}
const StaticStrings &
CompileRuntime::staticStrings()
{
- return runtime()->staticStrings;
+ return *runtime()->staticStrings;
}
const Value &
CompileRuntime::NaNValue()
{
return runtime()->NaNValue;
}
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -454,17 +454,17 @@ CharCodeAt(JSContext *cx, HandleString s
}
JSFlatString *
StringFromCharCode(JSContext *cx, int32_t code)
{
jschar c = jschar(code);
if (StaticStrings::hasUnit(c))
- return cx->runtime()->staticStrings.getUnit(c);
+ return cx->staticStrings().getUnit(c);
return js_NewStringCopyN<CanGC>(cx, &c, 1);
}
bool
SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
bool strict, jsbytecode *pc)
{
@@ -1035,16 +1035,22 @@ AssertValidObjectPtr(JSContext *cx, JSOb
JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
JS_ASSERT(obj->tenuredZone() == cx->zone());
}
}
void
AssertValidStringPtr(JSContext *cx, JSString *str)
{
+ // We can't closely inspect strings from another runtime.
+ if (str->runtimeFromAnyThread() != cx->runtime()) {
+ JS_ASSERT(str->isPermanentAtom());
+ return;
+ }
+
if (str->isAtom())
JS_ASSERT(cx->runtime()->isAtomsZone(str->tenuredZone()));
else
JS_ASSERT(str->tenuredZone() == cx->zone());
JS_ASSERT(str->runtimeFromMainThread() == cx->runtime());
JS_ASSERT(str->isAligned());
JS_ASSERT(str->length() <= JSString::MAX_LENGTH);
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -783,37 +783,44 @@ CodeGeneratorX86Shared::visitReturnZero(
masm.mov(ImmWord(0), ool->reg());
masm.jmp(ool->rejoin());
return true;
}
bool
CodeGeneratorX86Shared::visitUDivOrMod(LUDivOrMod *ins)
{
- JS_ASSERT(ToRegister(ins->lhs()) == eax);
+ Register lhs = ToRegister(ins->lhs());
Register rhs = ToRegister(ins->rhs());
Register output = ToRegister(ins->output());
+ JS_ASSERT_IF(lhs != rhs, rhs != eax);
+ JS_ASSERT(rhs != edx);
JS_ASSERT_IF(output == eax, ToRegister(ins->remainder()) == edx);
ReturnZero *ool = nullptr;
+ // Put the lhs in eax.
+ if (lhs != eax)
+ masm.mov(lhs, eax);
+
// Prevent divide by zero.
if (ins->canBeDivideByZero()) {
masm.testl(rhs, rhs);
if (ins->mir()->isTruncated()) {
if (!ool)
ool = new(alloc()) ReturnZero(output);
masm.j(Assembler::Zero, ool->entry());
} else {
if (!bailoutIf(Assembler::Zero, ins->snapshot()))
return false;
}
}
+ // Zero extend the lhs into edx to make (edx:eax), since udiv is 64-bit.
masm.mov(ImmWord(0), edx);
masm.udiv(rhs);
// Unsigned div or mod can return a value that's not a signed int32.
// If our users aren't expecting that, bail.
if (!ins->mir()->isTruncated()) {
masm.testl(output, output);
if (!bailoutIf(Assembler::Signed, ins->snapshot()))
@@ -888,54 +895,38 @@ CodeGeneratorX86Shared::visitDivPowTwoI(
// Do the shift.
masm.sarl(Imm32(shift), lhs);
}
return true;
}
bool
-CodeGeneratorX86Shared::visitDivSelfI(LDivSelfI *ins)
-{
- Register op = ToRegister(ins->op());
- Register output = ToRegister(ins->output());
- MDiv *mir = ins->mir();
-
- // If we can't divide by zero, lowering should have just used a constant one.
- JS_ASSERT(mir->canBeDivideByZero());
-
- masm.testl(op, op);
- if (mir->isTruncated()) {
- masm.emitSet(Assembler::NonZero, output);
- } else {
- if (!bailoutIf(Assembler::Zero, ins->snapshot()))
- return false;
- masm.mov(ImmWord(1), output);
- }
-
- return true;
-}
-
-bool
CodeGeneratorX86Shared::visitDivI(LDivI *ins)
{
Register remainder = ToRegister(ins->remainder());
Register lhs = ToRegister(ins->lhs());
Register rhs = ToRegister(ins->rhs());
Register output = ToRegister(ins->output());
MDiv *mir = ins->mir();
+ JS_ASSERT_IF(lhs != rhs, rhs != eax);
+ JS_ASSERT(rhs != edx);
JS_ASSERT(remainder == edx);
- JS_ASSERT(lhs == eax);
JS_ASSERT(output == eax);
Label done;
ReturnZero *ool = nullptr;
+ // Put the lhs in eax, for either the negative overflow case or the regular
+ // divide case.
+ if (lhs != eax)
+ masm.mov(lhs, eax);
+
// Handle divide by zero.
if (mir->canBeDivideByZero()) {
masm.testl(rhs, rhs);
if (mir->isTruncated()) {
// Truncated division by zero is zero (Infinity|0 == 0)
if (!ool)
ool = new(alloc()) ReturnZero(output);
masm.j(Assembler::Zero, ool->entry());
@@ -970,17 +961,19 @@ CodeGeneratorX86Shared::visitDivI(LDivI
masm.testl(lhs, lhs);
masm.j(Assembler::NonZero, &nonzero);
masm.cmpl(rhs, Imm32(0));
if (!bailoutIf(Assembler::LessThan, ins->snapshot()))
return false;
masm.bind(&nonzero);
}
- // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit.
+ // Sign extend the lhs into edx to make (edx:eax), since idiv is 64-bit.
+ if (lhs != eax)
+ masm.mov(lhs, eax);
masm.cdq();
masm.idiv(rhs);
if (!mir->isTruncated()) {
// If the remainder is > 0, bailout since this must be a double.
masm.testl(remainder, remainder);
if (!bailoutIf(Assembler::NonZero, ins->snapshot()))
return false;
@@ -993,49 +986,16 @@ CodeGeneratorX86Shared::visitDivI(LDivI
return false;
masm.bind(ool->rejoin());
}
return true;
}
bool
-CodeGeneratorX86Shared::visitModSelfI(LModSelfI *ins)
-{
- Register op = ToRegister(ins->op());
- Register output = ToRegister(ins->output());
- MMod *mir = ins->mir();
-
- // If we're not fallible, lowering should have just used a constant zero.
- JS_ASSERT(mir->fallible());
- JS_ASSERT(mir->canBeDivideByZero() || (!mir->isUnsigned() && mir->canBeNegativeDividend()));
-
- masm.testl(op, op);
-
- // For a negative operand, we need to return negative zero. We can't
- // represent that as an int32, so bail if that happens.
- if (!mir->isUnsigned() && mir->canBeNegativeDividend()) {
- if (!bailoutIf(Assembler::Signed, ins->snapshot()))
- return false;
- }
-
- // For a zero operand, we need to return NaN. We can't
- // represent that as an int32, so bail if that happens.
- if (mir->canBeDivideByZero()) {
- if (!bailoutIf(Assembler::Zero, ins->snapshot()))
- return false;
- }
-
- // For any other value, return 0.
- masm.mov(ImmWord(0), output);
-
- return true;
-}
-
-bool
CodeGeneratorX86Shared::visitModPowTwoI(LModPowTwoI *ins)
{
Register lhs = ToRegister(ins->getOperand(0));
int32_t shift = ins->shift();
Label negative;
if (ins->mir()->canBeNegativeDividend()) {
@@ -1109,24 +1069,29 @@ CodeGeneratorX86Shared::visitModOverflow
bool
CodeGeneratorX86Shared::visitModI(LModI *ins)
{
Register remainder = ToRegister(ins->remainder());
Register lhs = ToRegister(ins->lhs());
Register rhs = ToRegister(ins->rhs());
// Required to use idiv.
- JS_ASSERT(lhs == eax);
+ JS_ASSERT_IF(lhs != rhs, rhs != eax);
+ JS_ASSERT(rhs != edx);
JS_ASSERT(remainder == edx);
JS_ASSERT(ToRegister(ins->getTemp(0)) == eax);
Label done;
ReturnZero *ool = nullptr;
ModOverflowCheck *overflow = nullptr;
+ // Set up eax in preparation for doing a div.
+ if (lhs != eax)
+ masm.mov(lhs, eax);
+
// Prevent divide by zero.
if (ins->mir()->canBeDivideByZero()) {
masm.testl(rhs, rhs);
if (ins->mir()->isTruncated()) {
if (!ool)
ool = new(alloc()) ReturnZero(edx);
masm.j(Assembler::Zero, ool->entry());
} else {
--- a/js/src/jit/shared/CodeGenerator-x86-shared.h
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.h
@@ -86,20 +86,18 @@ class CodeGeneratorX86Shared : public Co
virtual bool visitSqrtD(LSqrtD *ins);
virtual bool visitSqrtF(LSqrtF *ins);
virtual bool visitPowHalfD(LPowHalfD *ins);
virtual bool visitAddI(LAddI *ins);
virtual bool visitSubI(LSubI *ins);
virtual bool visitMulI(LMulI *ins);
virtual bool visitDivI(LDivI *ins);
virtual bool visitDivPowTwoI(LDivPowTwoI *ins);
- virtual bool visitDivSelfI(LDivSelfI *ins);
virtual bool visitModI(LModI *ins);
virtual bool visitModPowTwoI(LModPowTwoI *ins);
- virtual bool visitModSelfI(LModSelfI *ins);
virtual bool visitBitNotI(LBitNotI *ins);
virtual bool visitBitOpI(LBitOpI *ins);
virtual bool visitShiftI(LShiftI *ins);
virtual bool visitUrshD(LUrshD *ins);
virtual bool visitTestIAndBranch(LTestIAndBranch *test);
virtual bool visitTestDAndBranch(LTestDAndBranch *test);
virtual bool visitTestFAndBranch(LTestFAndBranch *test);
virtual bool visitCompare(LCompare *comp);
--- a/js/src/jit/shared/LIR-x86-shared.h
+++ b/js/src/jit/shared/LIR-x86-shared.h
@@ -67,35 +67,16 @@ class LDivPowTwoI : public LBinaryMath<0
int32_t shift() const {
return shift_;
}
MDiv *mir() const {
return mir_->toDiv();
}
};
-// Division of a number by itself. Returns 1 unless the number is zero.
-class LDivSelfI : public LInstructionHelper<1, 1, 0>
-{
- public:
- LIR_HEADER(DivSelfI)
-
- LDivSelfI(const LAllocation &op) {
- setOperand(0, op);
- }
-
- const LAllocation *op() {
- return getOperand(0);
- }
-
- MDiv *mir() const {
- return mir_->toDiv();
- }
-};
-
class LModI : public LBinaryMath<1>
{
public:
LIR_HEADER(ModI)
LModI(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp) {
setOperand(0, lhs);
setOperand(1, rhs);
@@ -109,35 +90,16 @@ class LModI : public LBinaryMath<1>
const LDefinition *remainder() {
return getDef(0);
}
MMod *mir() const {
return mir_->toMod();
}
};
-// Modulo of a number by itself. Returns 0 unless the number is zero.
-class LModSelfI : public LInstructionHelper<1, 1, 0>
-{
- public:
- LIR_HEADER(ModSelfI)
-
- LModSelfI(const LAllocation &op) {
- setOperand(0, op);
- }
-
- const LAllocation *op() {
- return getOperand(0);
- }
-
- MMod *mir() const {
- return mir_->toMod();
- }
-};
-
// This class performs a simple x86 'div', yielding either a quotient or remainder depending on
// whether this instruction is defined to output eax (quotient) or edx (remainder).
class LUDivOrMod : public LBinaryMath<1>
{
public:
LIR_HEADER(UDivOrMod);
LUDivOrMod(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp) {
--- a/js/src/jit/shared/Lowering-x86-shared.cpp
+++ b/js/src/jit/shared/Lowering-x86-shared.cpp
@@ -155,34 +155,18 @@ LIRGeneratorX86Shared::lowerDivI(MDiv *d
lir = new(alloc()) LDivPowTwoI(lhs, useRegister(div->lhs()), shift);
}
if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
return false;
return defineReuseInput(lir, div, 0);
}
}
- // Optimize x/x. This is quaint, but it also protects the LDivI code below.
- // Since LDivI requires lhs to be in %eax, and since the register allocator
- // can't put a virtual register in two physical registers at the same time,
- // this puts rhs in %eax too, and since rhs isn't marked usedAtStart, it
- // would conflict with the %eax output register. (rhs could be marked
- // usedAtStart but for the fact that LDivI clobbers %edx early and rhs could
- // happen to be in %edx).
- if (div->lhs() == div->rhs()) {
- if (!div->canBeDivideByZero())
- return define(new(alloc()) LInteger(1), div);
-
- LDivSelfI *lir = new(alloc()) LDivSelfI(useRegisterAtStart(div->lhs()));
- if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
- return false;
- return define(lir, div);
- }
-
- LDivI *lir = new(alloc()) LDivI(useFixed(div->lhs(), eax), useRegister(div->rhs()), tempFixed(edx));
+ LDivI *lir = new(alloc()) LDivI(useRegister(div->lhs()), useRegister(div->rhs()),
+ tempFixed(edx));
if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
return false;
return defineFixed(lir, div, LAllocation(AnyRegister(eax)));
}
bool
LIRGeneratorX86Shared::lowerModI(MMod *mod)
{
@@ -195,30 +179,17 @@ LIRGeneratorX86Shared::lowerModI(MMod *m
if (rhs > 0 && 1 << shift == rhs) {
LModPowTwoI *lir = new(alloc()) LModPowTwoI(useRegisterAtStart(mod->lhs()), shift);
if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
return false;
return defineReuseInput(lir, mod, 0);
}
}
- // Optimize x%x. The comments in lowerDivI apply here as well, except
- // that we return 0 for all cases except when x is 0 and we're not
- // truncated.
- if (mod->rhs() == mod->lhs()) {
- if (mod->isTruncated())
- return define(new(alloc()) LInteger(0), mod);
-
- LModSelfI *lir = new(alloc()) LModSelfI(useRegisterAtStart(mod->lhs()));
- if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
- return false;
- return define(lir, mod);
- }
-
- LModI *lir = new(alloc()) LModI(useFixedAtStart(mod->lhs(), eax),
+ LModI *lir = new(alloc()) LModI(useRegister(mod->lhs()),
useRegister(mod->rhs()),
tempFixed(eax));
if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
return false;
return defineFixed(lir, mod, LAllocation(AnyRegister(edx)));
}
bool
@@ -232,50 +203,28 @@ LIRGeneratorX86Shared::visitAsmJSNeg(MAs
JS_ASSERT(ins->type() == MIRType_Double);
return defineReuseInput(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins, 0);
}
bool
LIRGeneratorX86Shared::lowerUDiv(MDiv *div)
{
- // Optimize x/x. The comments in lowerDivI apply here as well.
- if (div->lhs() == div->rhs()) {
- if (!div->canBeDivideByZero())
- return define(new(alloc()) LInteger(1), div);
-
- LDivSelfI *lir = new(alloc()) LDivSelfI(useRegisterAtStart(div->lhs()));
- if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
- return false;
- return define(lir, div);
- }
-
- LUDivOrMod *lir = new(alloc()) LUDivOrMod(useFixedAtStart(div->lhs(), eax),
+ LUDivOrMod *lir = new(alloc()) LUDivOrMod(useRegister(div->lhs()),
useRegister(div->rhs()),
tempFixed(edx));
if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
return false;
return defineFixed(lir, div, LAllocation(AnyRegister(eax)));
}
bool
LIRGeneratorX86Shared::lowerUMod(MMod *mod)
{
- // Optimize x%x. The comments in lowerModI apply here as well.
- if (mod->lhs() == mod->rhs()) {
- if (mod->isTruncated() || (mod->isUnsigned() && !mod->canBeDivideByZero()))
- return define(new(alloc()) LInteger(0), mod);
-
- LModSelfI *lir = new(alloc()) LModSelfI(useRegisterAtStart(mod->lhs()));
- if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
- return false;
- return define(lir, mod);
- }
-
- LUDivOrMod *lir = new(alloc()) LUDivOrMod(useFixedAtStart(mod->lhs(), eax),
+ LUDivOrMod *lir = new(alloc()) LUDivOrMod(useRegister(mod->lhs()),
useRegister(mod->rhs()),
tempFixed(eax));
if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
return false;
return defineFixed(lir, mod, LAllocation(AnyRegister(edx)));
}
bool
--- a/js/src/jit/x64/LOpcodes-x64.h
+++ b/js/src/jit/x64/LOpcodes-x64.h
@@ -8,19 +8,17 @@
#define jit_x64_LOpcodes_x64_h
#define LIR_CPU_OPCODE_LIST(_) \
_(Box) \
_(Unbox) \
_(UnboxFloatingPoint) \
_(DivI) \
_(DivPowTwoI) \
- _(DivSelfI) \
_(ModI) \
_(ModPowTwoI) \
- _(ModSelfI) \
_(PowHalfD) \
_(AsmJSUInt32ToDouble) \
_(AsmJSUInt32ToFloat32) \
_(AsmJSLoadFuncPtr) \
_(UDivOrMod)
#endif /* jit_x64_LOpcodes_x64_h */
--- a/js/src/jit/x86/LOpcodes-x86.h
+++ b/js/src/jit/x86/LOpcodes-x86.h
@@ -9,19 +9,17 @@
#define LIR_CPU_OPCODE_LIST(_) \
_(Unbox) \
_(UnboxFloatingPoint) \
_(Box) \
_(BoxFloatingPoint) \
_(DivI) \
_(DivPowTwoI) \
- _(DivSelfI) \
_(ModI) \
_(ModPowTwoI) \
- _(ModSelfI) \
_(PowHalfD) \
_(AsmJSUInt32ToDouble) \
_(AsmJSUInt32ToFloat32) \
_(AsmJSLoadFuncPtr) \
_(UDivOrMod)
#endif /* jit_x86_LOpcodes_x86_h */
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -631,22 +631,28 @@ JS::isGCEnabled()
{
return !TlsPerThreadData.get()->suppressGC;
}
#else
JS_FRIEND_API(bool) JS::isGCEnabled() { return true; }
#endif
JS_PUBLIC_API(JSRuntime *)
-JS_NewRuntime(uint32_t maxbytes, JSUseHelperThreads useHelperThreads)
+JS_NewRuntime(uint32_t maxbytes, JSUseHelperThreads useHelperThreads, JSRuntime *parentRuntime)
{
MOZ_ASSERT(jsInitState == Running,
"must call JS_Init prior to creating any JSRuntimes");
- JSRuntime *rt = js_new<JSRuntime>(useHelperThreads);
+ // Any parent runtime should be the topmost parent. This assert
+ // isn't required for correctness, but ensuring that the parent
+ // runtime is not destroyed before this one is more easily done
+ // for the main runtime in the process.
+ JS_ASSERT_IF(parentRuntime, !parentRuntime->parentRuntime);
+
+ JSRuntime *rt = js_new<JSRuntime>(parentRuntime, useHelperThreads);
if (!rt)
return nullptr;
if (!rt->init(maxbytes)) {
JS_DestroyRuntime(rt);
return nullptr;
}
@@ -802,16 +808,23 @@ JS_SetSecondContextPrivate(JSContext *cx
}
JS_PUBLIC_API(JSRuntime *)
JS_GetRuntime(JSContext *cx)
{
return cx->runtime();
}
+JS_PUBLIC_API(JSRuntime *)
+JS_GetParentRuntime(JSContext *cx)
+{
+ JSRuntime *rt = cx->runtime();
+ return rt->parentRuntime ? rt->parentRuntime : nullptr;
+}
+
JS_PUBLIC_API(JSContext *)
JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
{
JSContext *cx = *iterp;
cx = cx ? cx->getNext() : rt->contextList.getFirst();
*iterp = cx;
return cx;
}
@@ -1155,17 +1168,17 @@ typedef struct JSStdName {
static const JSStdName*
LookupStdName(JSRuntime *rt, HandleString name, const JSStdName *table)
{
MOZ_ASSERT(name->isAtom());
for (unsigned i = 0; !table[i].isSentinel(); i++) {
if (table[i].isDummy())
continue;
- JSAtom *atom = AtomStateOffsetToName(rt->atomState, table[i].atomOffset);
+ JSAtom *atom = AtomStateOffsetToName(*rt->commonNames, table[i].atomOffset);
MOZ_ASSERT(atom);
if (name == atom)
return &table[i];
}
return nullptr;
}
@@ -1260,17 +1273,17 @@ JS_ResolveStandardClass(JSContext *cx, H
rt = cx->runtime();
if (!rt->hasContexts() || !JSID_IS_ATOM(id))
return true;
RootedString idstr(cx, JSID_TO_STRING(id));
/* Check whether we're resolving 'undefined', and define it if so. */
- JSAtom *undefinedAtom = rt->atomState.undefined;
+ JSAtom *undefinedAtom = cx->names().undefined;
if (idstr == undefinedAtom) {
*resolved = true;
return JSObject::defineProperty(cx, obj, undefinedAtom->asPropertyName(),
UndefinedHandleValue,
JS_PropertyStub, JS_StrictPropertyStub,
JSPROP_PERMANENT | JSPROP_READONLY);
}
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1284,17 +1284,18 @@ JS_Init(void);
* It is currently not possible to initialize SpiderMonkey multiple times (that
* is, calling JS_Init/JSAPI methods/JS_ShutDown in that order, then doing so
* again). This restriction may eventually be lifted.
*/
extern JS_PUBLIC_API(void)
JS_ShutDown(void);
extern JS_PUBLIC_API(JSRuntime *)
-JS_NewRuntime(uint32_t maxbytes, JSUseHelperThreads useHelperThreads);
+JS_NewRuntime(uint32_t maxbytes, JSUseHelperThreads useHelperThreads,
+ JSRuntime *parentRuntime = nullptr);
extern JS_PUBLIC_API(void)
JS_DestroyRuntime(JSRuntime *rt);
// These are equivalent to ICU's |UMemAllocFn|, |UMemReallocFn|, and
// |UMemFreeFn| types. The first argument (called |context| in the ICU docs)
// will always be nullptr, and should be ignored.
typedef void *(*JS_ICUAllocFn)(const void *, size_t size);
@@ -1307,16 +1308,19 @@ extern JS_PUBLIC_API(bool)
JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, JS_ICUReallocFn reallocFn, JS_ICUFreeFn freeFn);
JS_PUBLIC_API(void *)
JS_GetRuntimePrivate(JSRuntime *rt);
extern JS_PUBLIC_API(JSRuntime *)
JS_GetRuntime(JSContext *cx);
+extern JS_PUBLIC_API(JSRuntime *)
+JS_GetParentRuntime(JSContext *cx);
+
JS_PUBLIC_API(void)
JS_SetRuntimePrivate(JSRuntime *rt, void *data);
extern JS_PUBLIC_API(void)
JS_BeginRequest(JSContext *cx);
extern JS_PUBLIC_API(void)
JS_EndRequest(JSContext *cx);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3272,18 +3272,17 @@ js::NewDenseCopiedArray(JSContext *cx, u
if (values)
arr->initDenseElements(0, values, length);
return arr;
}
ArrayObject *
-js::NewDenseCopiedArrayWithTemplate(JSContext *cx, uint32_t length, const Value *values,
- JSObject *templateObject)
+js::NewDenseAllocatedArrayWithTemplate(JSContext *cx, uint32_t length, JSObject *templateObject)
{
gc::AllocKind allocKind = GuessArrayGCKind(length);
JS_ASSERT(CanBeFinalizedInBackground(allocKind, &ArrayObject::class_));
allocKind = GetBackgroundAllocKind(allocKind);
RootedTypeObject type(cx, templateObject->type());
if (!type)
return nullptr;
@@ -3295,19 +3294,16 @@ js::NewDenseCopiedArrayWithTemplate(JSCo
gc::InitialHeap heap = GetInitialHeap(GenericObject, &ArrayObject::class_);
Rooted<ArrayObject *> arr(cx, JSObject::createArray(cx, allocKind, heap, shape, type, length));
if (!arr)
return nullptr;
if (!EnsureNewArrayElements(cx, arr, length))
return nullptr;
- arr->setDenseInitializedLength(length);
- arr->initDenseElements(0, values, length);
-
probes::CreateObject(cx, arr);
return arr;
}
#ifdef DEBUG
bool
js_ArrayInfo(JSContext *cx, unsigned argc, Value *vp)
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -65,23 +65,20 @@ NewDenseUnallocatedArray(ExclusiveContex
extern ArrayObject *
NewDenseCopiedArray(JSContext *cx, uint32_t length, HandleObject src, uint32_t elementOffset, JSObject *proto = nullptr);
/* Create a dense array from the given array values, which must be rooted */
extern ArrayObject *
NewDenseCopiedArray(JSContext *cx, uint32_t length, const Value *values, JSObject *proto = nullptr,
NewObjectKind newKind = GenericObject);
-/*
- * Create a dense array based on templateObject from the given array values,
- * which must be rooted.
- */
+/* Create a dense array based on templateObject with the given length. */
extern ArrayObject *
-NewDenseCopiedArrayWithTemplate(JSContext *cx, uint32_t length, const Value *values,
- JSObject *templateObject);
+NewDenseAllocatedArrayWithTemplate(JSContext *cx, uint32_t length, JSObject *templateObject);
+
/*
* Determines whether a write to the given element on |obj| should fail because
* |obj| is an Array with a non-writable length, and writing that element would
* increase the length of the array.
*/
extern bool
WouldDefinePastNonwritableLength(ThreadSafeContext *cx,
HandleObject obj, uint32_t index, bool strict,
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -99,86 +99,97 @@ const char js_super_str[] = "s
const char js_switch_str[] = "switch";
const char js_this_str[] = "this";
const char js_try_str[] = "try";
const char js_typeof_str[] = "typeof";
const char js_void_str[] = "void";
const char js_while_str[] = "while";
const char js_with_str[] = "with";
-/*
- * For a browser build from 2007-08-09 after the browser starts up there are
- * just 55 double atoms, but over 15000 string atoms. Not to penalize more
- * economical embeddings allocating too much memory initially we initialize
- * atomized strings with just 1K entries.
- */
-#define JS_STRING_HASH_COUNT 1024
-
-bool
-js::InitAtoms(JSRuntime *rt)
-{
- AutoLockForExclusiveAccess lock(rt);
- return rt->atoms().init(JS_STRING_HASH_COUNT);
-}
-
-void
-js::FinishAtoms(JSRuntime *rt)
-{
- AtomSet &atoms = rt->atoms();
- if (!atoms.initialized()) {
- /*
- * We are called with uninitialized state when JS_NewRuntime fails and
- * calls JS_DestroyRuntime on a partially initialized runtime.
- */
- return;
- }
-
- FreeOp fop(rt, false);
- for (AtomSet::Range r = atoms.all(); !r.empty(); r.popFront())
- r.front().asPtr()->finalize(&fop);
-}
+// Use a low initial capacity for atom hash tables to avoid penalizing runtimes
+// which create a small number of atoms.
+static const uint32_t JS_STRING_HASH_COUNT = 64;
struct CommonNameInfo
{
const char *str;
size_t length;
};
bool
-js::InitCommonNames(JSContext *cx)
+JSRuntime::initializeAtoms(JSContext *cx)
{
+ atoms_ = cx->new_<AtomSet>();
+ if (!atoms_ || !atoms_->init(JS_STRING_HASH_COUNT))
+ return false;
+
+ if (parentRuntime) {
+ staticStrings = parentRuntime->staticStrings;
+ commonNames = parentRuntime->commonNames;
+ emptyString = parentRuntime->emptyString;
+ permanentAtoms = parentRuntime->permanentAtoms;
+ return true;
+ }
+
+ permanentAtoms = cx->new_<AtomSet>();
+ if (!permanentAtoms || !permanentAtoms->init(JS_STRING_HASH_COUNT))
+ return false;
+
+ staticStrings = cx->new_<StaticStrings>();
+ if (!staticStrings || !staticStrings->init(cx))
+ return false;
+
static const CommonNameInfo cachedNames[] = {
#define COMMON_NAME_INFO(idpart, id, text) { js_##idpart##_str, sizeof(text) - 1 },
FOR_EACH_COMMON_PROPERTYNAME(COMMON_NAME_INFO)
#undef COMMON_NAME_INFO
#define COMMON_NAME_INFO(name, code, init, clasp) { js_##name##_str, sizeof(#name) - 1 },
JS_FOR_EACH_PROTOTYPE(COMMON_NAME_INFO)
#undef COMMON_NAME_INFO
};
- FixedHeapPtr<PropertyName> *names = &cx->runtime()->firstCachedName;
+ commonNames = cx->new_<JSAtomState>();
+ if (!commonNames)
+ return false;
+
+ FixedHeapPtr<PropertyName> *names = reinterpret_cast<FixedHeapPtr<PropertyName> *>(commonNames);
for (size_t i = 0; i < ArrayLength(cachedNames); i++, names++) {
JSAtom *atom = Atomize(cx, cachedNames[i].str, cachedNames[i].length, InternAtom);
if (!atom)
return false;
names->init(atom->asPropertyName());
}
- JS_ASSERT(uintptr_t(names) == uintptr_t(&cx->runtime()->atomState + 1));
+ JS_ASSERT(uintptr_t(names) == uintptr_t(commonNames + 1));
- cx->runtime()->emptyString = cx->names().empty;
+ emptyString = commonNames->empty;
return true;
}
void
-js::FinishCommonNames(JSRuntime *rt)
+JSRuntime::finishAtoms()
{
- rt->emptyString = nullptr;
-#ifdef DEBUG
- memset(&rt->atomState, JS_FREE_PATTERN, sizeof(JSAtomState));
-#endif
+ if (atoms_)
+ js_delete(atoms_);
+
+ if (!parentRuntime) {
+ if (staticStrings)
+ js_delete(staticStrings);
+
+ if (commonNames)
+ js_delete(commonNames);
+
+ if (permanentAtoms)
+ js_delete(permanentAtoms);
+ }
+
+ atoms_ = nullptr;
+ staticStrings = nullptr;
+ commonNames = nullptr;
+ permanentAtoms = nullptr;
+ emptyString = nullptr;
}
void
js::MarkAtoms(JSTracer *trc)
{
JSRuntime *rt = trc->runtime;
for (AtomSet::Enum e(rt->atoms()); !e.empty(); e.popFront()) {
const AtomStateEntry &entry = e.front();
@@ -189,41 +200,97 @@ js::MarkAtoms(JSTracer *trc)
bool tagged = entry.isTagged();
MarkStringRoot(trc, &atom, "interned_atom");
if (entry.asPtr() != atom)
e.rekeyFront(AtomHasher::Lookup(atom), AtomStateEntry(atom, tagged));
}
}
void
-js::SweepAtoms(JSRuntime *rt)
+js::MarkPermanentAtoms(JSTracer *trc)
{
- for (AtomSet::Enum e(rt->atoms()); !e.empty(); e.popFront()) {
+ JSRuntime *rt = trc->runtime;
+
+ // Permanent atoms only need to be marked in the runtime which owns them.
+ if (rt->parentRuntime)
+ return;
+
+ // Static strings are not included in the permanent atoms table.
+ if (rt->staticStrings)
+ rt->staticStrings->trace(trc);
+
+ if (rt->permanentAtoms) {
+ for (AtomSet::Enum e(*rt->permanentAtoms); !e.empty(); e.popFront()) {
+ const AtomStateEntry &entry = e.front();
+
+ JSAtom *atom = entry.asPtr();
+ MarkPermanentAtom(trc, atom, "permanent_table");
+ }
+ }
+}
+
+void
+JSRuntime::sweepAtoms()
+{
+ if (!atoms_)
+ return;
+
+ for (AtomSet::Enum e(*atoms_); !e.empty(); e.popFront()) {
AtomStateEntry entry = e.front();
JSAtom *atom = entry.asPtr();
bool isDying = IsStringAboutToBeFinalized(&atom);
/* Pinned or interned key cannot be finalized. */
- JS_ASSERT_IF(rt->hasContexts() && entry.isTagged(), !isDying);
+ JS_ASSERT_IF(hasContexts() && entry.isTagged(), !isDying);
if (isDying)
e.removeFront();
}
}
bool
+JSRuntime::transformToPermanentAtoms()
+{
+ JS_ASSERT(!parentRuntime);
+
+ // All static strings were created as permanent atoms, now move the contents
+ // of the atoms table into permanentAtoms and mark each as permanent.
+
+ JS_ASSERT(permanentAtoms && permanentAtoms->empty());
+
+ AtomSet *temp = atoms_;
+ atoms_ = permanentAtoms;
+ permanentAtoms = temp;
+
+ for (AtomSet::Enum e(*permanentAtoms); !e.empty(); e.popFront()) {
+ AtomStateEntry entry = e.front();
+ JSAtom *atom = entry.asPtr();
+ atom->morphIntoPermanentAtom();
+ }
+
+ return true;
+}
+
+bool
AtomIsInterned(JSContext *cx, JSAtom *atom)
{
/* We treat static strings as interned because they're never collected. */
if (StaticStrings::isStatic(atom))
return true;
+ AtomHasher::Lookup lookup(atom);
+
+ /* Likewise, permanent strings are considered to be interned. */
+ AtomSet::Ptr p = cx->permanentAtoms().readonlyThreadsafeLookup(lookup);
+ if (p)
+ return true;
+
AutoLockForExclusiveAccess lock(cx);
- AtomSet::Ptr p = cx->runtime()->atoms().lookup(atom);
+ p = cx->runtime()->atoms().lookup(lookup);
if (!p)
return false;
return p->isTagged();
}
/*
* When the jschars reside in a freshly allocated buffer the memory can be used
@@ -236,26 +303,34 @@ AtomizeAndTakeOwnership(ExclusiveContext
{
JS_ASSERT(tbchars[length] == 0);
if (JSAtom *s = cx->staticStrings().lookup(tbchars, length)) {
js_free(tbchars);
return s;
}
+ AtomHasher::Lookup lookup(tbchars, length);
+
+ AtomSet::Ptr pp = cx->permanentAtoms().readonlyThreadsafeLookup(lookup);
+ if (pp) {
+ js_free(tbchars);
+ return pp->asPtr();
+ }
+
AutoLockForExclusiveAccess lock(cx);
/*
* If a GC occurs at js_NewStringCopy then |p| will still have the correct
* hash, allowing us to avoid rehashing it. Even though the hash is
* unchanged, we need to re-lookup the table position because a last-ditch
* GC will potentially free some table entries.
*/
AtomSet& atoms = cx->atoms();
- AtomSet::AddPtr p = atoms.lookupForAdd(AtomHasher::Lookup(tbchars, length));
+ AtomSet::AddPtr p = atoms.lookupForAdd(lookup);
SkipRoot skipHash(cx, &p); /* Prevent the hash from being poisoned. */
if (p) {
JSAtom *atom = p->asPtr();
p->setTagged(bool(ib));
js_free(tbchars);
return atom;
}
@@ -265,44 +340,49 @@ AtomizeAndTakeOwnership(ExclusiveContext
if (!flat) {
js_free(tbchars);
js_ReportOutOfMemory(cx);
return nullptr;
}
JSAtom *atom = flat->morphAtomizedStringIntoAtom();
- if (!atoms.relookupOrAdd(p, AtomHasher::Lookup(tbchars, length),
- AtomStateEntry(atom, bool(ib)))) {
+ if (!atoms.relookupOrAdd(p, lookup, AtomStateEntry(atom, bool(ib)))) {
js_ReportOutOfMemory(cx); /* SystemAllocPolicy does not report OOM. */
return nullptr;
}
return atom;
}
/* |tbchars| must not point into an inline or short string. */
MOZ_ALWAYS_INLINE
static JSAtom *
AtomizeAndCopyChars(ExclusiveContext *cx, const jschar *tbchars, size_t length, InternBehavior ib)
{
if (JSAtom *s = cx->staticStrings().lookup(tbchars, length))
return s;
+ AtomHasher::Lookup lookup(tbchars, length);
+
+ AtomSet::Ptr pp = cx->permanentAtoms().readonlyThreadsafeLookup(lookup);
+ if (pp)
+ return pp->asPtr();
+
/*
* If a GC occurs at js_NewStringCopy then |p| will still have the correct
* hash, allowing us to avoid rehashing it. Even though the hash is
* unchanged, we need to re-lookup the table position because a last-ditch
* GC will potentially free some table entries.
*/
AutoLockForExclusiveAccess lock(cx);
AtomSet& atoms = cx->atoms();
- AtomSet::AddPtr p = atoms.lookupForAdd(AtomHasher::Lookup(tbchars, length));
+ AtomSet::AddPtr p = atoms.lookupForAdd(lookup);
SkipRoot skipHash(cx, &p); /* Prevent the hash from being poisoned. */
if (p) {
JSAtom *atom = p->asPtr();
p->setTagged(bool(ib));
return atom;
}
AutoCompartment ac(cx, cx->atomsCompartment());
@@ -310,18 +390,17 @@ AtomizeAndCopyChars(ExclusiveContext *cx
JSFlatString *flat = js_NewStringCopyN<NoGC>(cx, tbchars, length);
if (!flat) {
js_ReportOutOfMemory(cx);
return nullptr;
}
JSAtom *atom = flat->morphAtomizedStringIntoAtom();
- if (!atoms.relookupOrAdd(p, AtomHasher::Lookup(tbchars, length),
- AtomStateEntry(atom, bool(ib)))) {
+ if (!atoms.relookupOrAdd(p, lookup, AtomStateEntry(atom, bool(ib)))) {
js_ReportOutOfMemory(cx); /* SystemAllocPolicy does not report OOM. */
return nullptr;
}
return atom;
}
JSAtom *
@@ -329,19 +408,26 @@ js::AtomizeString(ExclusiveContext *cx,
js::InternBehavior ib /* = js::DoNotInternAtom */)
{
if (str->isAtom()) {
JSAtom &atom = str->asAtom();
/* N.B. static atoms are effectively always interned. */
if (ib != InternAtom || js::StaticStrings::isStatic(&atom))
return &atom;
+ AtomHasher::Lookup lookup(&atom);
+
+ /* Likewise, permanent atoms are always interned. */
+ AtomSet::Ptr p = cx->permanentAtoms().readonlyThreadsafeLookup(lookup);
+ if (p)
+ return &atom;
+
AutoLockForExclusiveAccess lock(cx);
- AtomSet::Ptr p = cx->atoms().lookup(AtomHasher::Lookup(&atom));
+ p = cx->atoms().lookup(lookup);
JS_ASSERT(p); /* Non-static atom must exist in atom state set. */
JS_ASSERT(p->asPtr() == &atom);
JS_ASSERT(ib == InternAtom);
p->setTagged(bool(ib));
return &atom;
}
const jschar *chars = str->getChars(cx);
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -84,21 +84,27 @@ class AtomStateEntry
struct AtomHasher
{
struct Lookup
{
const jschar *chars;
size_t length;
const JSAtom *atom; /* Optional. */
- Lookup(const jschar *chars, size_t length) : chars(chars), length(length), atom(nullptr) {}
+ HashNumber hash;
+
+ Lookup(const jschar *chars, size_t length)
+ : chars(chars), length(length), atom(nullptr)
+ {
+ hash = mozilla::HashString(chars, length);
+ }
inline Lookup(const JSAtom *atom);
};
- static HashNumber hash(const Lookup &l) { return mozilla::HashString(l.chars, l.length); }
+ static HashNumber hash(const Lookup &l) { return l.hash; }
static inline bool match(const AtomStateEntry &entry, const Lookup &lookup);
static void rekey(AtomStateEntry &k, const AtomStateEntry& newKey) { k = newKey; }
};
typedef HashSet<AtomStateEntry, AtomHasher, SystemAllocPolicy> AtomSet;
class PropertyName;
@@ -158,44 +164,23 @@ extern const char js_void_str[];
extern const char js_while_str[];
extern const char js_with_str[];
namespace js {
extern const char * const TypeStrings[];
/*
- * Initialize atom state. Return true on success, false on failure to allocate
- * memory. The caller must zero rt->atomState before calling this function and
- * only call it after js_InitGC successfully returns.
- */
-extern bool
-InitAtoms(JSRuntime *rt);
-
-/*
- * Free and clear atom state including any interned string atoms. This
- * function must be called before js_FinishGC.
- */
-extern void
-FinishAtoms(JSRuntime *rt);
-
-/*
* Atom tracing and garbage collection hooks.
*/
extern void
MarkAtoms(JSTracer *trc);
extern void
-SweepAtoms(JSRuntime *rt);
-
-extern bool
-InitCommonNames(JSContext *cx);
-
-extern void
-FinishCommonNames(JSRuntime *rt);
+MarkPermanentAtoms(JSTracer *trc);
/* N.B. must correspond to boolean tagging behavior. */
enum InternBehavior
{
DoNotInternAtom = false,
InternAtom = true
};
--- a/js/src/jsatominlines.h
+++ b/js/src/jsatominlines.h
@@ -133,17 +133,19 @@ IdToString(JSContext *cx, jsid id)
return nullptr;
return str->ensureFlat(cx);
}
inline
AtomHasher::Lookup::Lookup(const JSAtom *atom)
: chars(atom->chars()), length(atom->length()), atom(atom)
-{}
+{
+ hash = mozilla::HashString(chars, length);
+}
inline bool
AtomHasher::match(const AtomStateEntry &entry, const Lookup &lookup)
{
JSAtom *key = entry.asPtr();
if (lookup.atom)
return lookup.atom == key;
if (key->length() != lookup.length)
@@ -171,17 +173,17 @@ ClassName(JSProtoKey key, JSAtomState &a
sizeof(JSAtomState));
JS_STATIC_ASSERT(JSProto_Null == 0);
return (&atomState.Null)[key];
}
inline Handle<PropertyName*>
ClassName(JSProtoKey key, JSRuntime *rt)
{
- return ClassName(key, rt->atomState);
+ return ClassName(key, *rt->commonNames);
}
inline Handle<PropertyName*>
ClassName(JSProtoKey key, ExclusiveContext *cx)
{
return ClassName(key, cx->names());
}
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -189,29 +189,31 @@ js::NewContext(JSRuntime *rt, size_t sta
* steps should fail, the runtime will be left in a partially initialized
* state, with zeroes and nulls stored in the default-initialized remainder
* of the struct.
*/
if (!rt->haveCreatedContext) {
#ifdef JS_THREADSAFE
JS_BeginRequest(cx);
#endif
- bool ok = rt->staticStrings.init(cx);
- if (ok)
- ok = InitCommonNames(cx);
+ bool ok = rt->initializeAtoms(cx);
if (ok)
ok = rt->initSelfHosting(cx);
+ if (ok && !rt->parentRuntime)
+ ok = rt->transformToPermanentAtoms();
+
#ifdef JS_THREADSAFE
JS_EndRequest(cx);
#endif
if (!ok) {
DestroyContext(cx, DCM_NEW_FAILED);
return nullptr;
}
+
rt->haveCreatedContext = true;
}
JSContextCallback cxCallback = rt->cxCallback;
if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW, rt->cxCallbackData)) {
DestroyContext(cx, DCM_NEW_FAILED);
return nullptr;
}
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -271,18 +271,19 @@ struct ThreadSafeContext : ContextFriend
runtime_->updateMallocCounter(zone_, nbytes);
}
void reportAllocationOverflow() {
js_ReportAllocationOverflow(this);
}
// Accessors for immutable runtime data.
- JSAtomState &names() { return runtime_->atomState; }
- StaticStrings &staticStrings() { return runtime_->staticStrings; }
+ JSAtomState &names() { return *runtime_->commonNames; }
+ StaticStrings &staticStrings() { return *runtime_->staticStrings; }
+ AtomSet &permanentAtoms() { return *runtime_->permanentAtoms; }
const JS::AsmJSCacheOps &asmJSCacheOps() { return runtime_->asmJSCacheOps; }
PropertyName *emptyString() { return runtime_->emptyString; }
FreeOp *defaultFreeOp() { return runtime_->defaultFreeOp(); }
bool useHelperThreads() { return runtime_->useHelperThreads(); }
void *runtimeAddressForJit() { return runtime_; }
void *stackLimitAddress(StackKind kind) { return &runtime_->mainThread.nativeStackLimit[kind]; }
void *stackLimitAddressForJitCode(StackKind kind);
size_t gcSystemPageSize() { return runtime_->gcSystemPageSize; }
--- a/js/src/jscrashreport.cpp
+++ b/js/src/jscrashreport.cpp
@@ -211,41 +211,49 @@ Ring::copyBytes(void *data, size_t size)
js_memcpy(&buffer[offset], data, size);
offset += size;
}
}
} /* namespace crash */
} /* namespace js */
+#ifdef JS_CRASH_DIAGNOSTICS
static bool gInitialized;
static Stack gGCStack(JS_CRASH_STACK_GC);
static Stack gErrorStack(JS_CRASH_STACK_ERROR);
static Ring gRingBuffer(JS_CRASH_RING);
+#endif
void
js::crash::SnapshotGCStack()
{
+#ifdef JS_CRASH_DIAGNOSTICS
if (gInitialized)
gGCStack.snapshot();
+#endif
}
void
js::crash::SnapshotErrorStack()
{
+#ifdef JS_CRASH_DIAGNOSTICS
if (gInitialized)
gErrorStack.snapshot();
+#endif
}
void
js::crash::SaveCrashData(uint64_t tag, void *ptr, size_t size)
{
+#ifdef JS_CRASH_DIAGNOSTICS
if (gInitialized)
gRingBuffer.push(tag, ptr, size);
+#endif
}
JS_PUBLIC_API(void)
JS_EnumerateDiagnosticMemoryRegions(JSEnumerateDiagnosticMemoryCallback callback)
{
#ifdef JS_CRASH_DIAGNOSTICS
if (!gInitialized) {
gInitialized = true;
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -232,19 +232,25 @@ ComputeStackString(JSContext *cx)
/* Now the filename. */
RootedScript script(cx, i.script());
const char *cfilename = script->filename();
if (!cfilename)
cfilename = "";
if (!sb.appendInflated(cfilename, strlen(cfilename)))
return nullptr;
- /* Finally, : followed by the line number and a newline. */
- uint32_t line = PCToLineNumber(script, i.pc());
- if (!sb.append(':') || !NumberValueToStringBuffer(cx, NumberValue(line), sb) ||
+ uint32_t column = 0;
+ uint32_t line = PCToLineNumber(script, i.pc(), &column);
+ // Now the line number
+ if (!sb.append(':') || !NumberValueToStringBuffer(cx, NumberValue(line), sb))
+ return nullptr;
+
+ // Finally, : followed by the column number (1-based, as in other browsers)
+ // and a newline.
+ if (!sb.append(':') || !NumberValueToStringBuffer(cx, NumberValue(column + 1), sb) ||
!sb.append('\n'))
{
return nullptr;
}
/*
* Cut off the stack if it gets too deep (most commonly for
* infinite recursion errors).
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -65,17 +65,17 @@ JS_SetGrayGCRootsTracer(JSRuntime *rt, J
rt->gcGrayRootTracer.op = traceOp;
rt->gcGrayRootTracer.data = data;
}
JS_FRIEND_API(JSString *)
JS_GetAnonymousString(JSRuntime *rt)
{
JS_ASSERT(rt->hasContexts());
- return rt->atomState.anonymous;
+ return rt->commonNames->anonymous;
}
JS_FRIEND_API(void)
JS_SetIsWorkerRuntime(JSRuntime *rt)
{
rt->setIsWorkerRuntime();
}
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -175,17 +175,17 @@ fun_enumerate(JSContext *cx, HandleObjec
return false;
id = NameToId(cx->names().name);
if (!JSObject::hasProperty(cx, obj, id, &found, 0))
return false;
for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) {
const uint16_t offset = poisonPillProps[i];
- id = NameToId(AtomStateOffsetToName(cx->runtime()->atomState, offset));
+ id = NameToId(AtomStateOffsetToName(cx->names(), offset));
if (!JSObject::hasProperty(cx, obj, id, &found, 0))
return false;
}
return true;
}
static JSObject *
@@ -315,17 +315,17 @@ js::fun_resolve(JSContext *cx, HandleObj
}
objp.set(fun);
return true;
}
for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) {
const uint16_t offset = poisonPillProps[i];
- if (JSID_IS_ATOM(id, AtomStateOffsetToName(cx->runtime()->atomState, offset))) {
+ if (JSID_IS_ATOM(id, AtomStateOffsetToName(cx->names(), offset))) {
JS_ASSERT(!IsInternalFunctionObject(fun));
PropertyOp getter;
StrictPropertyOp setter;
unsigned attrs = JSPROP_PERMANENT | JSPROP_SHARED;
if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
return false;
if (fun->isInterpreted() ? fun->strict() : fun->isBoundFunction()) {
@@ -352,45 +352,66 @@ js::fun_resolve(JSContext *cx, HandleObj
}
template<XDRMode mode>
bool
js::XDRInterpretedFunction(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
MutableHandleObject objp)
{
enum FirstWordFlag {
- HasAtom = 0x1,
- IsStarGenerator = 0x2
+ HasAtom = 0x1,
+ IsStarGenerator = 0x2,
+ IsLazy = 0x4,
+ HasSingletonType = 0x8
};
/* NB: Keep this in sync with CloneFunctionAndScript. */
RootedAtom atom(xdr->cx());
uint32_t firstword = 0; /* bitmask of FirstWordFlag */
uint32_t flagsword = 0; /* word for argument count and fun->flags */
JSContext *cx = xdr->cx();
RootedFunction fun(cx);
RootedScript script(cx);
+ Rooted<LazyScript *> lazy(cx);
+
if (mode == XDR_ENCODE) {
fun = &objp->as<JSFunction>();
if (!fun->isInterpreted()) {
JSAutoByteString funNameBytes;
if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_NOT_SCRIPTED_FUNCTION, name);
}
return false;
}
+
if (fun->atom() || fun->hasGuessedAtom())
firstword |= HasAtom;
+
if (fun->isStarGenerator())
firstword |= IsStarGenerator;
- script = fun->getOrCreateScript(cx);
- if (!script)
- return false;
+
+ if (fun->isInterpretedLazy()) {
+ // This can only happen for re-lazified cloned functions, so this
+ // does not apply to any JSFunction produced by the parser, only to
+ // JSFunction created by the runtime.
+ JS_ASSERT(!fun->lazyScript()->maybeScript());
+
+ // Encode a lazy script.
+ firstword |= IsLazy;
+ lazy = fun->lazyScript();
+ } else {
+ // Encode the script.
+ script = fun->nonLazyScript();
+ }
+
+ if (fun->hasSingletonType())
+ firstword |= HasSingletonType;
+
atom = fun->displayAtom();
flagsword = (fun->nargs() << 16) | fun->flags();
}
if (!xdr->codeUint32(&firstword))
return false;
if (mode == XDR_DECODE) {
@@ -409,28 +430,39 @@ js::XDRInterpretedFunction(XDRState<mode
script = nullptr;
}
if ((firstword & HasAtom) && !XDRAtom(xdr, &atom))
return false;
if (!xdr->codeUint32(&flagsword))
return false;
- if (!XDRScript(xdr, enclosingScope, enclosingScript, fun, &script))
- return false;
+ if (firstword & IsLazy) {
+ if (!XDRLazyScript(xdr, enclosingScope, enclosingScript, fun, &lazy))
+ return false;
+ } else {
+ if (!XDRScript(xdr, enclosingScope, enclosingScript, fun, &script))
+ return false;
+ }
if (mode == XDR_DECODE) {
fun->setArgCount(flagsword >> 16);
fun->setFlags(uint16_t(flagsword));
fun->initAtom(atom);
- fun->initScript(script);
- script->setFunction(fun);
- if (!JSFunction::setTypeForScriptedFunction(cx, fun))
+ if (firstword & IsLazy) {
+ fun->initLazyScript(lazy);
+ } else {
+ fun->initScript(script);
+ script->setFunction(fun);
+ JS_ASSERT(fun->nargs() == script->bindings.numArgs());
+ }
+
+ bool singleton = firstword & HasSingletonType;
+ if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton))
return false;
- JS_ASSERT(fun->nargs() == fun->nonLazyScript()->bindings.numArgs());
objp.set(fun);
}
return true;
}
template bool
js::XDRInterpretedFunction(XDRState<XDR_ENCODE> *, HandleObject, HandleScript, MutableHandleObject);
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2433,22 +2433,21 @@ GCHelperThread::init()
backgroundAllocation = (GetCPUCount() >= 2);
#endif /* JS_THREADSAFE */
return true;
}
void
GCHelperThread::finish()
{
- if (!rt->useHelperThreads()) {
+ if (!rt->useHelperThreads() || !rt->gcLock) {
JS_ASSERT(state == IDLE);
return;
}
-
#ifdef JS_THREADSAFE
PRThread *join = nullptr;
{
AutoLockGC lock(rt);
if (thread && state != SHUTDOWN) {
/*
* We cannot be in the ALLOCATING or CANCEL_ALLOCATION states as
* the allocations should have been stopped during the last GC.
@@ -3135,17 +3134,17 @@ BeginMarkPhase(JSRuntime *rt)
}
/*
* For black roots, code in gc/Marking.cpp will already have set maybeAlive
* during MarkRuntime.
*/
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
- if (!zone->maybeAlive)
+ if (!zone->maybeAlive && !rt->isAtomsZone(zone))
zone->scheduledForDestruction = true;
}
rt->gcFoundBlackGrayEdges = false;
return true;
}
template <class CompartmentIterT>
@@ -3915,17 +3914,17 @@ BeginSweepingZoneGroup(JSRuntime *rt)
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_FINALIZE_START);
if (rt->gcFinalizeCallback)
rt->gcFinalizeCallback(&fop, JSFINALIZE_GROUP_START, !rt->gcIsFull /* unused */);
}
if (sweepingAtoms) {
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_ATOMS);
- SweepAtoms(rt);
+ rt->sweepAtoms();
}
/* Prune out dead views from ArrayBuffer's view lists. */
for (GCCompartmentGroupIter c(rt); !c.done(); c.next())
ArrayBufferObject::sweep(c);
/* Collect watch points associated with unreachable objects. */
WatchpointMap::sweepAll(rt);
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -92,17 +92,17 @@ ShouldNurseryAllocate(const Nursery &nur
#endif
inline JSGCTraceKind
GetGCThingTraceKind(const void *thing)
{
JS_ASSERT(thing);
const Cell *cell = static_cast<const Cell *>(thing);
#ifdef JSGC_GENERATIONAL
- if (IsInsideNursery(cell->runtimeFromMainThread(), cell))
+ if (IsInsideNursery(cell->runtimeFromAnyThread(), cell))
return JSTRACE_OBJECT;
#endif
return MapAllocToTraceKind(cell->tenuredGetAllocKind());
}
static inline void
GCPoke(JSRuntime *rt)
{
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -1192,17 +1192,17 @@ NormalizePropertyDescriptor(JSContext *c
AutoIdVector props(cx);
if (!GetPropertyNames(cx, attributes, 0, &props))
return false;
size_t n = props.length();
for (size_t i = 0; i < n; ++i) {
RootedId id(cx, props[i]);
if (JSID_IS_ATOM(id)) {
JSAtom *atom = JSID_TO_ATOM(id);
- const JSAtomState &atomState = cx->runtime()->atomState;
+ const JSAtomState &atomState = cx->names();
if (atom == atomState.value || atom == atomState.writable ||
atom == atomState.get || atom == atomState.set ||
atom == atomState.enumerable || atom == atomState.configurable)
{
continue;
}
}
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -409,16 +409,85 @@ js::XDRScriptConst(XDRState<mode> *xdr,
}
template bool
js::XDRScriptConst(XDRState<XDR_ENCODE> *, MutableHandleValue);
template bool
js::XDRScriptConst(XDRState<XDR_DECODE> *, MutableHandleValue);
+// Code LazyScript's free variables.
+template<XDRMode mode>
+static bool
+XDRLazyFreeVariables(XDRState<mode> *xdr, MutableHandle<LazyScript *> lazy)
+{
+ JSContext *cx = xdr->cx();
+ RootedAtom atom(cx);
+ HeapPtrAtom *freeVariables = lazy->freeVariables();
+ size_t numFreeVariables = lazy->numFreeVariables();
+ for (size_t i = 0; i < numFreeVariables; i++) {
+ if (mode == XDR_ENCODE)
+ atom = freeVariables[i];
+
+ if (!XDRAtom(xdr, &atom))
+ return false;
+
+ if (mode == XDR_DECODE)
+ freeVariables[i] = atom;
+ }
+
+ return true;
+}
+
+// Code the missing part needed to re-create a LazyScript from a JSScript.
+template<XDRMode mode>
+static bool
+XDRRelazificationInfo(XDRState<mode> *xdr, HandleFunction fun, HandleScript script,
+ MutableHandle<LazyScript *> lazy)
+{
+ MOZ_ASSERT_IF(mode == XDR_ENCODE, script->isRelazifiable() && script->maybeLazyScript());
+ MOZ_ASSERT_IF(mode == XDR_ENCODE, !lazy->numInnerFunctions());
+
+ JSContext *cx = xdr->cx();
+
+ uint64_t packedFields;
+ {
+ uint32_t begin = script->sourceStart();
+ uint32_t end = script->sourceEnd();
+ uint32_t lineno = script->lineno();
+ uint32_t column = script->column();
+
+ if (mode == XDR_ENCODE) {
+ packedFields = lazy->packedFields();
+ MOZ_ASSERT(begin == lazy->begin());
+ MOZ_ASSERT(end == lazy->end());
+ MOZ_ASSERT(lineno == lazy->lineno());
+ MOZ_ASSERT(column == lazy->column());
+ }
+
+ if (!xdr->codeUint64(&packedFields))
+ return false;
+
+ if (mode == XDR_DECODE) {
+ lazy.set(LazyScript::Create(cx, fun, packedFields, begin, end, lineno, column));
+
+ // As opposed to XDRLazyScript, we need to restore the runtime bits
+ // of the script, as we are trying to match the fact this function
+ // has already been parsed and that it would need to be re-lazified.
+ lazy->initRuntimeFields(packedFields);
+ }
+ }
+
+ // Code free variables.
+ if (!XDRLazyFreeVariables(xdr, lazy))
+ return false;
+
+ return true;
+}
+
static inline uint32_t
FindScopeObjectIndex(JSScript *script, NestedScopeObject &scope)
{
ObjectArray *objects = script->objects();
HeapPtrObject *vector = objects->vector;
unsigned length = objects->length;
for (unsigned i = 0; i < length; ++i) {
if (vector[i] == &scope)
@@ -458,17 +527,18 @@ js::XDRScript(XDRState<mode> *xdr, Handl
IsGeneratorExp,
IsLegacyGenerator,
IsStarGenerator,
OwnSource,
ExplicitUseStrict,
SelfHosted,
IsCompileAndGo,
HasSingleton,
- TreatAsRunOnce
+ TreatAsRunOnce,
+ HasLazyScript
};
uint32_t length, lineno, column, nslots;
uint32_t natoms, nsrcnotes, i;
uint32_t nconsts, nobjects, nregexps, ntrynotes, nblockscopes;
uint32_t prologLength, version;
uint32_t funLength = 0;
uint32_t nTypeSets = 0;
@@ -556,16 +626,18 @@ js::XDRScript(XDRState<mode> *xdr, Handl
if (script->isStarGenerator())
scriptBits |= (1 << IsStarGenerator);
if (script->compileAndGo())
scriptBits |= (1 << IsCompileAndGo);
if (script->hasSingletons())
scriptBits |= (1 << HasSingleton);
if (script->treatAsRunOnce())
scriptBits |= (1 << TreatAsRunOnce);
+ if (script->isRelazifiable())
+ scriptBits |= (1 << HasLazyScript);
}
if (!xdr->codeUint32(&prologLength))
return false;
if (!xdr->codeUint32(&version))
return false;
// To fuse allocations, we need lengths of all embedded arrays early.
@@ -816,42 +888,48 @@ js::XDRScript(XDRState<mode> *xdr, Handl
*objp = tmp;
}
break;
}
case CK_JSFunction: {
/* Code the nested function's enclosing scope. */
uint32_t funEnclosingScopeIndex = 0;
+ RootedObject funEnclosingScope(cx);
if (mode == XDR_ENCODE) {
- JSScript *innerScript = (*objp)->as<JSFunction>().getOrCreateScript(cx);
- if (!innerScript)
- return false;
- RootedObject staticScope(cx, innerScript->enclosingStaticScope());
- StaticScopeIter<NoGC> ssi(staticScope);
+ RootedFunction function(cx, &(*objp)->as<JSFunction>());
+
+ if (function->isInterpretedLazy())
+ funEnclosingScope = function->lazyScript()->enclosingScope();
+ else
+ funEnclosingScope = function->nonLazyScript()->enclosingStaticScope();
+
+ StaticScopeIter<NoGC> ssi(funEnclosingScope);
if (ssi.done() || ssi.type() == StaticScopeIter<NoGC>::FUNCTION) {
JS_ASSERT(ssi.done() == !fun);
funEnclosingScopeIndex = UINT32_MAX;
} else {
funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.block());
JS_ASSERT(funEnclosingScopeIndex < i);
}
}
+
if (!xdr->codeUint32(&funEnclosingScopeIndex))
return false;
- Rooted<JSObject*> funEnclosingScope(cx);
+
if (mode == XDR_DECODE) {
if (funEnclosingScopeIndex == UINT32_MAX) {
funEnclosingScope = fun;
} else {
JS_ASSERT(funEnclosingScopeIndex < i);
funEnclosingScope = script->objects()->vector[funEnclosingScopeIndex];
}
}
+ // Code nested function and script.
RootedObject tmp(cx, *objp);
if (!XDRInterpretedFunction(xdr, funEnclosingScope, script, &tmp))
return false;
*objp = tmp;
break;
}
case CK_JSObject: {
@@ -896,16 +974,28 @@ js::XDRScript(XDRState<mode> *xdr, Handl
!xdr->codeUint32(¬e->start) ||
!xdr->codeUint32(¬e->length) ||
!xdr->codeUint32(¬e->parent))
{
return false;
}
}
+ if (scriptBits & (1 << HasLazyScript)) {
+ Rooted<LazyScript *> lazy(cx);
+ if (mode == XDR_ENCODE)
+ lazy = script->maybeLazyScript();
+
+ if (!XDRRelazificationInfo(xdr, fun, script, &lazy))
+ return false;
+
+ if (mode == XDR_DECODE)
+ script->setLazyScript(lazy);
+ }
+
if (mode == XDR_DECODE) {
scriptp.set(script);
/* see BytecodeEmitter::tellDebuggerAboutCompiledScript */
CallNewScriptHook(cx, script, fun);
if (!fun) {
RootedGlobalObject global(cx, script->compileAndGo() ? &script->global() : nullptr);
Debugger::onNewScript(cx, script, global);
@@ -918,26 +1008,108 @@ js::XDRScript(XDRState<mode> *xdr, Handl
template bool
js::XDRScript(XDRState<XDR_ENCODE> *, HandleObject, HandleScript, HandleFunction,
MutableHandleScript);
template bool
js::XDRScript(XDRState<XDR_DECODE> *, HandleObject, HandleScript, HandleFunction,
MutableHandleScript);
+template<XDRMode mode>
+bool
+js::XDRLazyScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
+ HandleFunction fun, MutableHandle<LazyScript *> lazy)
+{
+ JSContext *cx = xdr->cx();
+
+ {
+ uint32_t begin;
+ uint32_t end;
+ uint32_t lineno;
+ uint32_t column;
+ uint64_t packedFields;
+
+ if (mode == XDR_ENCODE) {
+ MOZ_ASSERT(!lazy->maybeScript());
+ MOZ_ASSERT(fun == lazy->functionNonDelazifying());
+
+ begin = lazy->begin();
+ end = lazy->end();
+ lineno = lazy->lineno();
+ column = lazy->column();
+ packedFields = lazy->packedFields();
+ }
+
+ if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) ||
+ !xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) ||
+ !xdr->codeUint64(&packedFields))
+ {
+ return false;
+ }
+
+ if (mode == XDR_DECODE)
+ lazy.set(LazyScript::Create(cx, fun, packedFields, begin, end, lineno, column));
+ }
+
+ // Code free variables.
+ if (!XDRLazyFreeVariables(xdr, lazy))
+ return false;
+
+ // Code inner functions.
+ {
+ RootedObject func(cx);
+ HeapPtrFunction *innerFunctions = lazy->innerFunctions();
+ size_t numInnerFunctions = lazy->numInnerFunctions();
+ for (size_t i = 0; i < numInnerFunctions; i++) {
+ if (mode == XDR_ENCODE)
+ func = innerFunctions[i];
+
+ if (!XDRInterpretedFunction(xdr, fun, enclosingScript, &func))
+ return false;
+
+ if (mode == XDR_DECODE)
+ innerFunctions[i] = &func->as<JSFunction>();
+ }
+ }
+
+ if (mode == XDR_DECODE) {
+ JS_ASSERT(!lazy->sourceObject());
+ ScriptSourceObject *sourceObject = &enclosingScript->scriptSourceUnwrap();
+
+ // Set the enclosing scope of the lazy function, this would later be
+ // used to define the environment when the function would be used.
+ lazy->setParent(enclosingScope, sourceObject);
+ }
+
+ return true;
+}
+
+template bool
+js::XDRLazyScript(XDRState<XDR_ENCODE> *, HandleObject, HandleScript,
+ HandleFunction, MutableHandle<LazyScript *>);
+
+template bool
+js::XDRLazyScript(XDRState<XDR_DECODE> *, HandleObject, HandleScript,
+ HandleFunction, MutableHandle<LazyScript *>);
+
void
JSScript::setSourceObject(JSObject *object)
{
JS_ASSERT(compartment() == object->compartment());
sourceObject_ = object;
}
+js::ScriptSourceObject &
+JSScript::scriptSourceUnwrap() const {
+ return UncheckedUnwrap(sourceObject())->as<ScriptSourceObject>();
+}
+
js::ScriptSource *
JSScript::scriptSource() const {
- return UncheckedUnwrap(sourceObject())->as<ScriptSourceObject>().source();
+ return scriptSourceUnwrap().source();
}
bool
JSScript::initScriptCounts(JSContext *cx)
{
JS_ASSERT(!hasScriptCounts());
size_t n = 0;
@@ -3237,40 +3409,28 @@ JSScript::formalIsAliased(unsigned argSl
}
bool
JSScript::formalLivesInArgumentsObject(unsigned argSlot)
{
return argsObjAliasesFormals() && !formalIsAliased(argSlot);
}
-LazyScript::LazyScript(JSFunction *fun, void *table, uint32_t numFreeVariables, uint32_t numInnerFunctions,
- JSVersion version, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
+LazyScript::LazyScript(JSFunction *fun, void *table, uint64_t packedFields, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
: script_(nullptr),
function_(fun),
enclosingScope_(nullptr),
sourceObject_(nullptr),
table_(table),
- version_(version),
- numFreeVariables_(numFreeVariables),
- numInnerFunctions_(numInnerFunctions),
- generatorKindBits_(GeneratorKindAsBits(NotGenerator)),
- strict_(false),
- bindingsAccessedDynamically_(false),
- hasDebuggerStatement_(false),
- directlyInsideEval_(false),
- usesArgumentsAndApply_(false),
- hasBeenCloned_(false),
- treatAsRunOnce_(false),
+ packedFields_(packedFields),
begin_(begin),
end_(end),
lineno_(lineno),
column_(column)
{
- JS_ASSERT(this->version() == version);
JS_ASSERT(begin <= end);
}
void
LazyScript::initScript(JSScript *script)
{
JS_ASSERT(script && !script_);
script_ = script;
@@ -3296,40 +3456,116 @@ LazyScript::setParent(JSObject *enclosin
ScriptSourceObject *
LazyScript::sourceObject() const
{
return sourceObject_ ? &sourceObject_->as<ScriptSourceObject>() : nullptr;
}
/* static */ LazyScript *
-LazyScript::Create(ExclusiveContext *cx, HandleFunction fun,
- uint32_t numFreeVariables, uint32_t numInnerFunctions, JSVersion version,
- uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
+LazyScript::CreateRaw(ExclusiveContext *cx, HandleFunction fun,
+ uint64_t packedFields, uint32_t begin, uint32_t end,
+ uint32_t lineno, uint32_t column)
{
- JS_ASSERT(begin <= end);
-
- size_t bytes = (numFreeVariables * sizeof(HeapPtrAtom))
- + (numInnerFunctions * sizeof(HeapPtrFunction));
+ union {
+ PackedView p;
+ uint64_t packed;
+ };
+
+ packed = packedFields;
+
+ // Reset runtime flags to obtain a fresh LazyScript.
+ p.hasBeenCloned = false;
+ p.treatAsRunOnce = false;
+
+ size_t bytes = (p.numFreeVariables * sizeof(HeapPtrAtom))
+ + (p.numInnerFunctions * sizeof(HeapPtrFunction));
void *table = nullptr;
if (bytes) {
table = cx->malloc_(bytes);
if (!table)
return nullptr;
}
LazyScript *res = js_NewGCLazyScript(cx);
if (!res)
return nullptr;
cx->compartment()->scheduleDelazificationForDebugMode();
- return new (res) LazyScript(fun, table, numFreeVariables, numInnerFunctions, version,
- begin, end, lineno, column);
+ return new (res) LazyScript(fun, table, packed, begin, end, lineno, column);
+}
+
+/* static */ LazyScript *
+LazyScript::CreateRaw(ExclusiveContext *cx, HandleFunction fun,
+ uint32_t numFreeVariables, uint32_t numInnerFunctions, JSVersion version,
+ uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
+{
+ union {
+ PackedView p;
+ uint64_t packedFields;
+ };
+
+ p.version = version;
+ p.numFreeVariables = numFreeVariables;
+ p.numInnerFunctions = numInnerFunctions;
+ p.generatorKindBits = GeneratorKindAsBits(NotGenerator);
+ p.strict = false;
+ p.bindingsAccessedDynamically = false;
+ p.hasDebuggerStatement = false;
+ p.directlyInsideEval = false;
+ p.usesArgumentsAndApply = false;
+
+ LazyScript *res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
+ JS_ASSERT(res->version() == version);
+ return res;
+}
+
+/* static */ LazyScript *
+LazyScript::Create(ExclusiveContext *cx, HandleFunction fun,
+ uint64_t packedFields, uint32_t begin, uint32_t end,
+ uint32_t lineno, uint32_t column)
+{
+ // Dummy atom which is not a valid property name.
+ RootedAtom dummyAtom(cx, cx->names().comma);
+
+ // Dummy function which is not a valid function as this is the one which is
+ // holding this lazy script.
+ HandleFunction dummyFun = fun;
+
+ LazyScript *res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
+ if (!res)
+ return nullptr;
+
+ // Fill with dummies, to be GC-safe after the initialization of the free
+ // variables and inner functions.
+ size_t i, num;
+ HeapPtrAtom *variables = res->freeVariables();
+ for (i = 0, num = res->numFreeVariables(); i < num; i++)
+ variables[i].init(dummyAtom);
+
+ HeapPtrFunction *functions = res->innerFunctions();
+ for (i = 0, num = res->numInnerFunctions(); i < num; i++)
+ functions[i].init(dummyFun);
+
+ return res;
+}
+
+void
+LazyScript::initRuntimeFields(uint64_t packedFields)
+{
+ union {
+ PackedView p;
+ uint64_t packed;
+ };
+
+ packed = packedFields;
+ p_.hasBeenCloned = p.hasBeenCloned;
+ p_.treatAsRunOnce = p.treatAsRunOnce;
}
uint32_t
LazyScript::staticLevel(JSContext *cx) const
{
for (StaticScopeIter<NoGC> ssi(enclosingScope()); !ssi.done(); ssi++) {
if (ssi.type() == StaticScopeIter<NoGC>::FUNCTION)
return ssi.funScript()->staticLevel() + 1;
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -590,16 +590,21 @@ template<XDRMode mode>
bool
XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
HandleFunction fun, MutableHandleScript scriptp);
JSScript *
CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, HandleScript script,
NewObjectKind newKind = GenericObject);
+template<XDRMode mode>
+bool
+XDRLazyScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
+ HandleFunction fun, MutableHandle<LazyScript *> lazy);
+
/*
* Code any constant value.
*/
template<XDRMode mode>
bool
XDRScriptConst(XDRState<mode> *xdr, MutableHandleValue vp);
} /* namespace js */
@@ -1235,16 +1240,17 @@ class JSScript : public js::gc::Barriere
JSFlatString *sourceData(JSContext *cx);
static bool loadSource(JSContext *cx, js::ScriptSource *ss, bool *worked);
void setSourceObject(JSObject *object);
JSObject *sourceObject() const {
return sourceObject_;
}
+ js::ScriptSourceObject &scriptSourceUnwrap() const;
js::ScriptSource *scriptSource() const;
JSPrincipals *originPrincipals() const { return scriptSource()->originPrincipals(); }
const char *filename() const { return scriptSource()->filename(); }
public:
/* Return whether this script was compiled for 'eval' */
bool isForEval() { return isCachedEval() || isActiveEval(); }
@@ -1602,49 +1608,74 @@ class LazyScript : public gc::BarrieredC
// Heap allocated table with any free variables or inner functions.
void *table_;
#if JS_BITS_PER_WORD == 32
uint32_t padding;
#endif
- // Assorted bits that should really be in ScriptSourceObject.
- uint32_t version_ : 8;
+ struct PackedView {
+ // Assorted bits that should really be in ScriptSourceObject.
+ uint32_t version : 8;
- uint32_t numFreeVariables_ : 24;
- uint32_t numInnerFunctions_ : 23;
+ uint32_t numFreeVariables : 24;
+ uint32_t numInnerFunctions : 23;
- uint32_t generatorKindBits_:2;
+ uint32_t generatorKindBits : 2;
- // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
- uint32_t strict_ : 1;
- uint32_t bindingsAccessedDynamically_ : 1;
- uint32_t hasDebuggerStatement_ : 1;
- uint32_t directlyInsideEval_:1;
- uint32_t usesArgumentsAndApply_:1;
- uint32_t hasBeenCloned_:1;
- uint32_t treatAsRunOnce_:1;
+ // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
+ uint32_t strict : 1;
+ uint32_t bindingsAccessedDynamically : 1;
+ uint32_t hasDebuggerStatement : 1;
+ uint32_t directlyInsideEval : 1;
+ uint32_t usesArgumentsAndApply : 1;
+ uint32_t hasBeenCloned : 1;
+ uint32_t treatAsRunOnce : 1;
+ };
+
+ union {
+ PackedView p_;
+ uint64_t packedFields_;
+ };
// Source location for the script.
uint32_t begin_;
uint32_t end_;
uint32_t lineno_;
uint32_t column_;
- LazyScript(JSFunction *fun, void *table,
- uint32_t numFreeVariables, uint32_t numInnerFunctions, JSVersion version,
+ LazyScript(JSFunction *fun, void *table, uint64_t packedFields,
uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column);
+ // Create a LazyScript without initializing the freeVariables and the
+ // innerFunctions. To be GC-safe, the caller must initialize both vectors
+ // with valid atoms and functions.
+ static LazyScript *CreateRaw(ExclusiveContext *cx, HandleFunction fun,
+ uint64_t packedData, uint32_t begin, uint32_t end,
+ uint32_t lineno, uint32_t column);
+
public:
+ // Create a LazyScript without initializing the freeVariables and the
+ // innerFunctions. To be GC-safe, the caller must initialize both vectors
+ // with valid atoms and functions.
+ static LazyScript *CreateRaw(ExclusiveContext *cx, HandleFunction fun,
+ uint32_t numFreeVariables, uint32_t numInnerFunctions,
+ JSVersion version, uint32_t begin, uint32_t end,
+ uint32_t lineno, uint32_t column);
+
+ // Create a LazyScript and initialize the freeVariables and the
+ // innerFunctions with dummy values to be replaced in a later initialization
+ // phase.
static LazyScript *Create(ExclusiveContext *cx, HandleFunction fun,
- uint32_t numFreeVariables, uint32_t numInnerFunctions,
- JSVersion version, uint32_t begin, uint32_t end,
+ uint64_t packedData, uint32_t begin, uint32_t end,
uint32_t lineno, uint32_t column);
+ void initRuntimeFields(uint64_t packedFields);
+
inline JSFunction *functionDelazifying(JSContext *cx) const;
JSFunction *functionNonDelazifying() const {
return function_;
}
void initScript(JSScript *script);
void resetScript();
JSScript *maybeScript() {
@@ -1658,99 +1689,99 @@ class LazyScript : public gc::BarrieredC
ScriptSource *scriptSource() const {
return sourceObject()->source();
}
JSPrincipals *originPrincipals() const {
return scriptSource()->originPrincipals();
}
JSVersion version() const {
JS_STATIC_ASSERT(JSVERSION_UNKNOWN == -1);
- return (version_ == JS_BIT(8) - 1) ? JSVERSION_UNKNOWN : JSVersion(version_);
+ return (p_.version == JS_BIT(8) - 1) ? JSVERSION_UNKNOWN : JSVersion(p_.version);
}
void setParent(JSObject *enclosingScope, ScriptSourceObject *sourceObject);
uint32_t numFreeVariables() const {
- return numFreeVariables_;
+ return p_.numFreeVariables;
}
HeapPtrAtom *freeVariables() {
return (HeapPtrAtom *)table_;
}
uint32_t numInnerFunctions() const {
- return numInnerFunctions_;
+ return p_.numInnerFunctions;
}
HeapPtrFunction *innerFunctions() {
return (HeapPtrFunction *)&freeVariables()[numFreeVariables()];
}
- GeneratorKind generatorKind() const { return GeneratorKindFromBits(generatorKindBits_); }
+ GeneratorKind generatorKind() const { return GeneratorKindFromBits(p_.generatorKindBits); }
bool isGenerator() const { return generatorKind() != NotGenerator; }
bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
bool isStarGenerator() const { return generatorKind() == StarGenerator; }
void setGeneratorKind(GeneratorKind kind) {
// A script only gets its generator kind set as part of initialization,
// so it can only transition from NotGenerator.
JS_ASSERT(!isGenerator());
// Legacy generators cannot currently be lazy.
JS_ASSERT(kind != LegacyGenerator);
- generatorKindBits_ = GeneratorKindAsBits(kind);
+ p_.generatorKindBits = GeneratorKindAsBits(kind);
}
bool strict() const {
- return strict_;
+ return p_.strict;
}
void setStrict() {
- strict_ = true;
+ p_.strict = true;
}
bool bindingsAccessedDynamically() const {
- return bindingsAccessedDynamically_;
+ return p_.bindingsAccessedDynamically;
}
void setBindingsAccessedDynamically() {
- bindingsAccessedDynamically_ = true;
+ p_.bindingsAccessedDynamically = true;
}
bool hasDebuggerStatement() const {
- return hasDebuggerStatement_;
+ return p_.hasDebuggerStatement;
}
void setHasDebuggerStatement() {
- hasDebuggerStatement_ = true;
+ p_.hasDebuggerStatement = true;
}
bool directlyInsideEval() const {
- return directlyInsideEval_;
+ return p_.directlyInsideEval;
}
void setDirectlyInsideEval() {
- directlyInsideEval_ = true;
+ p_.directlyInsideEval = true;
}
bool usesArgumentsAndApply() const {
- return usesArgumentsAndApply_;
+ return p_.usesArgumentsAndApply;
}
void setUsesArgumentsAndApply() {
- usesArgumentsAndApply_ = true;
+ p_.usesArgumentsAndApply = true;
}
bool hasBeenCloned() const {
- return hasBeenCloned_;
+ return p_.hasBeenCloned;
}
void setHasBeenCloned() {
- hasBeenCloned_ = true;
+ p_.hasBeenCloned = true;
}
bool treatAsRunOnce() const {
- return treatAsRunOnce_;
+ return p_.treatAsRunOnce;
}
void setTreatAsRunOnce() {
- treatAsRunOnce_ = true;
+ p_.treatAsRunOnce = true;
}
ScriptSource *source() const {
return sourceObject()->source();
}
uint32_t begin() const {
return begin_;
}
@@ -1770,16 +1801,20 @@ class LazyScript : public gc::BarrieredC
void finalize(js::FreeOp *fop);
static inline js::ThingRootKind rootKind() { return js::THING_ROOT_LAZY_SCRIPT; }
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
{
return mallocSizeOf(table_);
}
+
+ uint64_t packedFields() const {
+ return packedFields_;
+ }
};
/* If this fails, add/remove padding within LazyScript. */
JS_STATIC_ASSERT(sizeof(LazyScript) % js::gc::CellSize == 0);
/*
* New-script-hook calling is factored from JSScript::fullyInitFromEmitter() so
* that it and callers of XDRScript() can share this code. In the case of
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -388,17 +388,17 @@ js::str_resolve(JSContext *cx, HandleObj
{
if (!JSID_IS_INT(id))
return true;
RootedString str(cx, obj->as<StringObject>().unbox());
int32_t slot = JSID_TO_INT(id);
if ((size_t)slot < str->length()) {
- JSString *str1 = cx->runtime()->staticStrings.getUnitStringForElement(cx, str, size_t(slot));
+ JSString *str1 = cx->staticStrings().getUnitStringForElement(cx, str, size_t(slot));
if (!str1)
return false;
RootedValue value(cx, StringValue(str1));
if (!JSObject::defineElement(cx, obj, uint32_t(slot), value, nullptr, nullptr,
STRING_ELEMENT_ATTRS))
{
return false;
}
@@ -859,17 +859,17 @@ js_str_charAt(JSContext *cx, unsigned ar
if (args.length() > 0 && !ToInteger(cx, args[0], &d))
return false;
if (d < 0 || str->length() <= d)
goto out_of_range;
i = size_t(d);
}
- str = cx->runtime()->staticStrings.getUnitStringForElement(cx, str, i);
+ str = cx->staticStrings().getUnitStringForElement(cx, str, i);
if (!str)
return false;
args.rval().setString(str);
return true;
out_of_range:
args.rval().setString(cx->runtime()->emptyString);
return true;
@@ -1858,17 +1858,17 @@ DoMatchLocal(JSContext *cx, CallArgs arg
if (status == RegExpRunStatus_Success_NotFound) {
args.rval().setNull();
return true;
}
res->updateFromMatchPairs(cx, input, matches);
RootedValue rval(cx);
- if (!CreateRegExpMatchResult(cx, input, chars, charsLen, matches, &rval))
+ if (!CreateRegExpMatchResult(cx, input, matches, &rval))
return false;
args.rval().set(rval);
return true;
}
/* ES5 15.5.4.10 step 8. */
static bool
@@ -3236,17 +3236,17 @@ SplitHelper(JSContext *cx, Handle<JSLine
// Fast-path for splitting a string into a character array via split("").
static ArrayObject *
CharSplitHelper(JSContext *cx, Handle<JSLinearString*> str, uint32_t limit)
{
size_t strLength = str->length();
if (strLength == 0)
return NewDenseEmptyArray(cx);
- js::StaticStrings &staticStrings = cx->runtime()->staticStrings;
+ js::StaticStrings &staticStrings = cx->staticStrings();
uint32_t resultlen = (limit < strLength ? limit : strLength);
AutoValueVector splits(cx);
if (!splits.reserve(resultlen))
return nullptr;
for (size_t i = 0; i < resultlen; ++i) {
JSString *sub = staticStrings.getUnitStringForElement(cx, str, i);
@@ -3541,17 +3541,17 @@ str_slice(JSContext *cx, unsigned argc,
size_t begin = args[0].toInt32();
size_t end = str->length();
if (begin <= end) {
size_t length = end - begin;
if (length == 0) {
str = cx->runtime()->emptyString;
} else {
str = (length == 1)
- ? cx->runtime()->staticStrings.getUnitStringForElement(cx, str, begin)
+ ? cx->staticStrings().getUnitStringForElement(cx, str, begin)
: js_NewDependentString(cx, str, begin, length);
if (!str)
return false;
}
args.rval().setString(str);
return true;
}
}
@@ -3859,17 +3859,17 @@ js::str_fromCharCode(JSContext *cx, unsi
CallArgs args = CallArgsFromVp(argc, vp);
JS_ASSERT(args.length() <= ARGS_LENGTH_MAX);
if (args.length() == 1) {
uint16_t code;
if (!ToUint16(cx, args[0], &code))
return false;
if (StaticStrings::hasUnit(code)) {
- args.rval().setString(cx->runtime()->staticStrings.getUnit(code));
+ args.rval().setString(cx->staticStrings().getUnit(code));
return true;
}
args[0].setInt32(code);
}
jschar *chars = cx->pod_malloc<jschar>(args.length() + 1);
if (!chars)
return false;
for (unsigned i = 0; i < args.length(); i++) {
@@ -3985,17 +3985,17 @@ js_NewDependentString(JSContext *cx, JSS
if (!base)
return nullptr;
if (start == 0 && length == base->length())
return base;
const jschar *chars = base->chars() + start;
- if (JSLinearString *staticStr = cx->runtime()->staticStrings.lookup(chars, length))
+ if (JSLinearString *staticStr = cx->staticStrings().lookup(chars, length))
return staticStr;
return JSDependentString::new_(cx, base, chars, length);
}
template <AllowGC allowGC>
JSFlatString *
js_NewStringCopyN(ExclusiveContext *cx, const jschar *s, size_t n)
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -188,16 +188,19 @@ enum JSShellErrNum {
};
static JSContext *
NewContext(JSRuntime *rt);
static void
DestroyContext(JSContext *cx, bool withGC);
+static JSObject *
+NewGlobalObject(JSContext *cx, JS::CompartmentOptions &options);
+
static const JSErrorFormatString *
my_GetErrorMessage(void *userRef, const char *locale, const unsigned errorNumber);
#ifdef EDITLINE
extern "C" {
extern JS_EXPORT_API(char *) readline(const char *prompt);
extern JS_EXPORT_API(void) add_history(char *line);
} // extern "C"
@@ -2600,16 +2603,113 @@ EvalInFrame(JSContext *cx, unsigned argc
bool ok = !!frame.evaluateUCInStackFrame(cx, chars, length,
fpscript->filename(),
JS_PCToLineNumber(cx, fpscript,
fi.pc()),
MutableHandleValue::fromMarkedLocation(vp));
return ok;
}
+struct WorkerInput
+{
+ JSRuntime *runtime;
+ jschar *chars;
+ size_t length;
+
+ WorkerInput(JSRuntime *runtime, jschar *chars, size_t length)
+ : runtime(runtime), chars(chars), length(length)
+ {}
+
+ ~WorkerInput() {
+ js_free(chars);
+ }
+};
+
+static void
+WorkerMain(void *arg)
+{
+ WorkerInput *input = (WorkerInput *) arg;
+
+ JSRuntime *rt = JS_NewRuntime(8L * 1024L * 1024L,
+ JS_USE_HELPER_THREADS,
+ input->runtime);
+ if (!rt) {
+ js_delete(input);
+ return;
+ }
+
+ JSContext *cx = NewContext(rt);
+ if (!cx) {
+ JS_DestroyRuntime(rt);
+ js_delete(input);
+ return;
+ }
+
+ do {
+ JSAutoRequest ar(cx);
+
+ JS::CompartmentOptions compartmentOptions;
+ compartmentOptions.setVersion(JSVERSION_LATEST);
+ RootedObject global(cx, NewGlobalObject(cx, compartmentOptions));
+ if (!global)
+ break;
+
+ JSAutoCompartment ac(cx, global);
+
+ JS::CompileOptions options(cx);
+ options.setFileAndLine("<string>", 1)
+ .setCompileAndGo(true);
+
+ JSScript *script = JS::Compile(cx, global, options,
+ input->chars, input->length);
+ if (!script)
+ break;
+ RootedValue result(cx);
+ JS_ExecuteScript(cx, global, script, result.address());
+ } while (0);
+
+ DestroyContext(cx, false);
+ JS_DestroyRuntime(rt);
+
+ js_delete(input);
+}
+
+Vector<PRThread *, 0, SystemAllocPolicy> workerThreads;
+
+static bool
+EvalInWorker(JSContext *cx, unsigned argc, jsval *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ if (argc < 1 || !args[0].isString()) {
+ JS_ReportError(cx, "Invalid arguments to evalInWorker");
+ return false;
+ }
+
+ if (!args[0].toString()->ensureLinear(cx))
+ return false;
+
+ JSLinearString *str = &args[0].toString()->asLinear();
+
+ jschar *chars = (jschar *) js_malloc(str->length() * sizeof(jschar));
+ if (!chars)
+ return false;
+ PodCopy(chars, str->chars(), str->length());
+
+ WorkerInput *input = js_new<WorkerInput>(cx->runtime(), chars, str->length());
+ if (!input)
+ return false;
+
+ PRThread *thread = PR_CreateThread(PR_USER_THREAD, WorkerMain, input,
+ PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
+ if (!thread || !workerThreads.append(thread))
+ return false;
+
+ return true;
+}
+
static bool
ShapeOf(JSContext *cx, unsigned argc, JS::Value *vp)
{
JS::Value v;
if (argc < 1 || !((v = JS_ARGV(cx, vp)[0]).isObject())) {
JS_ReportError(cx, "shapeOf: object expected");
return false;
}
@@ -3807,19 +3907,16 @@ WrapWithProto(JSContext *cx, unsigned ar
&Wrapper::singletonWithPrototype, &options);
if (!wrapped)
return false;
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(wrapped));
return true;
}
-static JSObject *
-NewGlobalObject(JSContext *cx, JS::CompartmentOptions &options);
-
static bool
NewGlobal(JSContext *cx, unsigned argc, jsval *vp)
{
JS::CompartmentOptions options;
options.setVersion(JSVERSION_LATEST);
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() == 1 && args[0].isObject()) {
@@ -4167,16 +4264,20 @@ static const JSFunctionSpecWithHelp shel
" if (s == '' && !o) return new o with eager standard classes\n"
" if (s == 'lazy' && !o) return new o with lazy standard classes"),
JS_FN_HELP("evalInFrame", EvalInFrame, 2, 0,
"evalInFrame(n,str,save)",
" Evaluate 'str' in the nth up frame.\n"
" If 'save' (default false), save the frame chain."),
+ JS_FN_HELP("evalInWorker", EvalInWorker, 1, 0,
+"evalInWorker(str)",
+" Evaluate 'str' in a separate thread with its own runtime.\n"),
+
JS_FN_HELP("shapeOf", ShapeOf, 1, 0,
"shapeOf(obj)",
" Get the shape of obj (an implementation detail)."),
JS_FN_HELP("resolver", Resolver, 1, 0,
"resolver(src[, proto])",
" Create object with resolve hook that copies properties\n"
" from src. If proto is omitted, use Object.prototype."),
@@ -5947,12 +6048,15 @@ main(int argc, char **argv, char **envp)
gTimeoutFunc = NullValue();
JS_RemoveValueRootRT(rt, &gTimeoutFunc);
DestroyContext(cx, true);
KillWatchdog();
+ for (size_t i = 0; i < workerThreads.length(); i++)
+ PR_JoinThread(workerThreads[i]);
+
JS_DestroyRuntime(rt);
JS_ShutDown();
return result;
}
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/extensions/column-numbers.js
@@ -0,0 +1,10 @@
+actual = 'No Error';
+expected = /column-numbers\.js:4:5/;
+try {
+ throw new Error("test");
+}
+catch(ex) {
+ actual = ex.stack;
+ print('Caught exception ' + ex.stack);
+}
+reportMatch(expected, actual, 'column number present');
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -816,17 +816,17 @@ typedef HashSet<GlobalObject *, DefaultH
* Convenience templates to generic constructor and prototype creation functions
* for ClassSpecs.
*/
template<JSNative ctor, size_t atomOffset, unsigned length>
JSObject *
GenericCreateConstructor(JSContext *cx, JSProtoKey key)
{
- JSAtom *atom = AtomStateOffsetToName(cx->runtime()->atomState, atomOffset);
+ JSAtom *atom = AtomStateOffsetToName(cx->names(), atomOffset);
return cx->global()->createConstructor(cx, ctor, atom, length);
}
template<const Class *clasp>
JSObject *
GenericCreatePrototype(JSContext *cx, JSProtoKey key)
{
return cx->global()->createBlankPrototype(cx, clasp);
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -434,17 +434,17 @@ GetElementOperation(JSContext *cx, JSOp
MutableHandleValue res)
{
JS_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
uint32_t index;
if (lref.isString() && IsDefinitelyIndex(rref, &index)) {
JSString *str = lref.toString();
if (index < str->length()) {
- str = cx->runtime()->staticStrings.getUnitStringForElement(cx, str, index);
+ str = cx->staticStrings().getUnitStringForElement(cx, str, index);
if (!str)
return false;
res.setString(str);
return true;
}
}
bool isObject = lref.isObject();
@@ -453,24 +453,24 @@ GetElementOperation(JSContext *cx, JSOp
return false;
return GetObjectElementOperation(cx, op, obj, isObject, rref, res);
}
static MOZ_ALWAYS_INLINE JSString *
TypeOfOperation(const Value &v, JSRuntime *rt)
{
JSType type = js::TypeOfValue(v);
- return TypeName(type, rt->atomState);
+ return TypeName(type, *rt->commonNames);
}
static inline JSString *
TypeOfObjectOperation(JSObject *obj, JSRuntime *rt)
{
JSType type = js::TypeOfObject(obj);
- return TypeName(type, rt->atomState);
+ return TypeName(type, *rt->commonNames);
}
static MOZ_ALWAYS_INLINE bool
InitElemOperation(JSContext *cx, HandleObject obj, HandleValue idval, HandleValue val)
{
JS_ASSERT(!val.isMagic(JS_ELEMENTS_HOLE));
RootedId id(cx);
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -650,20 +650,19 @@ RegExpCompartment::RegExpCompartment(JSR
RegExpCompartment::~RegExpCompartment()
{
JS_ASSERT_IF(map_.initialized(), map_.empty());
JS_ASSERT_IF(inUse_.initialized(), inUse_.empty());
}
JSObject *
-RegExpCompartment::getOrCreateMatchResultTemplateObject(JSContext *cx)
+RegExpCompartment::createMatchResultTemplateObject(JSContext *cx)
{
- if (matchResultTemplateObject_)
- return matchResultTemplateObject_;
+ JS_ASSERT(!matchResultTemplateObject_);
/* Create template array object */
RootedObject templateObject(cx, NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject));
if (!templateObject)
return matchResultTemplateObject_; // = nullptr
/* Set dummy index property */
RootedValue index(cx, Int32Value(0));
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -320,31 +320,37 @@ class RegExpCompartment
/*
* This is the template object where the result of re.exec() is based on,
* if there is a result. This is used in CreateRegExpMatchResult to set
* the input/index properties faster.
*/
ReadBarriered<JSObject> matchResultTemplateObject_;
+ JSObject *createMatchResultTemplateObject(JSContext *cx);
+
public:
RegExpCompartment(JSRuntime *rt);
~RegExpCompartment();
bool init(JSContext *cx);
void sweep(JSRuntime *rt);
void clearTables();
bool get(ExclusiveContext *cx, JSAtom *source, RegExpFlag flags, RegExpGuard *g);
/* Like 'get', but compile 'maybeOpt' (if non-null). */
bool get(JSContext *cx, HandleAtom source, JSString *maybeOpt, RegExpGuard *g);
/* Get or create template object used to base the result of .exec() on. */
- JSObject *getOrCreateMatchResultTemplateObject(JSContext *cx);
+ JSObject *getOrCreateMatchResultTemplateObject(JSContext *cx) {
+ if (matchResultTemplateObject_)
+ return matchResultTemplateObject_;
+ return createMatchResultTemplateObject(cx);
+ }
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
};
class RegExpObject : public JSObject
{
static const unsigned LAST_INDEX_SLOT = 0;
static const unsigned SOURCE_SLOT = 1;
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -104,23 +104,24 @@ PerThreadData::init()
}
static const JSWrapObjectCallbacks DefaultWrapObjectCallbacks = {
TransparentObjectWrapper,
nullptr,
nullptr
};
-JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
+JSRuntime::JSRuntime(JSRuntime *parentRuntime, JSUseHelperThreads useHelperThreads)
: JS::shadow::Runtime(
#ifdef JSGC_GENERATIONAL
&gcStoreBuffer
#endif
),
mainThread(this),
+ parentRuntime(parentRuntime),
interrupt(false),
#if defined(JS_THREADSAFE) && defined(JS_ION)
interruptPar(false),
#endif
handlingSignal(false),
operationCallback(nullptr),
#ifdef JS_THREADSAFE
operationCallbackLock(nullptr),
@@ -270,18 +271,22 @@ JSRuntime::JSRuntime(JSUseHelperThreads
thousandsSeparator(0),
decimalSeparator(0),
numGrouping(0),
#endif
mathCache_(nullptr),
activeCompilations_(0),
keepAtoms_(0),
trustedPrincipals_(nullptr),
+ beingDestroyed_(false),
+ atoms_(nullptr),
atomsCompartment_(nullptr),
- beingDestroyed_(false),
+ staticStrings(nullptr),
+ commonNames(nullptr),
+ permanentAtoms(nullptr),
wrapObjectCallbacks(&DefaultWrapObjectCallbacks),
preserveWrapperCallback(nullptr),
#ifdef DEBUG
noGCOrAllocationCheck(0),
#endif
jitSupportsFloatingPoint(false),
ionPcScriptCache(nullptr),
threadPool(this),
@@ -301,17 +306,16 @@ JSRuntime::JSRuntime(JSUseHelperThreads
liveRuntimesCount++;
setGCMode(JSGC_MODE_GLOBAL);
/* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
JS_INIT_CLIST(&onNewGlobalObjectWatchers);
PodZero(&debugHooks);
- PodZero(&atomState);
PodArrayZero(nativeStackQuota);
PodZero(&asmJSCacheOps);
#if JS_STACK_GROWTH_DIRECTION > 0
nativeStackLimit = UINTPTR_MAX;
#endif
}
@@ -384,19 +388,16 @@ JSRuntime::init(uint32_t maxbytes)
atomsCompartment->isSystem = true;
atomsZone->isSystem = true;
atomsZone->setGCLastBytes(8192, GC_NORMAL);
atomsZone.forget();
this->atomsCompartment_ = atomsCompartment.forget();
- if (!InitAtoms(this))
- return false;
-
if (!scriptDataTable_.init())
return false;
if (!evalCache.init())
return false;
/* The garbage collector depends on everything before this point being initialized. */
gcInitialized = true;
@@ -414,16 +415,20 @@ JSRuntime::init(uint32_t maxbytes)
nativeStackBase = GetNativeStackBase();
jitSupportsFloatingPoint = JitSupportsFloatingPoint();
#ifdef JS_ION
signalHandlersInstalled_ = EnsureAsmJSSignalHandlersInstalled(this);
#endif
+
+ if (!spsProfiler.init())
+ return false;
+
return true;
}
JSRuntime::~JSRuntime()
{
JS_ASSERT(!isHeapBusy());
if (gcInitialized) {
@@ -435,28 +440,25 @@ JSRuntime::~JSRuntime()
* parse tasks. Waiting for AsmJS and compression tasks is done
* synchronously (on the main thread or during parse tasks), so no
* explicit canceling is needed for these.
*/
for (CompartmentsIter comp(this, SkipAtoms); !comp.done(); comp.next())
CancelOffThreadIonCompile(comp, nullptr);
CancelOffThreadParses(this);
- /* Poison common names before final GC. */
- FinishCommonNames(this);
-
/* Clear debugging state to remove GC roots. */
for (CompartmentsIter comp(this, SkipAtoms); !comp.done(); comp.next()) {
comp->clearTraps(defaultFreeOp());
if (WatchpointMap *wpmap = comp->watchpointMap)
wpmap->clear();
}
- /* Clear the statics table to remove GC roots. */
- staticStrings.finish();
+ /* Clear atoms to remove GC roots and heap allocations. */
+ finishAtoms();
/*
* Flag us as being destroyed. This allows the GC to free things like
* interned atoms and Ion trampolines.
*/
beingDestroyed_ = true;
/* Allow the GC to release scripts that were being profiled. */
@@ -506,17 +508,16 @@ JSRuntime::~JSRuntime()
"JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
cxcount, (cxcount == 1) ? "" : "s");
}
#endif
#if !EXPOSE_INTL_API
FinishRuntimeNumberState(this);
#endif
- FinishAtoms(this);
js_FinishGC(this);
atomsCompartment_ = nullptr;
#ifdef JS_THREADSAFE
if (gcLock)
PR_DestroyLock(gcLock);
#endif
@@ -577,17 +578,23 @@ JSRuntime::resetIonStackLimit()
void
JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *rtSizes)
{
// Several tables in the runtime enumerated below can be used off thread.
AutoLockForExclusiveAccess lock(this);
rtSizes->object += mallocSizeOf(this);
- rtSizes->atomsTable += atoms().sizeOfExcludingThis(mallocSizeOf);
+ rtSizes->atomsTable += atoms().sizeOfIncludingThis(mallocSizeOf);
+
+ if (!parentRuntime) {
+ rtSizes->atomsTable += mallocSizeOf(staticStrings);
+ rtSizes->atomsTable += mallocSizeOf(commonNames);
+ rtSizes->atomsTable += permanentAtoms->sizeOfIncludingThis(mallocSizeOf);
+ }
for (ContextIter acx(this); !acx.done(); acx.next())
rtSizes->contexts += acx->sizeOfIncludingThis(mallocSizeOf);
rtSizes->dtoa += mallocSizeOf(mainThread.dtoaState);
rtSizes->temporary += tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -667,16 +667,22 @@ struct JSRuntime : public JS::shadow::Ru
*
* NB: This field is statically asserted to be at offset
* sizeof(js::shadow::Runtime). See
* PerThreadDataFriendFields::getMainThread.
*/
js::PerThreadData mainThread;
/*
+ * If non-null, another runtime guaranteed to outlive this one and whose
+ * permanent data may be used by this one where possible.
+ */
+ JSRuntime *parentRuntime;
+
+ /*
* If true, we've been asked to call the operation callback as soon as
* possible.
*/
mozilla::Atomic<bool, mozilla::Relaxed> interrupt;
#if defined(JS_THREADSAFE) && defined(JS_ION)
/*
* If non-zero, ForkJoin should service an interrupt. This is a separate
@@ -1473,59 +1479,73 @@ struct JSRuntime : public JS::shadow::Ru
}
private:
const JSPrincipals *trustedPrincipals_;
public:
void setTrustedPrincipals(const JSPrincipals *p) { trustedPrincipals_ = p; }
const JSPrincipals *trustedPrincipals() const { return trustedPrincipals_; }
- // Set of all currently-living atoms, and the compartment in which they
- // reside. The atoms compartment is additionally used to hold runtime
- // wide Ion code stubs. These may be modified by threads with an
- // ExclusiveContext and require a lock.
private:
- js::AtomSet atoms_;
- JSCompartment *atomsCompartment_;
bool beingDestroyed_;
public:
+ bool isBeingDestroyed() const {
+ return beingDestroyed_;
+ }
+
+ private:
+ // Set of all atoms other than those in permanentAtoms and staticStrings.
+ // This may be modified by threads with an ExclusiveContext and requires
+ // a lock.
+ js::AtomSet *atoms_;
+
+ // Compartment and associated zone containing all atoms in the runtime,
+ // as well as runtime wide IonCode stubs. The contents of this compartment
+ // may be modified by threads with an ExclusiveContext and requires a lock.
+ JSCompartment *atomsCompartment_;
+
+ public:
+ bool initializeAtoms(JSContext *cx);
+ void finishAtoms();
+
+ void sweepAtoms();
+
js::AtomSet &atoms() {
JS_ASSERT(currentThreadHasExclusiveAccess());
- return atoms_;
+ return *atoms_;
}
JSCompartment *atomsCompartment() {
JS_ASSERT(currentThreadHasExclusiveAccess());
return atomsCompartment_;
}
bool isAtomsCompartment(JSCompartment *comp) {
return comp == atomsCompartment_;
}
- bool isBeingDestroyed() const {
- return beingDestroyed_;
- }
-
// The atoms compartment is the only one in its zone.
inline bool isAtomsZone(JS::Zone *zone);
bool activeGCInAtomsZone();
- union {
- /*
- * Cached pointers to various interned property names, initialized in
- * order from first to last via the other union arm.
- */
- JSAtomState atomState;
+ // Permanent atoms are fixed during initialization of the runtime and are
+ // not modified or collected until the runtime is destroyed. These may be
+ // shared with another, longer living runtime through |parentRuntime| and
+ // can be freely accessed with no locking necessary.
+
+ // Permanent atoms pre-allocated for general use.
+ js::StaticStrings *staticStrings;
- js::FixedHeapPtr<js::PropertyName> firstCachedName;
- };
+ // Cached pointers to various permanent property names.
+ JSAtomState *commonNames;
- /* Tables of strings that are pre-allocated in the atomsCompartment. */
- js::StaticStrings staticStrings;
+ // All permanent atoms in the runtime, other than those in staticStrings.
+ js::AtomSet *permanentAtoms;
+
+ bool transformToPermanentAtoms();
const JSWrapObjectCallbacks *wrapObjectCallbacks;
js::PreserveWrapperCallback preserveWrapperCallback;
// Table of bytecode and other data that may be shared across scripts
// within the runtime. This may be modified by threads with an
// ExclusiveContext and requires a lock.
private:
@@ -1593,17 +1613,17 @@ struct JSRuntime : public JS::shadow::Ru
ionReturnOverride_ = js::MagicValue(JS_ARG_POISON);
return v;
}
void setIonReturnOverride(const js::Value &v) {
JS_ASSERT(!hasIonReturnOverride());
ionReturnOverride_ = v;
}
- JSRuntime(JSUseHelperThreads useHelperThreads);
+ JSRuntime(JSRuntime *parentRuntime, JSUseHelperThreads useHelperThreads);
~JSRuntime();
bool init(uint32_t maxbytes);
JSRuntime *thisFromCtor() { return this; }
void setGCMaxMallocBytes(size_t value);
--- a/js/src/vm/SPSProfiler.cpp
+++ b/js/src/vm/SPSProfiler.cpp
@@ -20,34 +20,42 @@ using namespace js;
using mozilla::DebugOnly;
SPSProfiler::SPSProfiler(JSRuntime *rt)
: rt(rt),
stack_(nullptr),
size_(nullptr),
max_(0),
slowAssertions(false),
- enabled_(false)
+ enabled_(false),
+ lock_(nullptr)
{
JS_ASSERT(rt != nullptr);
+}
+
+bool
+SPSProfiler::init()
+{
#ifdef JS_THREADSAFE
lock_ = PR_NewLock();
if (lock_ == nullptr)
- MOZ_CRASH("Couldn't allocate lock!");
+ return false;
#endif
+ return true;
}
SPSProfiler::~SPSProfiler()
{
if (strings.initialized()) {
for (ProfileStringMap::Enum e(strings); !e.empty(); e.popFront())
js_free(const_cast<char *>(e.front().value()));
}
#ifdef JS_THREADSAFE
- PR_DestroyLock(lock_);
+ if (lock_)
+ PR_DestroyLock(lock_);
#endif
}
void
SPSProfiler::setProfilingStack(ProfileEntry *stack, uint32_t *size, uint32_t max)
{
AutoSPSLock lock(lock_);
JS_ASSERT_IF(size_ && *size_ != 0, !enabled());
--- a/js/src/vm/SPSProfiler.h
+++ b/js/src/vm/SPSProfiler.h
@@ -129,16 +129,18 @@ class SPSProfiler
const char *allocProfileString(JSScript *script, JSFunction *function);
void push(const char *string, void *sp, JSScript *script, jsbytecode *pc);
void pop();
public:
SPSProfiler(JSRuntime *rt);
~SPSProfiler();
+ bool init();
+
uint32_t **addressOfSizePointer() {
return &size_;
}
uint32_t *addressOfMaxSize() {
return &max_;
}
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -99,17 +99,17 @@ js::ScopeCoordinateName(ScopeCoordinateN
Shape::Range<NoGC> r(shape);
while (r.front().slot() != sc.slot())
r.popFront();
id = r.front().propidRaw();
}
/* Beware nameless destructuring formal. */
if (!JSID_IS_ATOM(id))
- return script->runtimeFromAnyThread()->atomState.empty;
+ return script->runtimeFromAnyThread()->commonNames->empty;
return JSID_TO_ATOM(id)->asPropertyName();
}
JSScript *
js::ScopeCoordinateFunctionScript(JSScript *script, jsbytecode *pc)
{
StaticScopeIter<NoGC> ssi(InnermostStaticScope(script, pc));
uint32_t hops = ScopeCoordinate(pc).hops();
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -584,25 +584,25 @@ StaticStrings::init(JSContext *cx)
AutoLockForExclusiveAccess lock(cx);
AutoCompartment ac(cx, cx->runtime()->atomsCompartment());
for (uint32_t i = 0; i < UNIT_STATIC_LIMIT; i++) {
jschar buffer[] = { jschar(i), '\0' };
JSFlatString *s = js_NewStringCopyN<NoGC>(cx, buffer, 1);
if (!s)
return false;
- unitStaticTable[i] = s->morphAtomizedStringIntoAtom();
+ unitStaticTable[i] = s->morphAtomizedStringIntoPermanentAtom();
}
for (uint32_t i = 0; i < NUM_SMALL_CHARS * NUM_SMALL_CHARS; i++) {
jschar buffer[] = { FROM_SMALL_CHAR(i >> 6), FROM_SMALL_CHAR(i & 0x3F), '\0' };
JSFlatString *s = js_NewStringCopyN<NoGC>(cx, buffer, 2);
if (!s)
return false;
- length2StaticTable[i] = s->morphAtomizedStringIntoAtom();
+ length2StaticTable[i] = s->morphAtomizedStringIntoPermanentAtom();
}
for (uint32_t i = 0; i < INT_STATIC_LIMIT; i++) {
if (i < 10) {
intStaticTable[i] = unitStaticTable[i + '0'];
} else if (i < 100) {
size_t index = ((size_t)TO_SMALL_CHAR((i / 10) + '0') << 6) +
TO_SMALL_CHAR((i % 10) + '0');
@@ -610,43 +610,37 @@ StaticStrings::init(JSContext *cx)
} else {
jschar buffer[] = { jschar('0' + (i / 100)),
jschar('0' + ((i / 10) % 10)),
jschar('0' + (i % 10)),
'\0' };
JSFlatString *s = js_NewStringCopyN<NoGC>(cx, buffer, 3);
if (!s)
return false;
- intStaticTable[i] = s->morphAtomizedStringIntoAtom();
+ intStaticTable[i] = s->morphAtomizedStringIntoPermanentAtom();
}
}
return true;
}
void
StaticStrings::trace(JSTracer *trc)
{
/* These strings never change, so barriers are not needed. */
- for (uint32_t i = 0; i < UNIT_STATIC_LIMIT; i++) {
- if (unitStaticTable[i])
- MarkStringUnbarriered(trc, &unitStaticTable[i], "unit-static-string");
- }
+ for (uint32_t i = 0; i < UNIT_STATIC_LIMIT; i++)
+ MarkPermanentAtom(trc, unitStaticTable[i], "unit-static-string");
- for (uint32_t i = 0; i < NUM_SMALL_CHARS * NUM_SMALL_CHARS; i++) {
- if (length2StaticTable[i])
- MarkStringUnbarriered(trc, &length2StaticTable[i], "length2-static-string");
- }
+ for (uint32_t i = 0; i < NUM_SMALL_CHARS * NUM_SMALL_CHARS; i++)
+ MarkPermanentAtom(trc, length2StaticTable[i], "length2-static-string");
/* This may mark some strings more than once, but so be it. */
- for (uint32_t i = 0; i < INT_STATIC_LIMIT; i++) {
- if (intStaticTable[i])
- MarkStringUnbarriered(trc, &intStaticTable[i], "int-static-string");
- }
+ for (uint32_t i = 0; i < INT_STATIC_LIMIT; i++)
+ MarkPermanentAtom(trc, intStaticTable[i], "int-static-string");
}
bool
StaticStrings::isStatic(JSAtom *atom)
{
const jschar *chars = atom->chars();
switch (atom->length()) {
case 1:
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -109,18 +109,20 @@ static const size_t UINT32_CHAR_BUFFER_L
* |
* js::PropertyName - / chars don't contain an index (uint32_t)
*
* Classes marked with (abstract) above are not literally C++ Abstract Base
* Classes (since there are no virtual functions, pure or not, in this
* hierarchy), but have the same meaning: there are no strings with this type as
* its most-derived type.
*
- * Technically, there are three additional most-derived types that satisfy the
- * invariants of more than one of the abovementioned most-derived types:
+ * Atoms can additionally be permanent, i.e. unable to be collected, and can
+ * be combined with other string types to create additional most-derived types
+ * that satisfy the invariants of more than one of the abovementioned
+ * most-derived types:
* - InlineAtom = JSInlineString + JSAtom (atom with inline chars)
* - ShortAtom = JSShortString + JSAtom (atom with (more) inline chars)
*
* Derived string types can be queried from ancestor types via isX() and
* retrieved with asX() debug-only-checked casts.
*
* The ensureX() operations mutate 'this' in place to effectively the type to be
* at least X (e.g., ensureLinear will change a JSRope to be a JSFlatString).
@@ -171,31 +173,30 @@ class JSString : public js::gc::Barriere
*
* The string type encoding can be summarized as follows. The "instance
* encoding" entry for a type specifies the flag bits used to create a
* string instance of that type. Abstract types have no instances and thus
* have no such entry. The "subtype predicate" entry for a type specifies
* the predicate used to query whether a JSString instance is subtype
* (reflexively) of that type.
*
- * Rope 0000 0000
- * Linear - !0000
- * HasBase - xxx1
- * Dependent 0001 0001
- * Flat - isLinear && !isDependent
- * Undepended 0011 0011
- * Extensible 0010 0010
- * Inline 0100 isFlat && !isExtensible && (u1.chars == inlineStorage) || isInt32)
- * Short 0100 header in FINALIZE_SHORT_STRING arena
- * External 0100 header in FINALIZE_EXTERNAL_STRING arena
- * Int32 0110 x110 (NYI, Bug 654190)
- * Atom 1000 1xxx
- * InlineAtom 1000 1000 && is Inline
- * ShortAtom 1000 1000 && is Short
- * Int32Atom 1110 1110 (NYI, Bug 654190)
+ * Rope 0000 0000
+ * Linear - !0000
+ * HasBase - xxx1
+ * Dependent 0001 0001
+ * Flat - isLinear && !isDependent
+ * Undepended 0011 0011
+ * Extensible 0010 0010
+ * Inline 0100 isFlat && !isExtensible && (u1.chars == inlineStorage)
+ * Short 0100 header in FINALIZE_SHORT_STRING arena
+ * External 0100 header in FINALIZE_EXTERNAL_STRING arena
+ * Atom - 1xxx
+ * PermanentAtom 1100 1100
+ * InlineAtom - isAtom && is Inline
+ * ShortAtom - isAtom && is Short
*
* "HasBase" here refers to the two string types that have a 'base' field:
* JSDependentString and JSUndependedString.
* A JSUndependedString is a JSDependentString which has been 'fixed' (by ensureFixed)
* to be null-terminated. In such cases, the string must keep marking its base since
* there may be any number of *other* JSDependentStrings transitively depending on it.
*
*/
@@ -208,18 +209,21 @@ class JSString : public js::gc::Barriere
static const size_t UNDEPENDED_FLAGS = JS_BIT(0) | JS_BIT(1);
static const size_t EXTENSIBLE_FLAGS = JS_BIT(1);
static const size_t FIXED_FLAGS = JS_BIT(2);
static const size_t INT32_MASK = JS_BITMASK(3);
static const size_t INT32_FLAGS = JS_BIT(1) | JS_BIT(2);
static const size_t HAS_BASE_BIT = JS_BIT(0);
+ static const size_t PERMANENT_BIT = JS_BIT(2);
static const size_t ATOM_BIT = JS_BIT(3);
+ static const size_t PERMANENT_ATOM_FLAGS = JS_BIT(2) | JS_BIT(3);
+
static const size_t MAX_LENGTH = JS_BIT(32 - LENGTH_SHIFT) - 1;
size_t buildLengthAndFlags(size_t length, size_t flags) {
JS_ASSERT(length <= MAX_LENGTH);
JS_ASSERT(flags <= FLAGS_MASK);
return (length << LENGTH_SHIFT) | flags;
}
@@ -376,16 +380,21 @@ class JSString : public js::gc::Barriere
}
MOZ_ALWAYS_INLINE
bool isAtom() const {
return (d.lengthAndFlags & ATOM_BIT);
}
MOZ_ALWAYS_INLINE
+ bool isPermanentAtom() const {
+ return (d.lengthAndFlags & FLAGS_MASK) == PERMANENT_ATOM_FLAGS;
+ }
+
+ MOZ_ALWAYS_INLINE
JSAtom &asAtom() const {
JS_ASSERT(isAtom());
return *(JSAtom *)this;
}
/* Only called by the GC for dependent or undepended strings. */
inline bool hasBase() const {
@@ -420,16 +429,34 @@ class JSString : public js::gc::Barriere
static inline js::ThingRootKind rootKind() { return js::THING_ROOT_STRING; }
#ifdef DEBUG
void dump();
static void dumpChars(const jschar *s, size_t len);
bool equals(const char *s);
#endif
+ static MOZ_ALWAYS_INLINE void readBarrier(JSString *thing) {
+#ifdef JSGC_INCREMENTAL
+ if (thing->isPermanentAtom())
+ return;
+
+ js::gc::BarrieredCell<JSString>::readBarrier(thing);
+#endif
+ }
+
+ static MOZ_ALWAYS_INLINE void writeBarrierPre(JSString *thing) {
+#ifdef JSGC_INCREMENTAL
+ if (isNullLike(thing) || thing->isPermanentAtom())
+ return;
+
+ js::gc::BarrieredCell<JSString>::writeBarrierPre(thing);
+#endif
+ }
+
private:
JSString() MOZ_DELETE;
JSString(const JSString &other) MOZ_DELETE;
void operator=(const JSString &other) MOZ_DELETE;
};
class JSRope : public JSString
{
@@ -565,16 +592,20 @@ class JSFlatString : public JSLinearStri
/*
* Once a JSFlatString sub-class has been added to the atom state, this
* operation changes the string to the JSAtom type, in place.
*/
MOZ_ALWAYS_INLINE JSAtom *morphAtomizedStringIntoAtom() {
d.lengthAndFlags = buildLengthAndFlags(length(), ATOM_BIT);
return &asAtom();
}
+ MOZ_ALWAYS_INLINE JSAtom *morphAtomizedStringIntoPermanentAtom() {
+ d.lengthAndFlags = buildLengthAndFlags(length(), PERMANENT_ATOM_FLAGS);
+ return &asAtom();
+ }
inline void finalize(js::FreeOp *fop);
};
JS_STATIC_ASSERT(sizeof(JSFlatString) == sizeof(JSString));
class JSExtensibleString : public JSFlatString
{
@@ -691,16 +722,27 @@ class JSAtom : public JSFlatString
JSAtom &asAtom() const MOZ_DELETE;
public:
/* Returns the PropertyName for this. isIndex() must be false. */
inline js::PropertyName *asPropertyName();
inline void finalize(js::FreeOp *fop);
+ MOZ_ALWAYS_INLINE
+ bool isPermanent() const {
+ return (d.lengthAndFlags & PERMANENT_BIT);
+ }
+
+ // Transform this atom into a permanent atom. This is only done during
+ // initialization of the runtime.
+ MOZ_ALWAYS_INLINE void morphIntoPermanentAtom() {
+ d.lengthAndFlags = buildLengthAndFlags(length(), PERMANENT_ATOM_FLAGS);
+ }
+
#ifdef DEBUG
void dump();
#endif
};
JS_STATIC_ASSERT(sizeof(JSAtom) == sizeof(JSString));
namespace js {
@@ -746,39 +788,30 @@ class StaticStrings
{
private:
/* Bigger chars cannot be in a length-2 string. */
static const size_t SMALL_CHAR_LIMIT = 128U;
static const size_t NUM_SMALL_CHARS = 64U;
JSAtom *length2StaticTable[NUM_SMALL_CHARS * NUM_SMALL_CHARS];
- void clear() {
- mozilla::PodArrayZero(unitStaticTable);
- mozilla::PodArrayZero(length2StaticTable);
- mozilla::PodArrayZero(intStaticTable);
- }
-
public:
/* We keep these public for the JITs. */
static const size_t UNIT_STATIC_LIMIT = 256U;
JSAtom *unitStaticTable[UNIT_STATIC_LIMIT];
static const size_t INT_STATIC_LIMIT = 256U;
JSAtom *intStaticTable[INT_STATIC_LIMIT];
StaticStrings() {
- clear();
+ mozilla::PodZero(this);
}
bool init(JSContext *cx);
void trace(JSTracer *trc);
- void finish() {
- clear();
- }
static bool hasUint(uint32_t u) { return u < INT_STATIC_LIMIT; }
JSAtom *getUint(uint32_t u) {
JS_ASSERT(hasUint(u));
return intStaticTable[u];
}
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2955,17 +2955,17 @@ class XPCJSSourceHook: public js::Source
static const JSWrapObjectCallbacks WrapObjectCallbacks = {
xpc::WrapperFactory::Rewrap,
xpc::WrapperFactory::WrapForSameCompartment,
xpc::WrapperFactory::PrepareForWrapping
};
XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
- : CycleCollectedJSRuntime(32L * 1024L * 1024L, JS_USE_HELPER_THREADS),
+ : CycleCollectedJSRuntime(nullptr, 32L * 1024L * 1024L, JS_USE_HELPER_THREADS),
mJSContextStack(new XPCJSContextStack()),
mCallContext(nullptr),
mAutoRoots(nullptr),
mResolveName(JSID_VOID),
mResolvingWrapper(nullptr),
mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_SIZE)),
mWrappedJSClassMap(IID2WrappedJSClassMap::newMap(XPC_JS_CLASS_MAP_SIZE)),
mIID2NativeInterfaceMap(IID2NativeInterfaceMap::newMap(XPC_NATIVE_INTERFACE_MAP_SIZE)),
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/973390-1.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html style="display: flex;">
+<head>
+<meta charset="UTF-8">
+</head>
+<body style="display: table-cell;"></body>
+</html>
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -422,8 +422,9 @@ pref(layers.force-active,true) load 8596
load 866588.html
load 897852.html
asserts(4-6) load 898913.html # bug 847368
load 931464.html
load 936988-1.html
load 931460-1.html
load 935765-1.html
load 942690.html
+load 973390-1.html
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -2458,19 +2458,16 @@ nsCSSFrameConstructor::ConstructDocEleme
nullptr);
newFrame = frameItems.FirstChild();
NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
}
MOZ_ASSERT(newFrame);
MOZ_ASSERT(contentFrame);
- // set the primary frame
- aDocElement->SetPrimaryFrame(contentFrame);
-
NS_ASSERTION(processChildren ? !mRootElementFrame :
mRootElementFrame == contentFrame,
"unexpected mRootElementFrame");
mRootElementFrame = contentFrame;
// Figure out which frame has the main style for the document element,
// assigning it to mRootElementStyleFrame.
// Backgrounds should be propagated from that frame to the viewport.
@@ -2491,16 +2488,19 @@ nsCSSFrameConstructor::ConstructDocEleme
// Use a null PendingBinding, since our binding is not in fact pending.
ProcessChildren(state, aDocElement, styleContext, contentFrame, true,
childItems, false, nullptr);
// Set the initial child lists
contentFrame->SetInitialChildList(kPrincipalList, childItems);
}
+ // set the primary frame
+ aDocElement->SetPrimaryFrame(contentFrame);
+
SetInitialSingleChild(mDocElementContainingBlock, newFrame);
return newFrame;
}
nsIFrame*
nsCSSFrameConstructor::ConstructRootFrame()
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1212,18 +1212,17 @@ void nsDisplayList::PaintForFrame(nsDisp
aBuilder->FindReferenceFrameFor(aForFrame),
root, mVisibleRect, viewport,
(usingDisplayport ? &displayport : nullptr),
(usingCriticalDisplayport ? &criticalDisplayport : nullptr),
id, isRoot, containerParameters);
if (usingDisplayport &&
!(root->GetContentFlags() & Layer::CONTENT_OPAQUE)) {
// See bug 693938, attachment 567017
- NS_WARNING("We don't support transparent content with displayports, force it to be opqaue");
- root->SetContentFlags(Layer::CONTENT_OPAQUE);
+ NS_WARNING("Transparent content with displayports can be expensive.");
}
layerManager->SetRoot(root);
layerBuilder->WillEndTransaction();
bool temp = aBuilder->SetIsCompositingCheap(layerManager->IsCompositingCheap());
LayerManager::EndTransactionFlags flags = LayerManager::END_DEFAULT;
if (layerManager->NeedsWidgetInvalidation()) {
if (aFlags & PAINT_NO_COMPOSITE) {
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -165,19 +165,16 @@ class RefTest(object):
for v in options.extraPrefs:
thispref = v.split('=')
if len(thispref) < 2:
print "Error: syntax error in --setpref=" + v
sys.exit(1)
prefs[thispref[0]] = mozprofile.Preferences.cast(thispref[1].strip())
- # We need to set this here, see bug 972099
- prefs['gfx.color_management.force_srgb'] = True
-
# install the reftest extension bits into the profile
addons = []
addons.append(os.path.join(SCRIPT_DIRECTORY, "reftest"))
# 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'))
--- a/media/webrtc/moz.build
+++ b/media/webrtc/moz.build
@@ -164,17 +164,16 @@ if CONFIG['MOZ_WEBRTC_SIGNALING']:
'signaling/src/sipcc/core/src-common/util_ios_queue.c',
'signaling/src/sipcc/cpr/android/cpr_android_init.c',
'signaling/src/sipcc/cpr/android/cpr_android_stdio.c',
'signaling/src/sipcc/cpr/android/cpr_android_timers_using_select.c',
'signaling/src/sipcc/cpr/darwin/cpr_darwin_init.c',
'signaling/src/sipcc/cpr/darwin/cpr_darwin_stdio.c',
'signaling/src/sipcc/cpr/darwin/cpr_darwin_timers_using_select.c',
'signaling/src/sipcc/cpr/linux/cpr_linux_init.c',
- 'signaling/src/sipcc/cpr/linux/cpr_linux_ipc.c',
'signaling/src/sipcc/cpr/linux/cpr_linux_stdio.c',
'signaling/src/sipcc/cpr/linux/cpr_linux_timers_using_select.c',
'signaling/src/sipcc/cpr/win32/cpr_win_stdio.c',
'signaling/src/sipcc/cpr/win32/cpr_win_timers.c',
'signaling/src/sipcc/plat/common/dns_utils.c',
'signaling/src/sipcc/plat/csf2g/reset_api.c',
'signaling/src/sipcc/plat/win32/dns_utils.c',
'signaling/src/sipcc/plat/win32/mystub.c',
--- a/media/webrtc/signaling/signaling.gyp
+++ b/media/webrtc/signaling/signaling.gyp
@@ -553,16 +553,17 @@
'./src/sipcc/cpr/include/cpr_stdio.h',
'./src/sipcc/cpr/include/cpr_stdlib.h',
'./src/sipcc/cpr/include/cpr_string.h',
'./src/sipcc/cpr/include/cpr_strings.h',
'./src/sipcc/cpr/include/cpr_threads.h',
'./src/sipcc/cpr/include/cpr_time.h',
'./src/sipcc/cpr/include/cpr_timers.h',
'./src/sipcc/cpr/include/cpr_types.h',
+ './src/sipcc/cpr/common/cpr_ipc.c',
'./src/sipcc/cpr/common/cpr_string.c',
# INCLUDE
'./src/sipcc/include/cc_blf.h',
'./src/sipcc/include/cc_blf_listener.h',
'./src/sipcc/include/cc_call_feature.h',
'./src/sipcc/include/cc_call_listener.h',
'./src/sipcc/include/cc_config.h',
'./src/sipcc/include/cc_constants.h',
@@ -654,29 +655,27 @@
'./src/sipcc/core/sipstack/sip_platform_task.c',
# PLAT
'./src/sipcc/plat/common/dns_utils.c',
# CPR
'./src/sipcc/cpr/android/cpr_android_errno.c',
'./src/sipcc/cpr/android/cpr_android_init.c',
- './src/sipcc/cpr/android/cpr_android_ipc.c',
'./src/sipcc/cpr/android/cpr_android_socket.c',
'./src/sipcc/cpr/android/cpr_android_stdio.c',
'./src/sipcc/cpr/android/cpr_android_string.c',
'./src/sipcc/cpr/android/cpr_android_threads.c',
'./src/sipcc/cpr/android/cpr_android_timers_using_select.c',
'./src/sipcc/cpr/android/cpr_assert.h',
'./src/sipcc/cpr/android/cpr_android_align.h',
'./src/sipcc/cpr/android/cpr_android_assert.h',
'./src/sipcc/cpr/android/cpr_android_errno.h',
'./src/sipcc/cpr/android/cpr_android_in.h',
- './src/sipcc/cpr/android/cpr_darwin_ipc.h',
'./src/sipcc/cpr/android/cpr_android_private.h',
'./src/sipcc/cpr/android/cpr_android_rand.h',
'./src/sipcc/cpr/android/cpr_android_socket.h',
'./src/sipcc/cpr/android/cpr_android_stdio.h',
'./src/sipcc/cpr/android/cpr_android_string.h',
'./src/sipcc/cpr/android/cpr_android_strings.h',
'./src/sipcc/cpr/android/cpr_android_time.h',
'./src/sipcc/cpr/android/cpr_android_timers.h',
@@ -690,29 +689,27 @@
'./src/sipcc/core/sipstack/sip_platform_task.c',
# PLAT
'./src/sipcc/plat/common/dns_utils.c',
# CPR
'./src/sipcc/cpr/linux/cpr_linux_errno.c',
'./src/sipcc/cpr/linux/cpr_linux_init.c',
- './src/sipcc/cpr/linux/cpr_linux_ipc.c',
'./src/sipcc/cpr/linux/cpr_linux_socket.c',
'./src/sipcc/cpr/linux/cpr_linux_stdio.c',
'./src/sipcc/cpr/linux/cpr_linux_string.c',
'./src/sipcc/cpr/linux/cpr_linux_threads.c',
'./src/sipcc/cpr/linux/cpr_linux_timers_using_select.c',
'./src/sipcc/cpr/linux/cpr_assert.h',
'./src/sipcc/cpr/linux/cpr_linux_align.h',
'./src/sipcc/cpr/linux/cpr_linux_assert.h',
'./src/sipcc/cpr/linux/cpr_linux_errno.h',
'./src/sipcc/cpr/linux/cpr_linux_in.h',
- './src/sipcc/cpr/linux/cpr_linux_ipc.h',
'./src/sipcc/cpr/linux/cpr_linux_private.h',
'./src/sipcc/cpr/linux/cpr_linux_rand.h',
'./src/sipcc/cpr/linux/cpr_linux_socket.h',
'./src/sipcc/cpr/linux/cpr_linux_stdio.h',
'./src/sipcc/cpr/linux/cpr_linux_string.h',
'./src/sipcc/cpr/linux/cpr_linux_strings.h',
'./src/sipcc/cpr/linux/cpr_linux_time.h',
'./src/sipcc/cpr/linux/cpr_linux_timers.h',
@@ -740,18 +737,16 @@
'./src/sipcc/cpr/win32/cpr_win_assert.h',
'./src/sipcc/cpr/win32/cpr_win_debug.c',
'./src/sipcc/cpr/win32/cpr_win_debug.h',
'./src/sipcc/cpr/win32/cpr_win_defines.h',
'./src/sipcc/cpr/win32/cpr_win_errno.c',
'./src/sipcc/cpr/win32/cpr_win_errno.h',
'./src/sipcc/cpr/win32/cpr_win_in.h',
'./src/sipcc/cpr/win32/cpr_win_init.c',
- './src/sipcc/cpr/win32/cpr_win_ipc.c',
- './src/sipcc/cpr/win32/cpr_win_ipc.h',
'./src/sipcc/cpr/win32/cpr_win_locks.c',
'./src/sipcc/cpr/win32/cpr_win_locks.h',
'./src/sipcc/cpr/win32/cpr_win_rand.c',
'./src/sipcc/cpr/win32/cpr_win_rand.h',
'./src/sipcc/cpr/win32/cpr_win_socket.c',
'./src/sipcc/cpr/win32/cpr_win_socket.h',
'./src/sipcc/cpr/win32/cpr_win_stdio.c',
'./src/sipcc/cpr/win32/cpr_win_stdio.h',
@@ -796,18 +791,16 @@
#'./src/sipcc/plat/unix-common/random.c',
# CPR
'./src/sipcc/cpr/darwin/cpr_darwin_assert.h',
'./src/sipcc/cpr/darwin/cpr_darwin_errno.c',
'./src/sipcc/cpr/darwin/cpr_darwin_errno.h',
'./src/sipcc/cpr/darwin/cpr_darwin_in.h',
'./src/sipcc/cpr/darwin/cpr_darwin_init.c',
- './src/sipcc/cpr/darwin/cpr_darwin_ipc.c',
- './src/sipcc/cpr/darwin/cpr_darwin_ipc.h',
'./src/sipcc/cpr/darwin/cpr_darwin_private.h',
'./src/sipcc/cpr/darwin/cpr_darwin_rand.h',
'./src/sipcc/cpr/darwin/cpr_darwin_socket.c',
'./src/sipcc/cpr/darwin/cpr_darwin_socket.h',
'./src/sipcc/cpr/darwin/cpr_darwin_stdio.c',
'./src/sipcc/cpr/darwin/cpr_darwin_stdio.h',
'./src/sipcc/cpr/darwin/cpr_darwin_string.c',
'./src/sipcc/cpr/darwin/cpr_darwin_string.h',
deleted file mode 100644
--- a/media/webrtc/signaling/src/sipcc/cpr/android/cpr_android_ipc.c
+++ /dev/null
@@ -1,601 +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/. */
-
-#include "cpr.h"
-#include "cpr_stdlib.h"
-#include <cpr_stdio.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <time.h>
-#include <plat_api.h>
-#include "cpr_string.h"
-
-/*
- * If building with debug test interface,
- * allow access to internal CPR functions
- */
-#define STATIC static
-
-#define OS_MSGTQL 31 /* need to check number for MV linux and put here */
-
-/*
- * Internal CPR API
- */
-extern pthread_t cprGetThreadId(cprThread_t thread);
-
-/*
- * Extended internal message queue node
- *
- * A double-linked list holding the nessasary message information
- */
-typedef struct cpr_msgq_node_s
-{
- struct cpr_msgq_node_s *next;
- struct cpr_msgq_node_s *prev;
- void *msg;
- void *pUserData;
-} cpr_msgq_node_t;
-
-/*
- * Msg queue information needed to hide OS differences in implementation.
- * To use msg queues, the application code may pass in a name to the
- * create function for msg queues. CPR does not use this field, it is
- * solely for the convenience of the application and to aid in debugging.
- *
- * Note: Statistics are not protected by a mutex; therefore, there exists
- * the possibility that the results may not be accurate.
- *
- * Note:if the depth supplied by OS is insufficient,a message queue owner may
- * increase the message queue depth via cprCreateMessageQueue's depth
- * parameter where the value can range from MSGTQL to CPR_MAX_MSG_Q_DEPTH.
- */
-typedef struct cpr_msg_queue_s
-{
- struct cpr_msg_queue_s *next;
- const char *name;
- pthread_t thread;
- int32_t queueId;
- uint16_t currentCount;
- uint32_t totalCount;
- uint32_t sendErrors;
- uint32_t reTries;
- uint32_t highAttempts;
- uint32_t selfQErrors;
- uint16_t extendedQDepth;
- uint16_t maxExtendedQDepth;
- pthread_mutex_t mutex; /* lock for managing extended queue */
- pthread_cond_t cond; /* signal for queue/dequeue */
- cpr_msgq_node_t *head; /* extended queue head (newest element) */
- cpr_msgq_node_t *tail; /* extended queue tail (oldest element) */
-} cpr_msg_queue_t;
-
-/*
- * A enumeration used to report the result of posting a message to
- * a message queue
- */
-typedef enum
-{
- CPR_MSGQ_POST_SUCCESS,
- CPR_MSGQ_POST_FAILED,
- CPR_MSGQ_POST_PENDING
-} cpr_msgq_post_result_e;
-
-
-/*
- * Head of list of message queues
- */
-static cpr_msg_queue_t *msgQueueList = NULL;
-
-/*
- * Mutex to manage message queue list
- */
-pthread_mutex_t msgQueueListMutex;
-
-/*
- * String to represent message queue name when it is not provided
- */
-static const char unnamed_string[] = "unnamed";
-
-
-/*
- * CPR_MAX_MSG_Q_DEPTH
- *
- * The maximum queue depth supported by the CPR layer. This value
- * is arbitrary though the purpose is to limit the memory usage
- * by CPR and avoid (nearly) unbounded situations.
- *
- * Note: This value should be greater than MSGTQL which is currently
- * defined as 31
- */
-#define CPR_MAX_MSG_Q_DEPTH 256
-
-/*
- * CPR_SND_TIMEOUT_WAIT_INTERVAL
- *
- * The interval of time to wait in milliseconds between attempts to
- * send a message to the message queue
- *
- * Note: 20 ms. to avoid less than a tick wake up since on most
- * OSes 10ms is one 1 tick
- * this should really be OS_TICK_MS * 2 or OS_TICK_MS + X
- */
-#define CPR_SND_TIMEOUT_WAIT_INTERVAL 20
-
-/*
- * CPR_ATTEMPTS_TO_SEND
- *
- * The number of attempts made to send a message when the message
- * would otherwise be blocked. Note in this condition the thread
- * will sleep the timeout interval to allow the msg queue to be
- * drained.
- *
- * Note: 25 attempts for upto .5 seconds at the interval of
- * CPR_SND_TIMEOUT_WAIT_INTERVAL worst case.
- */
-#define CPR_ATTEMPTS_TO_SEND 25
-
-/*
- * Also, important to note that the total timeout interval must be
- * greater than the SIP's select call timeout value which is 25msec.
- * This is necessary to cover the case where the SIP message queue
- * is full and the select timeout occurs.
- *
- * Total timeout interval = CPR_SND_TIMEOUT_WAIT_INTERVAL *
- * CPR_ATTEMPTS_TO_SEND;
- */
-
-
-/*
- * Prototype declarations
- */
-static cpr_msgq_post_result_e
-cprPostMessage(cpr_msg_queue_t *msgq, void *msg, void **ppUserData);
-static void
-cprPegSendMessageStats(cpr_msg_queue_t *msgq, uint16_t numAttempts);
-
-
-/*
- * Functions
- */
-
-/**
- * Creates a message queue
- *
- * @param name - name of the message queue
- * @param depth - the message queue depth, optional field which will
- * default if set to zero(0)
- *
- * @return Msg queue handle or NULL if init failed, errno provided
- *
- * @note the actual message queue depth will be bounded by the
- * standard system message queue depth and CPR_MAX_MSG_Q_DEPTH.
- * If 'depth' is outside of the bounds, the value will be
- * reset automatically.
- */
-cprMsgQueue_t
-cprCreateMessageQueue (const char *name, uint16_t depth)
-{
- static const char fname[] = "cprCreateMessageQueue";
- cpr_msg_queue_t *msgq;
- static int key_id = 100; /* arbitrary starting number */
- pthread_cond_t _cond = PTHREAD_COND_INITIALIZER;
- pthread_mutex_t _lock = PTHREAD_MUTEX_INITIALIZER;
-
- msgq = cpr_calloc(1, sizeof(cpr_msg_queue_t));
- if (msgq == NULL) {
- printf("%s: Malloc failed: %s\n", fname,
- name ? name : unnamed_string);
- errno = ENOMEM;
- return NULL;
- }
-
- msgq->name = name ? name : unnamed_string;
- msgq->queueId = key_id++;
- msgq->cond = _cond;
- msgq->mutex = _lock;
-
- /*
- * Add message queue to list for statistics reporting
- */
- pthread_mutex_lock(&msgQueueListMutex);
- msgq->next = msgQueueList;
- msgQueueList = msgq;
- pthread_mutex_unlock(&msgQueueListMutex);
-
- return msgq;
-}
-
-
-/**
- * Removes all messages from the queue and then destroy the message queue
- *
- * @param msgQueue - message queue to destroy
- *
- * @return CPR_SUCCESS or CPR_FAILURE, errno provided
- */
-cprRC_t
-cprDestroyMessageQueue (cprMsgQueue_t msgQueue)
-{
- static const char fname[] = "cprDestroyMessageQueue";
- cpr_msg_queue_t *msgq;
- void *msg;
-
- msgq = (cpr_msg_queue_t *) msgQueue;
- if (msgq == NULL) {
- /* Bad application! */
- CPR_ERROR("%s: Invalid input\n", fname);
- errno = EINVAL;
- return CPR_FAILURE;
- }
-
- /* Drain message queue */
- msg = cprGetMessage(msgQueue, FALSE, NULL);
- while (msg != NULL) {
- cpr_free(msg);
- msg = cprGetMessage(msgQueue, FALSE, NULL);
- }
-
- /* Remove message queue from list */
- pthread_mutex_lock(&msgQueueListMutex);
- if (msgq == msgQueueList) {
- msgQueueList = msgq->next;
- } else {
- cpr_msg_queue_t *msgql = msgQueueList;
-
- while ((msgql->next != NULL) && (msgql->next != msgq)) {
- msgql = msgql->next;
- }
- if (msgql->next == msgq) {
- msgql->next = msgq->next;
- }
- }
- pthread_mutex_unlock(&msgQueueListMutex);
-
- /* Remove message queue mutex */
- if (pthread_mutex_destroy(&msgq->mutex) != 0) {
- CPR_ERROR("%s: Failed to destroy msg queue (%s) mutex: %d\n",
- fname, msgq->name, errno);
- }
-
- cpr_free(msgq);
- return CPR_SUCCESS;
-}
-
-
-/**
- * Associate a thread with the message queue
- *
- * @param msgQueue - msg queue to set
- * @param thread - CPR thread to associate with queue
- *
- * @return CPR_SUCCESS or CPR_FAILURE
- *
- * @note Nothing is done to prevent overwriting the thread ID
- * when the value has already been set.
- */
-cprRC_t
-cprSetMessageQueueThread (cprMsgQueue_t msgQueue, cprThread_t thread)
-{
- static const char fname[] = "cprSetMessageQueueThread";
- cpr_msg_queue_t *msgq;
-
- if ((!msgQueue) || (!thread)) {
- CPR_ERROR("%s: Invalid input\n", fname);
- return CPR_FAILURE;
- }
-
- msgq = (cpr_msg_queue_t *) msgQueue;
- if (msgq->thread != 0) {
- CPR_ERROR("%s: over-writing previously msgq thread name for %s",
- fname, msgq->name);
- }
-
- msgq->thread = cprGetThreadId(thread);
- return CPR_SUCCESS;
-}
-
-
-/**
- * Retrieve a message from a particular message queue
- *
- * @param[in] msgQueue - msg queue from which to retrieve the message
- * @param[in] waitForever - boolean to either wait forever (TRUE) or not
- * wait at all (FALSE) if the msg queue is empty.
- * @param[out] ppUserData - pointer to a pointer to user defined data
- *
- * @return Retrieved message buffer or NULL if failure occurred or
- * the waitForever flag was set to false and no messages were
- * on the queue.
- *
- * @note If ppUserData is defined, the value will be initialized to NULL
- */
-void *
-cprGetMessage (cprMsgQueue_t msgQueue, boolean waitForever, void **ppUserData)
-{
- static const char fname[] = "cprGetMessage";
-
- void *buffer = 0;
- cpr_msg_queue_t *msgq;
- cpr_msgq_node_t *node;
- struct timespec timeout;
- struct timeval tv;
- struct timezone tz;
-
- /* Initialize ppUserData */
- if (ppUserData) {
- *ppUserData = NULL;
- }
-
- msgq = (cpr_msg_queue_t *) msgQueue;
- if (msgq == NULL) {
- /* Bad application! */
- CPR_ERROR("%s: Invalid input\n", fname);
- errno = EINVAL;
- return NULL;
- }
-
- /*
- * If waitForever is set, block on the message queue
- * until a message is received, else return after
- * 25msec of waiting
- */
- pthread_mutex_lock(&msgq->mutex);
-
- if (!waitForever)
- {
- // We'll wait till 25uSec from now
- gettimeofday(&tv, &tz);
- timeout.tv_nsec = (tv.tv_usec * 1000) + 25000;
- timeout.tv_sec = tv.tv_sec;
-
- pthread_cond_timedwait(&msgq->cond, &msgq->mutex, &timeout);
- }
- else
- {
- while(msgq->tail==NULL)
- {
- pthread_cond_wait(&msgq->cond, &msgq->mutex);
- }
- }
-
- // If there is a message on the queue, de-queue it
- if (msgq->tail)
- {
- node = msgq->tail;
- msgq->tail = node->prev;
- if (msgq->tail) {
- msgq->tail->next = NULL;
- }
- if (msgq->head == node) {
- msgq->head = NULL;
- }
- msgq->currentCount--;
- /*
- * Pull out the data
- */
- if (ppUserData) {
- *ppUserData = node->pUserData;
- }
- buffer = node->msg;
-
- }
-
- pthread_mutex_unlock(&msgq->mutex);
-
- return buffer;
-}
-
-
-/**
- * Place a message on a particular queue. Note that caller may
- * block (see comments below)
- *
- * @param msgQueue - msg queue on which to place the message
- * @param msg - pointer to the msg to place on the queue
- * @param ppUserData - pointer to a pointer to user defined data
- *
- * @return CPR_SUCCESS or CPR_FAILURE, errno provided
- *
- * @note 1. Messages queues are set to be non-blocking, those cases
- * where the system call fails with a would-block error code
- * (EAGAIN) the function will attempt other mechanisms described
- * below.
- * @note 2. If enabled with an extended message queue, either via a
- * call to cprCreateMessageQueue with depth value or a call to
- * cprSetExtendMessageQueueDepth() (when unit testing), the message
- * will be added to the extended message queue and the call will
- * return successfully. When room becomes available on the
- * system's message queue, those messages will be added.
- * @note 3. If the message queue becomes full and no space is availabe
- * on the extended message queue, then the function will attempt
- * to resend the message up to CPR_ATTEMPTS_TO_SEND and the
- * calling thread will *BLOCK* CPR_SND_TIMEOUT_WAIT_INTERVAL
- * milliseconds after each failed attempt. If unsuccessful
- * after all attempts then EGAIN error code is returned.
- * @note 4. This applies to all CPR threads, including the timer thread.
- * So it is possible that the timer thread would be forced to
- * sleep which would have the effect of delaying all active
- * timers. The work to fix this rare situation is not considered
- * worth the effort to fix....so just leaving as is.
- */
-cprRC_t
-cprSendMessage (cprMsgQueue_t msgQueue, void *msg, void **ppUserData)
-{
- static const char fname[] = "cprSendMessage";
- static const char error_str[] = "%s: Msg not sent to %s queue: %s\n";
- cpr_msgq_post_result_e rc;
- cpr_msg_queue_t *msgq;
- int16_t attemptsToSend = CPR_ATTEMPTS_TO_SEND;
- uint16_t numAttempts = 0;
-
- /* Bad application? */
- if (msgQueue == NULL) {
- CPR_ERROR(error_str, fname, "undefined", "invalid input");
- errno = EINVAL;
- return CPR_FAILURE;
- }
-
- msgq = (cpr_msg_queue_t *) msgQueue;
-
- /*
- * Attempt to send message
- */
- do {
-
- /*
- * Post the message to the Queue
- */
- rc = cprPostMessage(msgq, msg, ppUserData);
-
- if (rc == CPR_MSGQ_POST_SUCCESS) {
- cprPegSendMessageStats(msgq, numAttempts);
- return CPR_SUCCESS;
- } else if (rc == CPR_MSGQ_POST_FAILED) {
- CPR_ERROR("%s: Msg not sent to %s queue: %d\n",
- fname, msgq->name, errno);
- msgq->sendErrors++;
- /*
- * If posting to calling thread's own queue,
- * then peg the self queue error.
- */
- if (pthread_self() == msgq->thread) {
- msgq->selfQErrors++;
- }
-
- return CPR_FAILURE;
- }
-
-
- /*
- * Did not succeed in sending the message, so continue
- * to attempt up to the CPR_ATTEMPTS_TO_SEND.
- */
- attemptsToSend--;
- if (attemptsToSend > 0) {
- /*
- * Force a context-switch of the thread attempting to
- * send the message, in order to help the case where
- * the msg queue is full and the owning thread may get
- * a a chance be scheduled so it can drain it (Note:
- * no guarantees, more of a "last-ditch effort" to
- * recover...especially when temporarily over-whelmed).
- */
- cprSleep(CPR_SND_TIMEOUT_WAIT_INTERVAL);
- msgq->reTries++;
- numAttempts++;
- }
- } while (attemptsToSend > 0);
-
- CPR_ERROR(error_str, fname, msgq->name, "FULL");
- msgq->sendErrors++;
- return CPR_FAILURE;
-}
-
-/**
- * Peg the statistics for successfully posting a message
- *
- * @param msgq - message queue
- * @param numAttempts - number of attempts to post message to message queue
- *
- * @return none
- *
- * @pre (msgq not_eq NULL)
- */
-static void
-cprPegSendMessageStats (cpr_msg_queue_t *msgq, uint16_t numAttempts)
-{
- /*
- * Collect statistics
- */
- msgq->totalCount++;
-
- if (numAttempts > msgq->highAttempts) {
- msgq->highAttempts = numAttempts;
- }
-}
-
-/**
- * Post message to system message queue
- *
- * @param msgq - message queue
- * @param msg - message to post
- * @param ppUserData - ptr to ptr to option user data
- *
- * @return the post result which is CPR_MSGQ_POST_SUCCESS,
- * CPR_MSGQ_POST_FAILURE or CPR_MSGQ_POST_PENDING
- *
- * @pre (msgq not_eq NULL)
- * @pre (msg not_eq NULL)
- */
-static cpr_msgq_post_result_e
-cprPostMessage (cpr_msg_queue_t *msgq, void *msg, void **ppUserData)
-{
- cpr_msgq_node_t *node;
-
- /*
- * Allocate new message queue node
- */
- node = cpr_malloc(sizeof(*node));
- if (!node) {
- errno = ENOMEM;
- return CPR_MSGQ_POST_FAILED;
- }
-
- pthread_mutex_lock(&msgq->mutex);
-
- /*
- * Fill in data
- */
- node->msg = msg;
- if (ppUserData != NULL) {
- node->pUserData = *ppUserData;
- } else {
- node->pUserData = NULL;
- }
-
- /*
- * Push onto list
- */
- node->prev = NULL;
- node->next = msgq->head;
- msgq->head = node;
-
- if (node->next) {
- node->next->prev = node;
- }
-
- if (msgq->tail == NULL) {
- msgq->tail = node;
- }
- msgq->currentCount++;
-
- pthread_cond_signal(&msgq->cond);
- pthread_mutex_unlock(&msgq->mutex);
-
- return CPR_MSGQ_POST_SUCCESS;
-
-}
-
-
-/**
- * cprGetDepth
- *
- * @brief get depth of a message queue
- *
- * The pSIPCC uses this API to look at the depth of a message queue for internal
- * routing and throttling decision
- *
- * @param[in] msgQueue - message queue
- *
- * @return depth of msgQueue
- *
- * @pre (msgQueue not_eq NULL)
- */
-uint16_t cprGetDepth (cprMsgQueue_t msgQueue)
-{
- cpr_msg_queue_t *msgq;
- msgq = (cpr_msg_queue_t *) msgQueue;
- return msgq->currentCount;
-}
-
deleted file mode 100644
--- a/media/webrtc/signaling/src/sipcc/cpr/android/cpr_android_ipc.h
+++ /dev/null
@@ -1,55 +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/. */
-
-#ifndef _CPR_CNU_IPC_H_
-#define _CPR_CNU_IPC_H_
-
-#include "cpr_threads.h"
-#include <pthread.h>
-
-/* Enable support for cprSetMessageQueueThread API */
-#define CPR_USE_SET_MESSAGE_QUEUE_THREAD
-
-/* Maximum message size allowed by CNU */
-#define CPR_MAX_MSG_SIZE 8192
-
-/* Our CNU msgtype */
-#define CPR_IPC_MSG 1
-
-
-/* Message buffer layout */
-struct msgbuffer {
- long mtype; /* Message type */
- void *msgPtr; /* Ptr to msg */
- void *usrPtr; /* Ptr to user data */
-};
-
-/* For gathering statistics regarding message queues */
-typedef struct {
- char name[16];
- uint16_t currentCount;
- uint32_t totalCount;
- uint32_t rcvTimeouts;
- uint32_t sendErrors;
- uint32_t reTries;
- uint32_t highAttempts;
- uint32_t selfQErrors;
- uint16_t extendedDepth;
-} cprMsgQueueStats_t;
-
-
-/*
- * Mutex for updating the message queue list
- */
-extern pthread_mutex_t msgQueueListMutex;
-
-
-/**
- * cprGetDepth
- *
- * Get depth of a message queue
- */
-uint16_t cprGetDepth(cprMsgQueue_t msgQueue);
-
-#endif
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/sipcc/cpr/common/cpr_ipc.c
@@ -0,0 +1,685 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cpr.h"
+#include "cpr_stdlib.h"
+#include "cpr_stdio.h"
+#include "plat_api.h"
+#include "cpr_string.h"
+
+#ifdef SIP_OS_WINDOWS
+#include <windows.h>
+#include <process.h>
+#include <winuser.h>
+#else
+#include <errno.h>
+#include <sys/time.h>
+#include <time.h>
+#endif /* SIP_OS_WINDOWS */
+
+
+#ifdef SIP_OS_WINDOWS
+extern cprMsgQueue_t sip_msgq;
+extern cprMsgQueue_t gsm_msgq;
+extern cprMsgQueue_t tmr_msgq;
+
+extern void gsm_shutdown();
+extern void sip_shutdown();
+
+/*
+ * Buffer to hold the messages sent/received by CPR. All
+ * CPR does is pass four bytes (CNU msg type) and an unsigned
+ * four bytes (pointer to the msg buffer).
+ */
+static char rcvBuffer[100];
+#define MSG_BUF 0xF000
+
+#else
+
+#define OS_MSGTQL 31 /* need to check number for MV linux and put here */
+
+/*
+ * Internal CPR API
+ */
+extern pthread_t cprGetThreadId(cprThread_t thread);
+
+
+/*
+ * Extended internal message queue node
+ *
+ * A double-linked list holding the nessasary message information
+ */
+typedef struct cpr_msgq_node_s
+{
+ struct cpr_msgq_node_s *next;
+ struct cpr_msgq_node_s *prev;
+ void *msg;
+ void *pUserData;
+} cpr_msgq_node_t;
+
+/*
+ * Msg queue information needed to hide OS differences in implementation.
+ * To use msg queues, the application code may pass in a name to the
+ * create function for msg queues. CPR does not use this field, it is
+ * solely for the convenience of the application and to aid in debugging.
+ *
+ * Note: Statistics are not protected by a mutex; therefore, there exists
+ * the possibility that the results may not be accurate.
+ *
+ * Note:if the depth supplied by OS is insufficient,a message queue owner may
+ * increase the message queue depth via cprCreateMessageQueue's depth
+ * parameter where the value can range from MSGTQL to CPR_MAX_MSG_Q_DEPTH.
+ */
+typedef struct cpr_msg_queue_s
+{
+ struct cpr_msg_queue_s *next;
+ const char *name;
+ pthread_t thread;
+ int32_t queueId;
+ uint16_t currentCount;
+ uint32_t totalCount;
+ uint32_t sendErrors;
+ uint32_t reTries;
+ uint32_t highAttempts;
+ uint32_t selfQErrors;
+ uint16_t extendedQDepth;
+ uint16_t maxExtendedQDepth;
+ pthread_mutex_t mutex; /* lock for managing extended queue */
+ pthread_cond_t cond; /* signal for queue/dequeue */
+ cpr_msgq_node_t *head; /* extended queue head (newest element) */
+ cpr_msgq_node_t *tail; /* extended queue tail (oldest element) */
+} cpr_msg_queue_t;
+
+/*
+ * A enumeration used to report the result of posting a message to
+ * a message queue
+ */
+typedef enum
+{
+ CPR_MSGQ_POST_SUCCESS,
+ CPR_MSGQ_POST_FAILED,
+ CPR_MSGQ_POST_PENDING
+} cpr_msgq_post_result_e;
+
+
+/*
+ * Head of list of message queues
+ */
+static cpr_msg_queue_t *msgQueueList = NULL;
+
+/*
+ * Mutex to manage message queue list
+ */
+pthread_mutex_t msgQueueListMutex;
+
+/*
+ * CPR_MAX_MSG_Q_DEPTH
+ *
+ * The maximum queue depth supported by the CPR layer. This value
+ * is arbitrary though the purpose is to limit the memory usage
+ * by CPR and avoid (nearly) unbounded situations.
+ *
+ * Note: This value should be greater than MSGTQL which is currently
+ * defined as 31
+ */
+#define CPR_MAX_MSG_Q_DEPTH 256
+
+/*
+ * CPR_SND_TIMEOUT_WAIT_INTERVAL
+ *
+ * The interval of time to wait in milliseconds between attempts to
+ * send a message to the message queue
+ *
+ * Note: 20 ms. to avoid less than a tick wake up since on most
+ * OSes 10ms is one 1 tick
+ * this should really be OS_TICK_MS * 2 or OS_TICK_MS + X
+ */
+#define CPR_SND_TIMEOUT_WAIT_INTERVAL 20
+
+/*
+ * CPR_ATTEMPTS_TO_SEND
+ *
+ * The number of attempts made to send a message when the message
+ * would otherwise be blocked. Note in this condition the thread
+ * will sleep the timeout interval to allow the msg queue to be
+ * drained.
+ *
+ * Note: 25 attempts for upto .5 seconds at the interval of
+ * CPR_SND_TIMEOUT_WAIT_INTERVAL worst case.
+ */
+#define CPR_ATTEMPTS_TO_SEND 25
+
+/*
+ * Also, important to note that the total timeout interval must be
+ * greater than the SIP's select call timeout value which is 25msec.
+ * This is necessary to cover the case where the SIP message queue
+ * is full and the select timeout occurs.
+ *
+ * Total timeout interval = CPR_SND_TIMEOUT_WAIT_INTERVAL *
+ * CPR_ATTEMPTS_TO_SEND;
+ */
+
+
+/**
+ * Peg the statistics for successfully posting a message
+ *
+ * @param msgq - message queue
+ * @param numAttempts - number of attempts to post message to message queue
+ *
+ * @return none
+ *
+ * @pre (msgq not_eq NULL)
+ */
+static void
+cprPegSendMessageStats (cpr_msg_queue_t *msgq, uint16_t numAttempts)
+{
+ /*
+ * Collect statistics
+ */
+ msgq->totalCount++;
+
+ if (numAttempts > msgq->highAttempts) {
+ msgq->highAttempts = numAttempts;
+ }
+}
+
+/**
+ * Post message to system message queue
+ *
+ * @param msgq - message queue
+ * @param msg - message to post
+ * @param ppUserData - ptr to ptr to option user data
+ *
+ * @return the post result which is CPR_MSGQ_POST_SUCCESS,
+ * CPR_MSGQ_POST_FAILURE or CPR_MSGQ_POST_PENDING
+ *
+ * @pre (msgq not_eq NULL)
+ * @pre (msg not_eq NULL)
+ */
+static cpr_msgq_post_result_e
+cprPostMessage (cpr_msg_queue_t *msgq, void *msg, void **ppUserData)
+{
+ cpr_msgq_node_t *node;
+
+ /*
+ * Allocate new message queue node
+ */
+ node = cpr_malloc(sizeof(*node));
+ if (!node) {
+ errno = ENOMEM;
+ return CPR_MSGQ_POST_FAILED;
+ }
+
+ pthread_mutex_lock(&msgq->mutex);
+
+ /*
+ * Fill in data
+ */
+ node->msg = msg;
+ if (ppUserData != NULL) {
+ node->pUserData = *ppUserData;
+ } else {
+ node->pUserData = NULL;
+ }
+
+ /*
+ * Push onto list
+ */
+ node->prev = NULL;
+ node->next = msgq->head;
+ msgq->head = node;
+
+ if (node->next) {
+ node->next->prev = node;
+ }
+
+ if (msgq->tail == NULL) {
+ msgq->tail = node;
+ }
+ msgq->currentCount++;
+
+ pthread_cond_signal(&msgq->cond);
+ pthread_mutex_unlock(&msgq->mutex);
+
+ return CPR_MSGQ_POST_SUCCESS;
+
+}
+#endif /* !SIP_OS_WINDOWS */
+
+/*
+ * Functions
+ */
+
+/**
+ * Creates a message queue
+ *
+ * @param name - name of the message queue
+ * @param depth - the message queue depth, optional field which will
+ * default if set to zero(0). This parameter is currently
+ * not supported on Windows.
+ *
+ * @return Msg queue handle or NULL if init failed, errno provided
+ *
+ * @note the actual message queue depth will be bounded by the
+ * standard system message queue depth and CPR_MAX_MSG_Q_DEPTH.
+ * If 'depth' is outside of the bounds, the value will be
+ * reset automatically.
+ */
+cprMsgQueue_t
+cprCreateMessageQueue (const char *name, uint16_t depth)
+{
+ cpr_msg_queue_t *msgq;
+
+ msgq = cpr_calloc(1, sizeof(cpr_msg_queue_t));
+ if (msgq == NULL) {
+ printf("%s: Malloc failed: %s\n", __FUNCTION__,
+ name ? name : "unnamed");
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ msgq->name = name ? name : "unnamed";
+
+#ifndef SIP_OS_WINDOWS
+ static int key_id = 100; /* arbitrary starting number */
+ pthread_cond_t _cond = PTHREAD_COND_INITIALIZER;
+ pthread_mutex_t _lock = PTHREAD_MUTEX_INITIALIZER;
+
+ msgq->queueId = key_id++;
+ msgq->cond = _cond;
+ msgq->mutex = _lock;
+
+ /*
+ * Add message queue to list for statistics reporting
+ */
+ pthread_mutex_lock(&msgQueueListMutex);
+ msgq->next = msgQueueList;
+ msgQueueList = msgq;
+ pthread_mutex_unlock(&msgQueueListMutex);
+#endif /* SIP_OS_WINDOWS */
+
+ return msgq;
+}
+
+
+
+/**
+ * Associate a thread with the message queue
+ *
+ * @param msgQueue - msg queue to set
+ * @param thread - CPR thread to associate with queue
+ *
+ * @return CPR_SUCCESS or CPR_FAILURE
+ *
+ * @note Nothing is done to prevent overwriting the thread ID
+ * when the value has already been set.
+ */
+cprRC_t
+cprSetMessageQueueThread (cprMsgQueue_t msgQueue, cprThread_t thread)
+{
+ cpr_msg_queue_t *msgq;
+
+ if ((!msgQueue) || (!thread)) {
+ CPR_ERROR("%s: Invalid input\n", __FUNCTION__);
+ return CPR_FAILURE;
+ }
+
+#ifdef SIP_OS_WINDOWS
+ ((cpr_msg_queue_t *)msgQueue)->handlePtr = thread;
+#else
+ msgq = (cpr_msg_queue_t *) msgQueue;
+ if (msgq->thread != 0) {
+ CPR_ERROR("%s: over-writing previously msgq thread name for %s",
+ __FUNCTION__, msgq->name);
+ }
+
+ msgq->thread = cprGetThreadId(thread);
+#endif /* SIP_OS_WINDOWS */
+
+ return CPR_SUCCESS;
+}
+
+
+/**
+ * Retrieve a message from a particular message queue
+ *
+ * @param[in] msgQueue - msg queue from which to retrieve the message
+ * @param[in] waitForever - boolean to either wait forever (TRUE) or not
+ * wait at all (FALSE) if the msg queue is empty.
+ * @param[out] ppUserData - pointer to a pointer to user defined data
+ *
+ * @return Retrieved message buffer or NULL if failure occurred or
+ * the waitForever flag was set to false and no messages were
+ * on the queue.
+ *
+ * @note If ppUserData is defined, the value will be initialized to NULL
+ */
+void *
+cprGetMessage (cprMsgQueue_t msgQueue, boolean waitForever, void **ppUserData)
+{
+ void *buffer = NULL;
+
+#ifdef SIP_OS_WINDOWS
+ struct msgbuffer *rcvMsg = (struct msgbuffer *)rcvBuffer;
+ cpr_msg_queue_t *pCprMsgQueue;
+ MSG msg;
+ cpr_thread_t *pThreadPtr;
+#endif
+
+ if (!msgQueue) {
+ CPR_ERROR("%s - invalid msgQueue\n", __FUNCTION__);
+ return NULL;
+ }
+
+ /* Initialize ppUserData */
+ if (ppUserData) {
+ *ppUserData = NULL;
+ }
+
+#ifdef SIP_OS_WINDOWS
+ pCprMsgQueue = (cpr_msg_queue_t *)msgQueue;
+ memset(&msg, 0, sizeof(MSG));
+
+ if (waitForever == TRUE) {
+ if (GetMessage(&msg, NULL, 0, 0) == -1) {
+ CPR_ERROR("%s - msgQueue = %x failed: %d\n",
+ __FUNCTION__, msgQueue, GetLastError());
+ return NULL;
+ }
+ } else {
+ if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) == 0) {
+ /* no message present */
+ return NULL;
+ }
+ }
+
+ switch (msg.message) {
+ case WM_CLOSE:
+ if (msgQueue == &gsm_msgq)
+ {
+ CPR_ERROR("%s - WM_CLOSE GSM msg queue\n", __FUNCTION__);
+ gsm_shutdown();
+ }
+ else if (msgQueue == &sip_msgq)
+ {
+ CPR_ERROR("%s - WM_CLOSE SIP msg queue\n", __FUNCTION__);
+ sip_regmgr_destroy_cc_conns();
+ sip_shutdown();
+ }
+ else if (msgQueue == &tmr_msgq)
+ {
+ CPR_ERROR("%s - WM_CLOSE TMR msg queue\n", __FUNCTION__);
+ }
+
+ pThreadPtr=(cpr_thread_t *)pCprMsgQueue->handlePtr;
+ if (pThreadPtr)
+ {
+ CloseHandle(pThreadPtr->u.handlePtr);
+ }
+ /* zap the thread ptr, since the thread is going away now */
+ pCprMsgQueue->handlePtr = NULL;
+ _endthreadex(0);
+ break;
+ case MSG_BUF:
+ rcvMsg = (struct msgbuffer *)msg.wParam;
+ buffer = rcvMsg->msgPtr;
+ if (ppUserData) {
+ *ppUserData = rcvMsg->usrPtr;
+ }
+ cpr_free((void *)msg.wParam);
+ break;
+ case MSG_ECHO_EVENT:
+ {
+ HANDLE event;
+ event = (HANDLE*)msg.wParam;
+ SetEvent( event );
+ }
+ break;
+ case WM_TIMER:
+ DispatchMessage(&msg);
+ return NULL;
+ break;
+ default:
+ break;
+ }
+#else
+ cpr_msg_queue_t *msgq;
+ cpr_msgq_node_t *node;
+ struct timespec timeout;
+ struct timeval tv;
+ struct timezone tz;
+
+ msgq = (cpr_msg_queue_t *) msgQueue;
+
+ /*
+ * If waitForever is set, block on the message queue
+ * until a message is received, else return after
+ * 25msec of waiting
+ */
+ pthread_mutex_lock(&msgq->mutex);
+
+ if (!waitForever)
+ {
+ // We'll wait till 25uSec from now
+ gettimeofday(&tv, &tz);
+ timeout.tv_nsec = (tv.tv_usec * 1000) + 25000;
+ timeout.tv_sec = tv.tv_sec;
+
+ pthread_cond_timedwait(&msgq->cond, &msgq->mutex, &timeout);
+ }
+ else
+ {
+ while(msgq->tail==NULL)
+ {
+ pthread_cond_wait(&msgq->cond, &msgq->mutex);
+ }
+ }
+
+ // If there is a message on the queue, de-queue it
+ if (msgq->tail)
+ {
+ node = msgq->tail;
+ msgq->tail = node->prev;
+ if (msgq->tail) {
+ msgq->tail->next = NULL;
+ }
+ if (msgq->head == node) {
+ msgq->head = NULL;
+ }
+ msgq->currentCount--;
+ /*
+ * Pull out the data
+ */
+ if (ppUserData) {
+ *ppUserData = node->pUserData;
+ }
+ buffer = node->msg;
+
+ }
+
+ pthread_mutex_unlock(&msgq->mutex);
+#endif /* SIP_OS_WINDOWS */
+
+ return buffer;
+}
+
+
+/**
+ * Place a message on a particular queue. Note that caller may
+ * block (see comments below)
+ *
+ * @param msgQueue - msg queue on which to place the message
+ * @param msg - pointer to the msg to place on the queue
+ * @param ppUserData - pointer to a pointer to user defined data
+ *
+ * @return CPR_SUCCESS or CPR_FAILURE, errno provided
+ *
+ * @note 1. Messages queues are set to be non-blocking, those cases
+ * where the system call fails with a would-block error code
+ * (EAGAIN) the function will attempt other mechanisms described
+ * below.
+ * @note 2. If enabled with an extended message queue, either via a
+ * call to cprCreateMessageQueue with depth value or a call to
+ * cprSetExtendMessageQueueDepth() (when unit testing), the message
+ * will be added to the extended message queue and the call will
+ * return successfully. When room becomes available on the
+ * system's message queue, those messages will be added.
+ * @note 3. If the message queue becomes full and no space is availabe
+ * on the extended message queue, then the function will attempt
+ * to resend the message up to CPR_ATTEMPTS_TO_SEND and the
+ * calling thread will *BLOCK* CPR_SND_TIMEOUT_WAIT_INTERVAL
+ * milliseconds after each failed attempt. If unsuccessful
+ * after all attempts then EGAIN error code is returned.
+ * @note 4. This applies to all CPR threads, including the timer thread.
+ * So it is possible that the timer thread would be forced to
+ * sleep which would have the effect of delaying all active
+ * timers. The work to fix this rare situation is not considered
+ * worth the effort to fix....so just leaving as is.
+ */
+cprRC_t
+cprSendMessage (cprMsgQueue_t msgQueue, void *msg, void **ppUserData)
+{
+#ifdef SIP_OS_WINDOWS
+ struct msgbuffer *sendMsg;
+ cpr_thread_t *pCprThread;
+ HANDLE *hThread;
+#endif
+
+ if (!msgQueue) {
+ CPR_ERROR("%s - msgQueue is NULL\n", __FUNCTION__);
+ return CPR_FAILURE;
+ }
+
+#ifdef SIP_OS_WINDOWS
+ pCprThread = (cpr_thread_t *)(((cpr_msg_queue_t *)msgQueue)->handlePtr);
+ if (!pCprThread) {
+ CPR_ERROR("%s - msgQueue(%x) not associated with a thread\n",
+ __FUNCTION__, msgQueue);
+ return CPR_FAILURE;
+ }
+
+ hThread = (HANDLE*)(pCprThread->u.handlePtr);
+ if (!hThread) {
+ CPR_ERROR("%s - msgQueue(%x)'s thread(%x) not assoc. with Windows\n",
+ __FUNCTION__, msgQueue, pCprThread);
+ return CPR_FAILURE;
+ }
+
+ /* Package up the message */
+ sendMsg = (struct msgbuffer *)cpr_calloc(1, sizeof(struct msgbuffer));
+ if (!sendMsg) {
+ CPR_ERROR("%s - No memory\n", __FUNCTION__);
+ return CPR_FAILURE;
+ }
+ sendMsg->mtype = PHONE_IPC_MSG;
+
+ /* Save the address of the message */
+ sendMsg->msgPtr = msg;
+
+ /* Allow the ppUserData to be optional */
+ if (ppUserData) {
+ sendMsg->usrPtr = *ppUserData;
+ }
+
+ /* Post the message */
+ if (hThread == NULL || PostThreadMessage(pCprThread->threadId, MSG_BUF,
+ (WPARAM)sendMsg, 0) == 0 ) {
+ CPR_ERROR("%s - Msg not sent: %d\n", __FUNCTION__, GetLastError());
+ cpr_free(sendMsg);
+ return CPR_FAILURE;
+ }
+ return CPR_SUCCESS;
+
+#else
+ static const char error_str[] = "%s: Msg not sent to %s queue: %s\n";
+ cpr_msgq_post_result_e rc;
+ cpr_msg_queue_t *msgq;
+ int16_t attemptsToSend = CPR_ATTEMPTS_TO_SEND;
+ uint16_t numAttempts = 0;
+
+ msgq = (cpr_msg_queue_t *) msgQueue;
+
+ /*
+ * Attempt to send message
+ */
+ do {
+
+ /*
+ * Post the message to the Queue
+ */
+ rc = cprPostMessage(msgq, msg, ppUserData);
+
+ if (rc == CPR_MSGQ_POST_SUCCESS) {
+ cprPegSendMessageStats(msgq, numAttempts);
+ return CPR_SUCCESS;
+ } else if (rc == CPR_MSGQ_POST_FAILED) {
+ CPR_ERROR("%s: Msg not sent to %s queue: %d\n",
+ __FUNCTION__, msgq->name, errno);
+ msgq->sendErrors++;
+ /*
+ * If posting to calling thread's own queue,
+ * then peg the self queue error.
+ */
+ if (pthread_self() == msgq->thread) {
+ msgq->selfQErrors++;
+ }
+
+ return CPR_FAILURE;
+ }
+
+
+ /*
+ * Did not succeed in sending the message, so continue
+ * to attempt up to the CPR_ATTEMPTS_TO_SEND.
+ */
+ attemptsToSend--;
+ if (attemptsToSend > 0) {
+ /*
+ * Force a context-switch of the thread attempting to
+ * send the message, in order to help the case where
+ * the msg queue is full and the owning thread may get
+ * a a chance be scheduled so it can drain it (Note:
+ * no guarantees, more of a "last-ditch effort" to
+ * recover...especially when temporarily over-whelmed).
+ */
+ cprSleep(CPR_SND_TIMEOUT_WAIT_INTERVAL);
+ msgq->reTries++;
+ numAttempts++;
+ }
+ } while (attemptsToSend > 0);
+
+ CPR_ERROR(error_str, __FUNCTION__, msgq->name, "FULL");
+ msgq->sendErrors++;
+ return CPR_FAILURE;
+#endif /* SIP_OS_WINDOWS */
+}
+
+
+
+/**
+ * cprGetDepth
+ *
+ * @brief get depth of a message queue
+ *
+ * The pSIPCC uses this API to look at the depth of a message queue for internal
+ * routing and throttling decision
+ *
+ * @param[in] msgQueue - message queue
+ *
+ * @return depth of msgQueue
+ *
+ * @pre (msgQueue not_eq NULL)
+ */
+uint16_t cprGetDepth (cprMsgQueue_t msgQueue)
+{
+#ifdef SIP_OS_WINDOWS
+ return 0;
+#else
+ cpr_msg_queue_t *msgq;
+ msgq = (cpr_msg_queue_t *) msgQueue;
+ return msgq->currentCount;
+#endif /* SIP_OS_WINDOWS */
+}
+
+
deleted file mode 100644
--- a/media/webrtc/signaling/src/sipcc/cpr/darwin/cpr_darwin_ipc.c
+++ /dev/null
@@ -1,611 +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/. */
-
-#include "cpr.h"
-#include "cpr_stdlib.h"
-#include <cpr_stdio.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <time.h>
-#include <plat_api.h>
-#include "cpr_string.h"
-
-/*
- * If building with debug test interface,
- * allow access to internal CPR functions
- */
-#define STATIC static
-
-#define OS_MSGTQL 31 /* need to check number for MV linux and put here */
-
-/*
- * Internal CPR API
- */
-extern pthread_t cprGetThreadId(cprThread_t thread);
-
-/*
- * Extended internal message queue node
- *
- * A double-linked list holding the nessasary message information
- */
-typedef struct cpr_msgq_node_s
-{
- struct cpr_msgq_node_s *next;
- struct cpr_msgq_node_s *prev;
- void *msg;
- void *pUserData;
-} cpr_msgq_node_t;
-
-/*
- * Msg queue information needed to hide OS differences in implementation.
- * To use msg queues, the application code may pass in a name to the
- * create function for msg queues. CPR does not use this field, it is
- * solely for the convenience of the application and to aid in debugging.
- *
- * Note: Statistics are not protected by a mutex; therefore, there exists
- * the possibility that the results may not be accurate.
- *
- * Note:if the depth supplied by OS is insufficient,a message queue owner may
- * increase the message queue depth via cprCreateMessageQueue's depth
- * parameter where the value can range from MSGTQL to CPR_MAX_MSG_Q_DEPTH.
- */
-typedef struct cpr_msg_queue_s
-{
- struct cpr_msg_queue_s *next;
- const char *name;
- pthread_t thread;
- int32_t queueId;
- uint16_t currentCount;
- uint32_t totalCount;
- uint32_t sendErrors;
- uint32_t reTries;
- uint32_t highAttempts;
- uint32_t selfQErrors;
- uint16_t extendedQDepth;
- uint16_t maxExtendedQDepth;
- pthread_mutex_t mutex; /* lock for managing extended queue */
- pthread_cond_t cond; /* signal for queue/dequeue */
- cpr_msgq_node_t *head; /* extended queue head (newest element) */
- cpr_msgq_node_t *tail; /* extended queue tail (oldest element) */
-} cpr_msg_queue_t;
-
-/*
- * A enumeration used to report the result of posting a message to
- * a message queue
- */
-typedef enum
-{
- CPR_MSGQ_POST_SUCCESS,
- CPR_MSGQ_POST_FAILED,
- CPR_MSGQ_POST_PENDING
-} cpr_msgq_post_result_e;
-
-
-/*
- * Head of list of message queues
- */
-static cpr_msg_queue_t *msgQueueList = NULL;
-
-/*
- * Mutex to manage message queue list
- */
-pthread_mutex_t msgQueueListMutex;
-
-/*
- * String to represent message queue name when it is not provided
- */
-static const char unnamed_string[] = "unnamed";
-
-
-/*
- * CPR_MAX_MSG_Q_DEPTH
- *
- * The maximum queue depth supported by the CPR layer. This value
- * is arbitrary though the purpose is to limit the memory usage
- * by CPR and avoid (nearly) unbounded situations.
- *
- * Note: This value should be greater than MSGTQL which is currently
- * defined as 31
- */
-#define CPR_MAX_MSG_Q_DEPTH 256
-
-/*
- * CPR_SND_TIMEOUT_WAIT_INTERVAL
- *
- * The interval of time to wait in milliseconds between attempts to
- * send a message to the message queue
- *
- * Note: 20 ms. to avoid less than a tick wake up since on most
- * OSes 10ms is one 1 tick
- * this should really be OS_TICK_MS * 2 or OS_TICK_MS + X
- */
-#define CPR_SND_TIMEOUT_WAIT_INTERVAL 20
-
-/*
- * CPR_ATTEMPTS_TO_SEND
- *
- * The number of attempts made to send a message when the message
- * would otherwise be blocked. Note in this condition the thread
- * will sleep the timeout interval to allow the msg queue to be
- * drained.
- *
- * Note: 25 attempts for upto .5 seconds at the interval of
- * CPR_SND_TIMEOUT_WAIT_INTERVAL worst case.
- */
-#define CPR_ATTEMPTS_TO_SEND 25
-
-/*
- * Also, important to note that the total timeout interval must be
- * greater than the SIP's select call timeout value which is 25msec.
- * This is necessary to cover the case where the SIP message queue
- * is full and the select timeout occurs.
- *
- * Total timeout interval = CPR_SND_TIMEOUT_WAIT_INTERVAL *
- * CPR_ATTEMPTS_TO_SEND;
- */
-
-
-/*
- * Prototype declarations
- */
-static cpr_msgq_post_result_e
-cprPostMessage(cpr_msg_queue_t *msgq, void *msg, void **ppUserData);
-static void
-cprPegSendMessageStats(cpr_msg_queue_t *msgq, uint16_t numAttempts);
-
-
-/*
- * Functions
- */
-
-/**
- * Creates a message queue
- *
- * @param name - name of the message queue
- * @param depth - the message queue depth, optional field which will
- * default if set to zero(0)
- *
- * @return Msg queue handle or NULL if init failed, errno provided
- *
- * @note the actual message queue depth will be bounded by the
- * standard system message queue depth and CPR_MAX_MSG_Q_DEPTH.
- * If 'depth' is outside of the bounds, the value will be
- * reset automatically.
- */
-cprMsgQueue_t
-cprCreateMessageQueue (const char *name, uint16_t depth)
-{
- static const char fname[] = "cprCreateMessageQueue";
- cpr_msg_queue_t *msgq;
- static int key_id = 100; /* arbitrary starting number */
-
- msgq = cpr_calloc(1, sizeof(cpr_msg_queue_t));
- if (msgq == NULL) {
- printf("%s: Malloc failed: %s\n", fname,
- name ? name : unnamed_string);
- errno = ENOMEM;
- return NULL;
- }
-
- msgq->name = name ? name : unnamed_string;
- msgq->queueId = key_id++;
-
- pthread_cond_t _cond = PTHREAD_COND_INITIALIZER;
- msgq->cond = _cond;
- pthread_mutex_t _lock = PTHREAD_MUTEX_INITIALIZER;
- msgq->mutex = _lock;
-
- /*
- * Add message queue to list for statistics reporting
- */
- pthread_mutex_lock(&msgQueueListMutex);
- msgq->next = msgQueueList;
- msgQueueList = msgq;
- pthread_mutex_unlock(&msgQueueListMutex);
-
- return msgq;
-}
-
-
-/**
- * Removes all messages from the queue and then destroy the message queue
- *
- * @param msgQueue - message queue to destroy
- *
- * @return CPR_SUCCESS or CPR_FAILURE, errno provided
- */
-cprRC_t
-cprDestroyMessageQueue (cprMsgQueue_t msgQueue)
-{
- static const char fname[] = "cprDestroyMessageQueue";
- cpr_msg_queue_t *msgq;
- void *msg;
-
- msgq = (cpr_msg_queue_t *) msgQueue;
- if (msgq == NULL) {
- /* Bad application! */
- CPR_ERROR("%s: Invalid input\n", fname);
- errno = EINVAL;
- return CPR_FAILURE;
- }
-
- /* Drain message queue */
- msg = cprGetMessage(msgQueue, FALSE, NULL);
- while (msg != NULL) {
- cpr_free(msg);
- msg = cprGetMessage(msgQueue, FALSE, NULL);
- }
-
- /* Remove message queue from list */
- pthread_mutex_lock(&msgQueueListMutex);
- if (msgq == msgQueueList) {
- msgQueueList = msgq->next;
- } else {
- cpr_msg_queue_t *msgql = msgQueueList;
-
- while ((msgql->next != NULL) && (msgql->next != msgq)) {
- msgql = msgql->next;
- }
- if (msgql->next == msgq) {
- msgql->next = msgq->next;
- }
- }
- pthread_mutex_unlock(&msgQueueListMutex);
-
- /* Remove message queue mutex */
- if (pthread_mutex_destroy(&msgq->mutex) != 0) {
- CPR_ERROR("%s: Failed to destroy msg queue (%s) mutex: %d\n",
- fname, msgq->name, errno);
- }
-
- cpr_free(msgq);
- return CPR_SUCCESS;
-}
-
-
-/**
- * Associate a thread with the message queue
- *
- * @param msgQueue - msg queue to set
- * @param thread - CPR thread to associate with queue
- *
- * @return CPR_SUCCESS or CPR_FAILURE
- *
- * @note Nothing is done to prevent overwriting the thread ID
- * when the value has already been set.
- */
-cprRC_t
-cprSetMessageQueueThread (cprMsgQueue_t msgQueue, cprThread_t thread)
-{
- static const char fname[] = "cprSetMessageQueueThread";
- cpr_msg_queue_t *msgq;
-
- if ((!msgQueue) || (!thread)) {
- CPR_ERROR("%s: Invalid input\n", fname);
- return CPR_FAILURE;
- }
-
- msgq = (cpr_msg_queue_t *) msgQueue;
- if (msgq->thread != 0) {
- CPR_ERROR("%s: over-writing previously msgq thread name for %s",
- fname, msgq->name);
- }
-
- msgq->thread = cprGetThreadId(thread);
- return CPR_SUCCESS;
-}
-
-
-/**
- * Retrieve a message from a particular message queue
- *
- * @param[in] msgQueue - msg queue from which to retrieve the message
- * @param[in] waitForever - boolean to either wait forever (TRUE) or not
- * wait at all (FALSE) if the msg queue is empty.
- * @param[out] ppUserData - pointer to a pointer to user defined data
- *
- * @return Retrieved message buffer or NULL if failure occurred or
- * the waitForever flag was set to false and no messages were
- * on the queue.
- *
- * @note If ppUserData is defined, the value will be initialized to NULL
- */
-void *
-cprGetMessage (cprMsgQueue_t msgQueue, boolean waitForever, void **ppUserData)
-{
- static const char fname[] = "cprGetMessage";
-
- void *buffer = 0;
- cpr_msg_queue_t *msgq;
- cpr_msgq_node_t *node;
- struct timespec timeout;
- struct timeval tv;
-#ifndef __APPLE__
- struct timezone tz;
-#else
- // On the iPhone, there is a DarwinAlias problem with "timezone"
- struct _timezone {
- int tz_minuteswest; /* of Greenwich */
- int tz_dsttime; /* type of dst correction to apply */
- } tz;
-#endif
-
- /* Initialize ppUserData */
- if (ppUserData) {
- *ppUserData = NULL;
- }
-
- msgq = (cpr_msg_queue_t *) msgQueue;
- if (msgq == NULL) {
- /* Bad application! */
- CPR_ERROR("%s: Invalid input\n", fname);
- errno = EINVAL;
- return NULL;
- }
-
- /*
- * If waitForever is set, block on the message queue
- * until a message is received, else return after
- * 25msec of waiting
- */
- pthread_mutex_lock(&msgq->mutex);
-
- if (!waitForever)
- {
- // We'll wait till 25uSec from now
- gettimeofday(&tv, &tz);
- timeout.tv_nsec = (tv.tv_usec * 1000) + 25000;
- timeout.tv_sec = tv.tv_sec;
-
- pthread_cond_timedwait(&msgq->cond, &msgq->mutex, &timeout);
-
- }
- else
- {
- while(msgq->tail==NULL)
- {
- pthread_cond_wait(&msgq->cond, &msgq->mutex);
- }
- }
-
- // If there is a message on the queue, de-queue it
- if (msgq->tail)
- {
- node = msgq->tail;
- msgq->tail = node->prev;
- if (msgq->tail) {
- msgq->tail->next = NULL;
- }
- if (msgq->head == node) {
- msgq->head = NULL;
- }
- msgq->currentCount--;
- /*
- * Pull out the data
- */
- if (ppUserData) {
- *ppUserData = node->pUserData;
- }
- buffer = node->msg;
-
- }
-
- pthread_mutex_unlock(&msgq->mutex);
-
- return buffer;
-}
-
-
-/**
- * Place a message on a particular queue. Note that caller may
- * block (see comments below)
- *
- * @param msgQueue - msg queue on which to place the message
- * @param msg - pointer to the msg to place on the queue
- * @param ppUserData - pointer to a pointer to user defined data
- *
- * @return CPR_SUCCESS or CPR_FAILURE, errno provided
- *
- * @note 1. Messages queues are set to be non-blocking, those cases
- * where the system call fails with a would-block error code
- * (EAGAIN) the function will attempt other mechanisms described
- * below.
- * @note 2. If enabled with an extended message queue, either via a
- * call to cprCreateMessageQueue with depth value or a call to
- * cprSetExtendMessageQueueDepth() (when unit testing), the message
- * will be added to the extended message queue and the call will
- * return successfully. When room becomes available on the
- * system's message queue, those messages will be added.
- * @note 3. If the message queue becomes full and no space is availabe
- * on the extended message queue, then the function will attempt
- * to resend the message up to CPR_ATTEMPTS_TO_SEND and the
- * calling thread will *BLOCK* CPR_SND_TIMEOUT_WAIT_INTERVAL
- * milliseconds after each failed attempt. If unsuccessful
- * after all attempts then EGAIN error code is returned.
- * @note 4. This applies to all CPR threads, including the timer thread.
- * So it is possible that the timer thread would be forced to
- * sleep which would have the effect of delaying all active
- * timers. The work to fix this rare situation is not considered
- * worth the effort to fix....so just leaving as is.
- */
-cprRC_t
-cprSendMessage (cprMsgQueue_t msgQueue, void *msg, void **ppUserData)
-{
- static const char fname[] = "cprSendMessage";
- static const char error_str[] = "%s: Msg not sent to %s queue: %s\n";
- cpr_msgq_post_result_e rc;
- cpr_msg_queue_t *msgq;
- int16_t attemptsToSend = CPR_ATTEMPTS_TO_SEND;
- uint16_t numAttempts = 0;
-
- /* Bad application? */
- if (msgQueue == NULL) {
- CPR_ERROR(error_str, fname, "undefined", "invalid input");
- errno = EINVAL;
- return CPR_FAILURE;
- }
-
- msgq = (cpr_msg_queue_t *) msgQueue;
-
- /*
- * Attempt to send message
- */
- do {
-
- /*
- * Post the message to the Queue
- */
- rc = cprPostMessage(msgq, msg, ppUserData);
-
- if (rc == CPR_MSGQ_POST_SUCCESS) {
- cprPegSendMessageStats(msgq, numAttempts);
- return CPR_SUCCESS;
- } else if (rc == CPR_MSGQ_POST_FAILED) {
- CPR_ERROR("%s: Msg not sent to %s queue: %d\n",
- fname, msgq->name, errno);
- msgq->sendErrors++;
- /*
- * If posting to calling thread's own queue,
- * then peg the self queue error.
- */
- if (pthread_self() == msgq->thread) {
- msgq->selfQErrors++;
- }
-
- return CPR_FAILURE;
- }
-
-
- /*
- * Did not succeed in sending the message, so continue
- * to attempt up to the CPR_ATTEMPTS_TO_SEND.
- */
- attemptsToSend--;
- if (attemptsToSend > 0) {
- /*
- * Force a context-switch of the thread attempting to
- * send the message, in order to help the case where
- * the msg queue is full and the owning thread may get
- * a a chance be scheduled so it can drain it (Note:
- * no guarantees, more of a "last-ditch effort" to
- * recover...especially when temporarily over-whelmed).
- */
- cprSleep(CPR_SND_TIMEOUT_WAIT_INTERVAL);
- msgq->reTries++;
- numAttempts++;
- }
- } while (attemptsToSend > 0);
-
- CPR_ERROR(error_str, fname, msgq->name, "FULL");
- msgq->sendErrors++;
- return CPR_FAILURE;
-}
-
-/**
- * Peg the statistics for successfully posting a message
- *
- * @param msgq - message queue
- * @param numAttempts - number of attempts to post message to message queue
- *
- * @return none
- *
- * @pre (msgq not_eq NULL)
- */
-static void
-cprPegSendMessageStats (cpr_msg_queue_t *msgq, uint16_t numAttempts)
-{
- /*
- * Collect statistics
- */
- msgq->totalCount++;
-
- if (numAttempts > msgq->highAttempts) {
- msgq->highAttempts = numAttempts;
- }
-}
-
-/**
- * Post message to system message queue
- *
- * @param msgq - message queue
- * @param msg - message to post
- * @param ppUserData - ptr to ptr to option user data
- *
- * @return the post result which is CPR_MSGQ_POST_SUCCESS,
- * CPR_MSGQ_POST_FAILURE or CPR_MSGQ_POST_PENDING
- *
- * @pre (msgq not_eq NULL)
- * @pre (msg not_eq NULL)
- */
-static cpr_msgq_post_result_e
-cprPostMessage (cpr_msg_queue_t *msgq, void *msg, void **ppUserData)
-{
- cpr_msgq_node_t *node;
-
- /*
- * Allocate new message queue node
- */
- node = cpr_malloc(sizeof(*node));
- if (!node) {
- errno = ENOMEM;
- return CPR_MSGQ_POST_FAILED;
- }
-
- pthread_mutex_lock(&msgq->mutex);
-
- /*
- * Fill in data
- */
- node->msg = msg;
- if (ppUserData != NULL) {
- node->pUserData = *ppUserData;
- } else {
- node->pUserData = NULL;
- }
-
- /*
- * Push onto list
- */
- node->prev = NULL;
- node->next = msgq->head;
- msgq->head = node;
-
- if (node->next) {
- node->next->prev = node;
- }
-
- if (msgq->tail == NULL) {
- msgq->tail = node;
- }
- msgq->currentCount++;
-
- pthread_cond_signal(&msgq->cond);
- pthread_mutex_unlock(&msgq->mutex);
-
- return CPR_MSGQ_POST_SUCCESS;
-
-}
-
-
-/**
- * cprGetDepth
- *
- * @brief get depth of a message queue
- *
- * The pSIPCC uses this API to look at the depth of a message queue for internal
- * routing and throttling decision
- *
- * @param[in] msgQueue - message queue
- *
- * @return depth of msgQueue
- *
- * @pre (msgQueue not_eq NULL)
- */
-uint16_t cprGetDepth (cprMsgQueue_t msgQueue)
-{
- cpr_msg_queue_t *msgq;
- msgq = (cpr_msg_queue_t *) msgQueue;
- return msgq->currentCount;
-}
-
deleted file mode 100644
--- a/media/webrtc/signaling/src/sipcc/cpr/darwin/cpr_darwin_ipc.h
+++ /dev/null
@@ -1,47 +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/. */
-
-#ifndef _CPR_DARWIN_IPC_H_
-#define _CPR_DARWIN_IPC_H_
-
-#include "cpr_threads.h"
-#include <pthread.h>
-
-/* Enable support for cprSetMessageQueueThread API */
-#define CPR_USE_SET_MESSAGE_QUEUE_THREAD
-
-/* Maximum message size allowed by CNU */
-#define CPR_MAX_MSG_SIZE 8192
-
-/* Our CNU msgtype */
-#define PHONE_IPC_MSG 1
-
-
-/* For gathering statistics regarding message queues */
-typedef struct {
- char name[16];
- uint16_t currentCount;
- uint32_t totalCount;
- uint32_t rcvTimeouts;
- uint32_t sendErrors;
- uint32_t reTries;
- uint32_t highAttempts;
- uint32_t selfQErrors;
- uint16_t extendedDepth;
-} cprMsgQueueStats_t;
-
-/*
- * Mutex for updating the message queue list
- */
-extern pthread_mutex_t msgQueueListMutex;
-
-/**
- * cprGetDepth
- *
- * Get depth of a message queue
- */
-uint16_t cprGetDepth(cprMsgQueue_t msgQueue);
-
-
-#endif
--- a/media/webrtc/signaling/src/sipcc/cpr/include/cpr_ipc.h
+++ b/media/webrtc/signaling/src/sipcc/cpr/include/cpr_ipc.h
@@ -1,38 +1,62 @@
/* 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 _CPR_IPC_H_
#define _CPR_IPC_H_
#include "cpr_types.h"
+#include "cpr_threads.h"
+
+#ifndef SIP_OS_WINDOWS
+#include <pthread.h>
+#endif /* !SIP_OS_WINDOWS */
__BEGIN_DECLS
/**
* Define handle for message queues
*/
typedef void* cprMsgQueue_t;
/*
* A timeout value of -1 means wait forever when
* attempting to get a message. Just #define something
* so the application code is easier to read.
*/
#define WAIT_FOREVER -1
-#if defined SIP_OS_LINUX
-#include "../linux/cpr_linux_ipc.h"
-#elif defined SIP_OS_WINDOWS
-#include "../win32/cpr_win_ipc.h"
-#elif defined SIP_OS_OSX
-#include "../darwin/cpr_darwin_ipc.h"
-#endif
+/* Enable support for cprSetMessageQueueThread API */
+#define CPR_USE_SET_MESSAGE_QUEUE_THREAD
+
+/* Maximum message size allowed by CNU */
+#define CPR_MAX_MSG_SIZE 8192
+
+/* Our CNU msgtype */
+#ifdef SIP_OS_WINDOWS
+#define PHONE_IPC_MSG 0xF005
+
+/* Msg buffer layout */
+struct msgbuffer {
+ int32_t mtype; /* Message type */
+ void *msgPtr; /* Ptr to msg */
+ void *usrPtr; /* Ptr to user data */
+};
+
+#else
+#define PHONE_IPC_MSG 1
+
+/*
+ * Mutex for updating the message queue list
+ */
+extern pthread_mutex_t msgQueueListMutex;
+
+#endif /* SIP_OS_WINDOWS */
/* Function prototypes */
/**
* Creates a message queue
*
* @brief The cprCreateMessageQueue function is called to allow the OS to
* perform whatever work is needed to create a message queue.
@@ -55,33 +79,16 @@ typedef void* cprMsgQueue_t;
* standard system message queue depth and CPR_MAX_MSG_Q_DEPTH.
* If 'depth' is outside of the bounds, the value will be
* reset automatically.
*/
cprMsgQueue_t
cprCreateMessageQueue(const char *name, uint16_t depth);
-/**
- * cprDestroyMessageQueue
- * @brief Removes all messages from the queue and then destroy the message queue
- *
- * The cprDestroyMessageQueue function is called to destroy a message queue. The
- * function drains any messages from the queue and the frees the
- * message queue. Any messages on the queue are to be deleted, and not sent to the intended
- * recipient. It is the application's responsibility to ensure that no threads are
- * blocked on a message queue when it is destroyed.
- *
- * @param[in] msgQueue - message queue to destroy
- *
- * @return CPR_SUCCESS or CPR_FAILURE, errno should be provided in this case
- */
-cprRC_t
-cprDestroyMessageQueue(cprMsgQueue_t msgQueue);
-
#ifdef CPR_USE_SET_MESSAGE_QUEUE_THREAD
/**
* cprSetMessageQueueThread
* @brief Associate a thread with the message queue
*
* This method is used by pSIPCC to associate a thread and a message queue.
* @param[in] msgQueue - msg queue to set
* @param[in] thread - CPR thread to associate with queue
@@ -154,12 +161,19 @@ cprGetMessage(cprMsgQueue_t msgQueue,
* timers. The work to fix this rare situation is not considered
* worth the effort to fix....so just leaving as is.
*/
cprRC_t
cprSendMessage(cprMsgQueue_t msgQueue,
void* msg,
void** usrPtr);
+/**
+ * cprGetDepth
+ *
+ * Get depth of a message queue
+ */
+uint16_t cprGetDepth(cprMsgQueue_t msgQueue);
+
__END_DECLS
#endif
deleted file mode 100644
--- a/media/webrtc/signaling/src/sipcc/cpr/linux/cpr_linux_ipc.c
+++ /dev/null
@@ -1,965 +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/. */
-
-/**
- * @brief CPR layer for interprocess communication
- *
- * The name of this file may be overly broad, rather this file deals
- * with IPC via message queues. A user may create, destroy and
- * associate a thread with a message queue. Once established, messages
- * can be delivered and retrieved.
- *
- * The send/get APIs attempt to reliably deliver messages even when
- * under stress. Two mechanisms have been added to deal with a full
- * message queue. First, the message queue size may be extended to
- * allow more messages to be handled than supported by an OS.
- * Second, if the queue is indeed full a sleep-and-retry
- * method is used to force a context-switch to allow for other threads
- * to run in hope of clearing some messages off of the queue. The
- * latter method is always-on by default. The former method must be
- * enabled by extending the message queue by some size greater than
- * zero (0).
- *
- * @defgroup IPC The Inter Process Communication module
- * @ingroup CPR
- * @brief The module related to IPC abstraction for the pSIPCC
- * @addtogroup MsgQIPCAPIs The Message Queue IPC APIs
- * @ingroup IPC
- * @brief APIs expected by pSIPCC for using message queues
- *
- * @{
- *
- *
- */
-#include "cpr.h"
-#include "cpr_stdlib.h"
-#include <cpr_stdio.h>
-#include <errno.h>
-#if defined(WEBRTC_GONK)
-#include <sys/syscall.h>
-#include <unistd.h>
-#include <linux/msg.h>
-#include <linux/ipc.h>
-#else
-#include <sys/msg.h>
-#include <sys/ipc.h>
-#endif
-#include "plat_api.h"
-#include "CSFLog.h"
-
-static const char *logTag = "cpr_linux_ipc";
-
-#define STATIC static
-
-#if defined(WEBRTC_GONK)
-
-#if defined(__i386__)
-# include <asm-generic/ipc.h>
-#endif /* __i386__ */
-
-int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
-{
-#if defined(__i386__)
- return syscall(__NR_ipc, MSGSND, msqid, msgsz, msgflg, msgp);
-#else
- return syscall(__NR_msgsnd, msqid, msgp, msgsz, msgflg);
-#endif
-}
-
-ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)
-{
-#if defined(__i386__)
- struct ipc_kludge tmp = {
- .msgp = msgp,
- .msgtyp = msgtyp
- };
-
- return syscall(__NR_ipc, MSGRCV, msqid, msgsz, msgflg, &tmp);
-#else
- return syscall(__NR_msgrcv, msqid, msgp, msgsz, msgtyp, msgflg);
-#endif
-}
-
-int msgctl(int msqid, int cmd, struct msqid_ds *buf)
-{
-#if defined(__i386__)
- /* Android defines |struct ipc_perm| as old ABI. */
- return syscall(__NR_ipc, MSGCTL, msqid, cmd | IPC_64, 0, buf);
-#else
- return syscall(__NR_msgctl, msqid, cmd, buf);
-#endif
-}
-
-int msgget(key_t key, int msgflg)
-{
-#if defined(__i386__)
- return syscall(__NR_ipc, MSGGET, key, msgflg, 0, NULL);
-#else
- return syscall(__NR_msgget, key, msgflg);
-#endif
-}
-#endif
-
-/* @def The Message Queue depth */
-#define OS_MSGTQL 31
-
-/*
- * Internal CPR API
- */
-extern pthread_t cprGetThreadId(cprThread_t thread);
-
-/**
- * @struct cpr_msgq_node_s
- * Extended internal message queue node
- *
- * A double-linked list holding the necessary message information
- */
-typedef struct cpr_msgq_node_s
-{
- struct cpr_msgq_node_s *next;
- struct cpr_msgq_node_s *prev;
- void *msg;
- void *pUserData;
-} cpr_msgq_node_t;
-
-/**
- * @struct cpr_msg_queue_s
- * Msg queue information needed to hide OS differences in implementation.
- * To use msg queues, the application code may pass in a name to the
- * create function for msg queues. CPR does not use this field, it is
- * solely for the convenience of the application and to aid in debugging.
- *
- * Note: Statistics are not protected by a mutex; therefore, there exists
- * the possibility that the results may not be accurate.
- *
- * Note:if the depth supplied by OS is insufficient,a message queue owner may
- * increase the message queue depth via cprCreateMessageQueue's depth
- * parameter where the value can range from MSGTQL to CPR_MAX_MSG_Q_DEPTH.
- */
-typedef struct cpr_msg_queue_s
-{
- struct cpr_msg_queue_s *next;
- const char *name;
- pthread_t thread;
- int32_t queueId;
- uint16_t currentCount;
- uint32_t totalCount;
- uint32_t sendErrors;
- uint32_t reTries;
- uint32_t highAttempts;
- uint32_t selfQErrors;
- uint16_t extendedQDepth;
- uint16_t maxExtendedQDepth;
- pthread_mutex_t mutex; /* lock for managing extended queue */
- cpr_msgq_node_t *head; /* extended queue head (newest element) */
- cpr_msgq_node_t *tail; /* extended queue tail (oldest element) */
-} cpr_msg_queue_t;
-
-/**
- * @enum cpr_msgq_post_result_e
- * A enumeration used to report the result of posting a message to
- * a message queue
- */
-typedef enum
-{
- CPR_MSGQ_POST_SUCCESS,
- CPR_MSGQ_POST_FAILED,
- CPR_MSGQ_POST_PENDING
-} cpr_msgq_post_result_e;
-
-
-/*
- * Head of list of message queues
- */
-static cpr_msg_queue_t *msgQueueList = NULL;
-
-/*
- * Mutex to manage message queue list
- */
-pthread_mutex_t msgQueueListMutex;
-
-/*
- * String to represent message queue name when it is not provided
- */
-static const char unnamed_string[] = "unnamed";
-
-
-/*
- * CPR_MAX_MSG_Q_DEPTH
- *
- * The maximum queue depth supported by the CPR layer. This value
- * is arbitrary though the purpose is to limit the memory usage
- * by CPR and avoid (nearly) unbounded situations.
- *
- * Note: This value should be greater than MSGTQL which is currently
- * defined as 31
- */
-#define CPR_MAX_MSG_Q_DEPTH 256
-
-/*
- * CPR_SND_TIMEOUT_WAIT_INTERVAL
- *
- * The interval of time to wait in milliseconds between attempts to
- * send a message to the message queue
- *
- * Note: 20 ms. to avoid less than a tick wake up since on most
- * OSes 10ms is one 1 tick
- * this should really be OS_TICK_MS * 2 or OS_TICK_MS + X
- */
-#define CPR_SND_TIMEOUT_WAIT_INTERVAL 20
-
-/*
- * CPR_ATTEMPTS_TO_SEND
- *
- * The number of attempts made to send a message when the message
- * would otherwise be blocked. Note in this condition the thread
- * will sleep the timeout interval to allow the msg queue to be
- * drained.
- *
- * Note: 25 attempts for upto .5 seconds at the interval of
- * CPR_SND_TIMEOUT_WAIT_INTERVAL worst case.
- */
-#define CPR_ATTEMPTS_TO_SEND 25
-
-/*
- * Also, important to note that the total timeout interval must be
- * greater than the SIP's select call timeout value which is 25msec.
- * This is necessary to cover the case where the SIP message queue
- * is full and the select timeout occurs.
- *
- * Total timeout interval = CPR_SND_TIMEOUT_WAIT_INTERVAL *
- * CPR_ATTEMPTS_TO_SEND;
- */
-
-
-/*
- * Prototype declarations
- */
-static cpr_msgq_post_result_e
-cprPostMessage(cpr_msg_queue_t *msgq, void *msg, void **ppUserData);
-static void
-cprPegSendMessageStats(cpr_msg_queue_t *msgq, uint16_t numAttempts);
-static cpr_msgq_post_result_e
-cprPostExtendedQMsg(cpr_msg_queue_t *msgq, void *msg, void **ppUserData);
-static void
-cprMoveMsgToQueue(cpr_msg_queue_t *msgq);
-
-/*
- * Functions
- */
-
-/**
- * Creates a message queue
- *
- * @brief The cprCreateMessageQueue function is called to allow the OS to
- * perform whatever work is needed to create a message queue.
-
- * If the name is present, CPR should assign this name to the message queue to assist in
- * debugging. The message queue depth is the second input parameter and is for
- * setting the desired queue depth. This parameter may not be supported by all OS.
- * Its primary intention is to set queue depth beyond the default queue depth
- * limitation.
- * On any OS where there is no limit on the message queue depth or
- * its queue depth is sufficiently large then this parameter is ignored on that
- * OS.
- *
- * @param[in] name - name of the message queue (optional)
- * @param[in] depth - the message queue depth, optional field which should
- * default if set to zero(0)
- *
- * @return Msg queue handle or NULL if init failed, errno should be provided
- *
- * @note the actual message queue depth will be bounded by the
- * standard system message queue depth and CPR_MAX_MSG_Q_DEPTH.
- * If 'depth' is outside of the bounds, the value will be
- * reset automatically.
- */
-cprMsgQueue_t
-cprCreateMessageQueue (const char *name, uint16_t depth)
-{
- cpr_msg_queue_t *msgq;
- struct msqid_ds buf;
-
- msgq =(cpr_msg_queue_t *)cpr_calloc(1, sizeof(cpr_msg_queue_t));
- if (msgq == NULL) {
- CPR_ERROR("%s: Malloc failed: %s\n", __FUNCTION__,
- name ? name : unnamed_string);
- errno = ENOMEM;
- return NULL;
- }
-
- msgq->name = name ? name : unnamed_string;
-
- /*
- * Set creation flag so that OS will create the message queue
- */
- msgq->queueId = msgget(IPC_PRIVATE, (IPC_EXCL | IPC_CREAT | 0666));
-
- if (msgq->queueId == -1) {
- CPR_ERROR("%s: Creation failed: %s: %d\n", __FUNCTION__, name, errno);
- if (errno == EEXIST) {
-
- }
-
- cpr_free(msgq);
- return NULL;
- }
- CSFLogDebug(logTag, "create message q with id=%x\n", msgq->queueId);
-
- /* flush the q before ?? */
-
- /*
- * Create mutex for extended (overflow) queue
- */
- if (pthread_mutex_init(&msgq->mutex, NULL) != 0) {
- CPR_ERROR("%s: Failed to create msg queue (%s) mutex: %d\n",
- __FUNCTION__, name, errno);
- (void) msgctl(msgq->queueId, IPC_RMID, &buf);
- cpr_free(msgq);
- return NULL;
- }
-
- /*
- * Set the extended message queue depth (within bounds)
- */
- if (depth > CPR_MAX_MSG_Q_DEPTH) {
- CPR_INFO("%s: Depth too large (%d) reset to %d\n", __FUNCTION__, depth,
- CPR_MAX_MSG_Q_DEPTH);
- depth = CPR_MAX_MSG_Q_DEPTH;
- }
-
- if (depth < OS_MSGTQL) {
- if (depth) {
- CPR_INFO("%s: Depth too small (%d) reset to %d\n", __FUNCTION__, depth, OS_MSGTQL);
- }
- depth = OS_MSGTQL;
- }
- msgq->maxExtendedQDepth = depth - OS_MSGTQL;
-
- /*
- * Add message queue to list for statistics reporting
- */
- pthread_mutex_lock(&msgQueueListMutex);
- msgq->next = msgQueueList;
- msgQueueList = msgq;
- pthread_mutex_unlock(&msgQueueListMutex);
-
- return msgq;
-}
-
-
-/**
- * cprDestroyMessageQueue
- * @brief Removes all messages from the queue and then destroy the message queue
- *
- * The cprDestroyMessageQueue function is called to destroy a message queue. The
- * function drains any messages from the queue and the frees the
- * message queue. Any messages on the queue are to be deleted, and not sent to the intended
- * recipient. It is the application's responsibility to ensure that no threads are
- * blocked on a message queue when it is destroyed.
- *
- * @param[in] msgQueue - message queue to destroy
- *
- * @return CPR_SUCCESS or CPR_FAILURE, errno should be provided in this case
- */
-cprRC_t
-cprDestroyMessageQueue (cprMsgQueue_t msgQueue)
-{
- static const char fname[] = "cprDestroyMessageQueue";
- cpr_msg_queue_t *msgq;
- void *msg;
- struct msqid_ds buf;
- CSFLogDebug(logTag, "Destroy message Q called..\n");
-
-
- msgq = (cpr_msg_queue_t *) msgQueue;
- if (msgq == NULL) {
- /* Bad application! */
- CPR_ERROR("%s: Invalid input\n", fname);
- errno = EINVAL;
- return CPR_FAILURE;
- }
-
- /* Drain message queue */
- msg = cprGetMessage(msgQueue, FALSE, NULL);
- while (msg != NULL) {
- cpr_free(msg);
- msg = cprGetMessage(msgQueue, FALSE, NULL);
- }
-
- /* Remove message queue from list */
- pthread_mutex_lock(&msgQueueListMutex);
- if (msgq == msgQueueList) {
- msgQueueList = msgq->next;
- } else {
- cpr_msg_queue_t *msgql = msgQueueList;
-
- while ((msgql->next != NULL) && (msgql->next != msgq)) {
- msgql = msgql->next;
- }
- if (msgql->next == msgq) {
- msgql->next = msgq->next;
- }
- }
- pthread_mutex_unlock(&msgQueueListMutex);
-
- /* Remove message queue */
- if (msgctl(msgq->queueId, IPC_RMID, &buf) == -1) {
- CPR_ERROR("%s: Destruction failed: %s: %d\n", fname,
- msgq->name, errno);
- return CPR_FAILURE;
- }
-
- /* Remove message queue mutex */
- if (pthread_mutex_destroy(&msgq->mutex) != 0) {
- CPR_ERROR("%s: Failed to destroy msg queue (%s) mutex: %d\n",
- fname, msgq->name, errno);
- }
-
- cpr_free(msgq);
- return CPR_SUCCESS;
-}
-
-
-/**
- * cprSetMessageQueueThread
- * @brief Associate a thread with the message queue
- *
- * This method is used by pSIPCC to associate a thread and a message queue.
- * @param[in] msgQueue - msg queue to set
- * @param[in] thread - CPR thread to associate with queue
- *
- * @return CPR_SUCCESS or CPR_FAILURE
- *
- * @note Nothing is done to prevent overwriting the thread ID
- * when the value has already been set.
- */
-cprRC_t
-cprSetMessageQueueThread (cprMsgQueue_t msgQueue, cprThread_t thread)
-{
- static const char fname[] = "cprSetMessageQueueThread";
- cpr_msg_queue_t *msgq;
-
- if ((!msgQueue) || (!thread)) {
- CPR_ERROR("%s: Invalid input\n", fname);
- return CPR_FAILURE;
- }
-
- msgq = (cpr_msg_queue_t *) msgQueue;
- if (msgq->thread != 0) {
- CPR_ERROR("%s: over-writing previously msgq thread name for %s",
- fname, msgq->name);
- }
-
- msgq->thread = cprGetThreadId(thread);
- return CPR_SUCCESS;
-}
-
-/**
- * cprGetMessage
- * @brief Retrieve a message from a particular message queue
- *
- * The cprGetMessage function retrieves the first message from the message queue
- * specified and returns a void pointer to that message.
- *
- * @param[in] msgQueue - msg queue from which to retrieve the message. This
- * is the handle returned from cprCreateMessageQueue.
- * @param[in] waitForever - boolean to either wait forever (TRUE) or not
- * wait at all (FALSE) if the msg queue is empty.
- * @param[out] ppUserData - pointer to a pointer to user defined data. This
- * will be NULL if no user data was present.
- *
- * @return Retrieved message buffer or NULL if failure occurred or
- * the waitForever flag was set to false and no messages were
- * on the queue.
- *
- * @note If ppUserData is defined, the value will be initialized to NULL
- */
-void *
-cprGetMessage (cprMsgQueue_t msgQueue, boolean waitForever, void **ppUserData)
-{
- static const char fname[] = "cprGetMessage";
- struct msgbuffer rcvBuffer = { 0 };
- struct msgbuffer *rcvMsg = &rcvBuffer;
- void *buffer;
- int msgrcvflags;
- cpr_msg_queue_t *msgq;
-
- /* Initialize ppUserData */
- if (ppUserData) {
- *ppUserData = NULL;
- }
-
- msgq = (cpr_msg_queue_t *) msgQueue;
- if (msgq == NULL) {
- /* Bad application! */
- CPR_ERROR("%s: Invalid input\n", fname);
- errno = EINVAL;
- return NULL;
- }
-
- /*
- * If waitForever is set, block on the message queue
- * until a message is received.
- */
- if (waitForever) {
- msgrcvflags = 0;
- } else {
- msgrcvflags = IPC_NOWAIT;
- }
-
- if (msgrcv(msgq->queueId, rcvMsg,
- sizeof(struct msgbuffer) - offsetof(struct msgbuffer, msgPtr),
- 0, msgrcvflags) == -1) {
- if (!waitForever && errno == ENOMSG) {
- CPR_INFO("%s: no message on queue %s (non-blocking receive "
- " operation), returning\n", fname, msgq->name);
- } else {
- CPR_ERROR("%s: msgrcv for queue %s failed: %d\n",
- fname, msgq->name, errno);
- }
- return NULL;
- }
- CPR_INFO("%s: msgrcv success for queue %s \n",fname, msgq->name);
-
- (void) pthread_mutex_lock(&msgq->mutex);
- /* Update statistics */
- msgq->currentCount--;
- (void) pthread_mutex_unlock(&msgq->mutex);
-
- /*
- * Pull out the data
- */
- if (ppUserData) {
- *ppUserData = rcvMsg->usrPtr;
- }
- buffer = rcvMsg->msgPtr;
-
- /*
- * If there are messages on the extended queue, attempt to
- * push a message back onto the real system queue
- */
- if (msgq->extendedQDepth) {
- cprMoveMsgToQueue(msgq);
- }
-
- return buffer;
-}
-
-
-/**
- * cprSendMessage
- * @brief Place a message on a particular queue. Note that caller may
- * block (see comments below)
- *
- * @param[in] msgQueue - msg queue on which to place the message
- * @param[in] msg - pointer to the msg to place on the queue
- * @param[in] ppUserData - pointer to a pointer to user defined data
- *
- * @return CPR_SUCCESS or CPR_FAILURE, errno should be provided
- *
- * @note 1. Messages queues are set to be non-blocking, those cases
- * where the system call fails with a would-block error code
- * (EAGAIN) the function will attempt other mechanisms described
- * below.
- * @note 2. If enabled with an extended message queue, either via a
- * call to cprCreateMessageQueue with depth value or a call to
- * cprSetExtendMessageQueueDepth() (when unit testing), the message
- * will be added to the extended message queue and the call will
- * return successfully. When room becomes available on the
- * system's message queue, those messages will be added.
- * @note 3. If the message queue becomes full and no space is availabe
- * on the extended message queue, then the function will attempt
- * to resend the message up to CPR_ATTEMPTS_TO_SEND and the
- * calling thread will *BLOCK* CPR_SND_TIMEOUT_WAIT_INTERVAL
- * milliseconds after each failed attempt. If unsuccessful
- * after all attempts then EGAIN error code is returned.
- * @note 4. This applies to all CPR threads, including the timer thread.
- * So it is possible that the timer thread would be forced to
- * sleep which would have the effect of delaying all active
- * timers. The work to fix this rare situation is not considered
- * worth the effort to fix....so just leaving as is.
- */
-cprRC_t
-cprSendMessage (cprMsgQueue_t msgQueue, void *msg, void **ppUserData)
-{
- static const char fname[] = "cprSendMessage";
- static const char error_str[] = "%s: Msg not sent to %s queue: %s\n";
- cpr_msgq_post_result_e rc;
- cpr_msg_queue_t *msgq;
- int16_t attemptsToSend = CPR_ATTEMPTS_TO_SEND;
- uint16_t numAttempts = 0;
-
- /* Bad application? */
- if (msgQueue == NULL) {
- CPR_ERROR(error_str, fname, "undefined", "invalid input");
- errno = EINVAL;
- return CPR_FAILURE;
- }
-
- msgq = (cpr_msg_queue_t *) msgQueue;
-
- /*
- * Attempt to send message
- */
- do {
- (void) pthread_mutex_lock(&msgq->mutex);
-
- /*
- * If in a queue overflow condition, post message to the
- * extended queue; otherwise, post to normal message queue
- */
- if (msgq->extendedQDepth) {
- /*
- * Check if extended queue is full, if not then
- * attempt to add the message.
- */
- if (msgq->extendedQDepth < msgq->maxExtendedQDepth) {
- rc = cprPostExtendedQMsg(msgq, msg, ppUserData);
- // do under lock to avoid races
- if (rc == CPR_MSGQ_POST_SUCCESS) {
- cprPegSendMessageStats(msgq, numAttempts);
- } else {